diff --git a/Cargo.lock b/Cargo.lock index 53854582..2d62aee0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -472,6 +472,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "downcast-rs" version = "1.2.1" @@ -756,6 +765,15 @@ dependencies = [ "url", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.7.2" @@ -787,6 +805,22 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" version = "0.2.18" @@ -796,6 +830,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -808,6 +851,12 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking" version = "2.2.0" @@ -887,6 +936,12 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "proc-macro2" version = "1.0.81" @@ -1090,9 +1145,19 @@ dependencies = [ "serde", "serde_json", "snapshot", + "wgsl-lsp-log", "wgsl-parser", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "similar" version = "2.5.0" @@ -1212,6 +1277,39 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -1271,6 +1369,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "time", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -1338,6 +1477,12 @@ dependencies = [ "serde", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.4" @@ -1446,6 +1591,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "wgsl-lsp-log" +version = "0.1.0" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_utils", + "time", + "tracing-error", + "tracing-log", + "tracing-subscriber", +] + [[package]] name = "wgsl-parser" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index 4d794ea3..ee844d80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] resolver = "2" members = [ + "packages/log", "packages/parser", "packages/server", "packages/utils", @@ -9,6 +10,12 @@ members = [ [workspace.dependencies] anyhow = "1.0" +bevy_app = "0.13.2" +bevy_core = "0.13.2" +bevy_derive = "0.13.2" +bevy_log = "0.13.2" +bevy_ecs = "0.13.2" +bevy_utils = "0.13.2" bitflags = "2.5" gramatika = { version = "0.6.0", features = ["substr-source"] } parking_lot = "0.12" diff --git a/package-lock.json b/package-lock.json index 9d3b2554..41610cec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "@swc/helpers": "~0.5.2", "@types/jest": "29.4.4", "@types/node": "18.16.9", - "@types/vscode": "^1.61.0", + "@types/vscode": "^1.75.0", "@typescript-eslint/eslint-plugin": "7.3.0", "@typescript-eslint/parser": "7.3.0", "@vscode-devkit/grammar": "0.0.1", @@ -3905,9 +3905,9 @@ "dev": true }, "node_modules/@types/vscode": { - "version": "1.62.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.62.0.tgz", - "integrity": "sha512-iGlQJ1w5e3qPUryroO6v4lxg3ql1ztdTCwQW3xEwFawdyPLoeUSv48SYfMwc7kQA7h6ThUqflZIjgKAykeF9oA==", + "version": "1.89.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.89.0.tgz", + "integrity": "sha512-TMfGKLSVxfGfoO8JfIE/neZqv7QLwS4nwPwL/NwMvxtAY2230H2I4Z5xx6836pmJvMAzqooRQ4pmLm7RUicP3A==", "dev": true }, "node_modules/@types/yargs": { diff --git a/package.json b/package.json index 939a1dfe..bfccd388 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "@swc/helpers": "~0.5.2", "@types/jest": "29.4.4", "@types/node": "18.16.9", - "@types/vscode": "^1.61.0", + "@types/vscode": "^1.75.0", "@typescript-eslint/eslint-plugin": "7.3.0", "@typescript-eslint/parser": "7.3.0", "@vscode-devkit/grammar": "0.0.1", diff --git a/packages/client/src/app/context.ts b/packages/client/src/app/context.ts index 9daf2ea3..0f4bfbe1 100644 --- a/packages/client/src/app/context.ts +++ b/packages/client/src/app/context.ts @@ -1,4 +1,4 @@ -import { ExtensionContext, OutputChannel, window } from "vscode"; +import { ExtensionContext, LogOutputChannel, window } from "vscode"; import { LanguageClient } from "vscode-languageclient/node"; // prettier-ignore @@ -8,12 +8,12 @@ class Context implements ExtensionContext { inner: ExtensionContext; client: LanguageClient; - private _channel: OutputChannel; + private _channel: LogOutputChannel; constructor(ctx: ExtensionContext, client: LanguageClient) { this.inner = ctx; this.client = client; - this._channel = window.createOutputChannel("WGSL Language Client"); + this._channel = window.createOutputChannel("WGSL Language Client", { log: true }); Context.instance = this; } @@ -39,8 +39,32 @@ class Context implements ExtensionContext { get asAbsolutePath() { return this.inner.asAbsolutePath } - log(message: string): void { - this._channel.appendLine(message); + append(value: string): void { + this._channel.append(value); + } + + appendLine(value: string): void { + this._channel.appendLine(value); + } + + trace(message: string, ...args: any[]): void { + this._channel.trace(message, ...args); + } + + debug(message: string, ...args: any[]): void { + this._channel.debug(message, ...args); + } + + info(message: string, ...args: any[]): void { + this._channel.info(message, ...args); + } + + warn(message: string, ...args: any[]): void { + this._channel.warn(message, ...args); + } + + error(error: string | Error, ...args: any[]): void { + this._channel.error(error, ...args); } } diff --git a/packages/client/src/app/main.ts b/packages/client/src/app/main.ts index 91e255af..148b39d1 100644 --- a/packages/client/src/app/main.ts +++ b/packages/client/src/app/main.ts @@ -10,8 +10,6 @@ import contentProviders, { // prettier-ignore export function activate(context: ExtensionContext) { - console.log("WGSL Language Support activated"); - ctx.bootstrap(context, client.create()); contentProviders.register("wgsl-ast", DebugAstProvider); diff --git a/packages/log/Cargo.toml b/packages/log/Cargo.toml new file mode 100644 index 00000000..c593edd9 --- /dev/null +++ b/packages/log/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "wgsl-lsp-log" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" + +[dependencies] +bevy_app = { workspace = true } +bevy_ecs = { workspace = true } +bevy_utils = { workspace = true } +time = { version = "0.3.36", features = ["formatting", "local-offset", "macros"]} +tracing-error = "0.2.0" +tracing-log = "0.2.0" +tracing-subscriber = { version = "0.3.1", features = [ + "env-filter", + "fmt", + "registry", + "std", + "time", +]} diff --git a/packages/log/project.json b/packages/log/project.json new file mode 100644 index 00000000..759d9aa0 --- /dev/null +++ b/packages/log/project.json @@ -0,0 +1,36 @@ +{ + "name": "log", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "projectType": "library", + "sourceRoot": "packages/log/src", + "targets": { + "build": { + "executor": "@nxrs/cargo:build", + "options": { + "package": "wgsl-lsp-log", + "profile": "dev" + }, + "configurations": { + "production": { + "profile": "release" + } + } + }, + "test": { + "executor": "@nxrs/cargo:test", + "options": { + "package": "wgsl-lsp-log" + } + }, + "lint": { + "executor": "@nxrs/cargo:clippy", + "options": { + "package": "wgsl-lsp-log", + "fix": false, + "failOnWarnings": true, + "noDeps": true + } + } + }, + "tags": [] +} diff --git a/packages/log/src/lib.rs b/packages/log/src/lib.rs new file mode 100644 index 00000000..449c900a --- /dev/null +++ b/packages/log/src/lib.rs @@ -0,0 +1,113 @@ +use bevy_app::{App, Plugin}; +use bevy_utils::tracing::{subscriber as bevy_subscriber, Level}; +pub use bevy_utils::{ + debug_once, error_once, info_once, once, trace_once, + tracing::{ + debug, debug_span, error, error_span, info, info_span, trace, trace_span, warn, warn_span, + }, + warn_once, +}; +use tracing_error::ErrorLayer; +use tracing_log::LogTracer; +use tracing_subscriber::{fmt::time::FormatTime, prelude::*, registry::Registry, EnvFilter}; + +pub struct LogPlugin { + /// Filters logs using the [`EnvFilter`] format + pub filter: String, + + /// Filters out logs that are "less than" the given level. + /// This can be further filtered using the `filter` setting. + pub level: Level, +} + +impl Default for LogPlugin { + fn default() -> Self { + Self { + filter: String::new(), + level: Level::INFO, + } + } +} + +impl Plugin for LogPlugin { + fn build(&self, _: &mut App) { + let old_handler = std::panic::take_hook(); + std::panic::set_hook(Box::new(move |infos| { + eprintln!("{}", tracing_error::SpanTrace::capture()); + old_handler(infos); + })); + + let default_filter = format!("{},{}", self.level, self.filter); + let filter_layer = EnvFilter::try_from_default_env() + .or_else(|_| EnvFilter::try_new(&default_filter)) + .unwrap(); + + let subscriber = Registry::default() + .with(filter_layer) + .with(ErrorLayer::default()) + .with( + tracing_subscriber::fmt::layer() + .with_ansi(false) + .with_timer(fmt_time()) + .with_writer(std::io::stderr), + ); + + #[cfg(r#false)] + let subscriber = { + let log_file_timestamp = time::OffsetDateTime::now_local() + .unwrap() + .format(time::macros::format_description!( + "[year]-[month padding:zero]-[day padding:zero]_\ + [hour repr:24]-[minute padding:zero]-[second padding:zero]" + )) + .unwrap(); + + let log_path = format!("D:/.vscode-wgsl/{log_file_timestamp}.log"); + let log_file = std::fs::OpenOptions::new() + .append(false) + .write(true) + .truncate(true) + .create(true) + .open(log_path) + .unwrap(); + + subscriber.with( + tracing_subscriber::fmt::layer() + .with_ansi(false) + .with_timer(fmt_time()) + .with_writer(log_file), + ) + }; + + let subscriber = Box::new(subscriber); + + let logger_already_set = LogTracer::init().is_err(); + let subscriber_already_set = bevy_subscriber::set_global_default(subscriber).is_err(); + + match (logger_already_set, subscriber_already_set) { + (true, true) => error!( + "Could not set global logger and tracing subscriber as they are already set. \ + Consider disabling LogPlugin." + ), + (true, false) => error!( + "Could not set global logger as it is already set. \ + Consider disabling LogPlugin." + ), + (false, true) => error!( + "Could not set global tracing subscriber as it is already set. \ + Consider disabling LogPlugin." + ), + (false, false) => (), + } + } +} + +fn fmt_time() -> impl FormatTime { + let timer = time::macros::format_description!( + "[year]-[month padding:zero]-[day padding:zero] \ + [hour repr:24]:[minute padding:zero]:[second padding:zero].[subsecond digits:3]" + ); + let time_offset = time::UtcOffset::current_local_offset().unwrap_or(time::UtcOffset::UTC); + + tracing_subscriber::fmt::time::OffsetTime::new(time_offset, timer) +} diff --git a/packages/parser/src/comment.rs b/packages/parser/src/comment.rs index 8573cab2..360780e9 100644 --- a/packages/parser/src/comment.rs +++ b/packages/parser/src/comment.rs @@ -46,7 +46,7 @@ impl Parse for Comment { None => Err(SpannedError { message: "Unexpected end of input".into(), source: input.source(), - span: None, + span: input.prev().map(|token| token.span()), }), } } @@ -120,7 +120,7 @@ impl Parse for BlockComment { return Err(SpannedError { message: "Unexpected end of input".into(), source: input.source(), - span: None, + span: input.prev().map(|token| token.span()), }); } } diff --git a/packages/parser/src/common.rs b/packages/parser/src/common.rs index 19caed50..610573ab 100644 --- a/packages/parser/src/common.rs +++ b/packages/parser/src/common.rs @@ -243,7 +243,7 @@ impl Parse for TypeDecl { return Err(SpannedError { message: "Unexpected end of input".into(), source: input.source(), - span: None, + span: input.prev().map(|token| token.span()), }) } } diff --git a/packages/parser/src/decl/import.rs b/packages/parser/src/decl/import.rs index ddaa4892..e524bb88 100644 --- a/packages/parser/src/decl/import.rs +++ b/packages/parser/src/decl/import.rs @@ -212,7 +212,7 @@ impl Parse for ImportPath { None => Err(SpannedError { message: "Unexpected end of input".into(), source: input.source(), - span: None, + span: input.prev().map(|token| token.span()), }), } } diff --git a/packages/parser/src/decl/mod.rs b/packages/parser/src/decl/mod.rs index bf78c192..bf61bd45 100644 --- a/packages/parser/src/decl/mod.rs +++ b/packages/parser/src/decl/mod.rs @@ -132,7 +132,7 @@ impl Parse for Decl { None => Err(SpannedError { message: "Unexpected end of input".into(), source: input.source(), - span: None, + span: input.prev().map(|token| token.span()), }), } } diff --git a/packages/parser/src/parser.rs b/packages/parser/src/parser.rs index 5870deb3..2e54af89 100644 --- a/packages/parser/src/parser.rs +++ b/packages/parser/src/parser.rs @@ -59,7 +59,7 @@ pub(crate) trait ErrorRecoveringParseStream: ParseStreamer { let mut results = vec![]; let mut recovering = false; - while loop_condition(self) { + while !self.is_empty() && loop_condition(self) { match self.parse::
() {
Ok(parsed) => {
if recovering {
diff --git a/packages/parser/src/stmt.rs b/packages/parser/src/stmt.rs
index 96197cad..5a256a36 100644
--- a/packages/parser/src/stmt.rs
+++ b/packages/parser/src/stmt.rs
@@ -328,7 +328,7 @@ impl Parse for SwitchBody {
return Err(SpannedError {
message: "Unexpected end of input".into(),
source: input.source(),
- span: None,
+ span: input.prev().map(|token| token.span()),
})
}
};
@@ -371,7 +371,7 @@ impl Parse for CaseStmt {
return Err(SpannedError {
message: "Unexpected end of input".into(),
source: input.source(),
- span: None,
+ span: input.prev().map(|token| token.span()),
});
}
};
@@ -480,7 +480,7 @@ impl Parse for ForStmt {
return Err(SpannedError {
message: "Unexpected end of input".into(),
source: input.source(),
- span: None,
+ span: input.prev().map(|token| token.span()),
})
}
};
diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml
index 4c779d67..82a50fa3 100644
--- a/packages/server/Cargo.toml
+++ b/packages/server/Cargo.toml
@@ -6,11 +6,12 @@ license = "MIT OR Apache-2.0"
[dependencies]
anyhow = { workspace = true }
-bevy_app = "0.13.2"
-bevy_core = "0.13.2"
-bevy_derive = "0.13.2"
-bevy_ecs = "0.13.2"
-bevy_utils = "0.13.2"
+bevy_app = { workspace = true }
+bevy_core = { workspace = true }
+bevy_derive = { workspace = true }
+bevy_ecs = { workspace = true }
+# bevy_log = { workspace = true }
+bevy_utils = { workspace = true }
bitflags = { workspace = true }
crossbeam = "0.8"
gramatika = { workspace = true }
@@ -23,6 +24,10 @@ ropey = "1.5"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
+[dependencies.log]
+package = "wgsl-lsp-log"
+path = "../log"
+
[dependencies.parser]
package = "wgsl-parser"
path = "../parser"
diff --git a/packages/server/src/config.rs b/packages/server/src/config.rs
index f8cafd06..fcfbca64 100644
--- a/packages/server/src/config.rs
+++ b/packages/server/src/config.rs
@@ -94,7 +94,7 @@ fn update_config(
mut er_config_change: EventReader