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, ) -> anyhow::Result<()> { if er_config_change.len() > 1 { - eprintln!("WARNING: Multiple configuration changes are not yet handled correctly!"); + log::warn!("Multiple configuration changes are not yet handled correctly!"); } if let Some(event) = er_config_change.read().last() { @@ -121,8 +121,8 @@ impl TryFrom<&serde_json::Value> for Config { bail!("Cannot deserialize configuration from an empty array"); } if configs.len() > 1 { - eprintln!("WARNING: Multiple configurations not yet handled correctly!"); - eprintln!(" Configurations: {configs:?}"); + log::warn!("WARNING: Multiple configurations not yet handled correctly!"); + log::warn!(" Configurations: {configs:?}"); serde_json::from_value(configs.iter().last().unwrap().clone())? } diff --git a/packages/server/src/declarations/find.rs b/packages/server/src/declarations/find.rs index 4cb68b53..41a9afe6 100644 --- a/packages/server/src/declarations/find.rs +++ b/packages/server/src/declarations/find.rs @@ -34,12 +34,12 @@ pub(super) fn find_decl( let parent_expr = parser::utils::find_parent::(tree, needle.span()); if parent_expr.is_none() && needle.kind() != TokenKind::Struct { if debug { - eprintln!("Failed to find parent expression for needle"); + log::debug!("Failed to find parent expression for needle"); } if let Some(qualified_path) = imports?.get(&needle.lexeme()) { if debug { - eprintln!("Found import: {qualified_path:?}"); + log::debug!("Found import: {qualified_path:?}"); } return find_directly_imported( needle, @@ -61,12 +61,12 @@ pub(super) fn find_decl( let ident = if let Some(parent_expr) = parent_expr.as_ref() { if debug { - eprintln!("Parent expression: {parent_expr:#?}"); + log::debug!("Parent expression: {parent_expr:#?}"); } find_ident_expr_in_parent_expr(needle, parent_expr, debug)? } else if let Some(parent_decl) = parent_decl.as_ref() { if debug { - eprintln!("Parent declaration: {parent_decl:#?}"); + log::debug!("Parent declaration: {parent_decl:#?}"); } find_ident_expr_in_parent_decl(needle, parent_decl, debug)? } else { @@ -87,9 +87,9 @@ pub(super) fn find_decl( let (namespace_tokens, leaf) = decompose_ident_expr(ident); if debug { - eprintln!("Decomposed..."); - eprintln!(" namespace: {namespace_tokens:?}"); - eprintln!(" leaf: {leaf:?}"); + log::debug!("Decomposed..."); + log::debug!(" namespace: {namespace_tokens:?}"); + log::debug!(" leaf: {leaf:?}"); } if let Some(result) = find_for_imported_namespace( @@ -124,7 +124,7 @@ fn find_directly_imported( debug: bool, ) -> Option<(Token, Url)> { if debug { - eprintln!("find_directly_imported {needle:?}"); + log::debug!("find_directly_imported {needle:?}"); } let mut end = qualified_path.len(); @@ -324,7 +324,7 @@ fn find_for_imported_namespace( debug: bool, ) -> Option<(Token, Url)> { if debug { - eprintln!("find_symbol_for_imported_namespace {needle:?}"); + log::debug!("find_symbol_for_imported_namespace {needle:?}"); } let [namespace] = &namespace_tokens else { @@ -332,12 +332,12 @@ fn find_for_imported_namespace( }; let qualified_path = imports.get(&namespace.lexeme())?; if debug { - eprintln!("import: {qualified_path:?}"); + log::debug!("import: {qualified_path:?}"); } let module_uri = module_paths.get(qualified_path)?; if debug { - eprintln!("Module URI: {module_uri}"); + log::debug!("Module URI: {module_uri}"); } let &entity = documents.get(module_uri)?; @@ -420,7 +420,7 @@ fn find_ident_expr_in_parent_expr<'a>( debug: bool, ) -> Option<&'a IdentExpr> { if debug { - eprintln!("find_ident_expr {expr:#?}"); + log::debug!("find_ident_expr {expr:#?}"); } match expr { @@ -444,7 +444,7 @@ fn find_ident_expr_in_parent_decl<'a>( debug: bool, ) -> Option<&'a IdentExpr> { if debug { - eprintln!("find_ident_expr_in_parent_decl: {decl:#?}"); + log::debug!("find_ident_expr_in_parent_decl: {decl:#?}"); } match decl { Decl::Param(ParamDecl { ty, .. }) @@ -468,7 +468,7 @@ fn find_ident_expr_in_type_decl<'a>( debug: bool, ) -> Option<&'a IdentExpr> { if debug { - eprintln!("find_ident_expr_in_type_decl: {ty:#?}"); + log::debug!("find_ident_expr_in_type_decl: {ty:#?}"); } if ty.name.span().contains(needle.span()) { Some(&ty.name) diff --git a/packages/server/src/declarations/mod.rs b/packages/server/src/declarations/mod.rs index 8e142608..f928a1e5 100644 --- a/packages/server/src/declarations/mod.rs +++ b/packages/server/src/declarations/mod.rs @@ -227,7 +227,9 @@ fn map_token_references( )]); } } else { - eprintln!("Failed to find TokenReferences for document: {entity:?} {decl_uri}"); + log::error!( + "Failed to find TokenReferences for document: {entity:?} {decl_uri}" + ); } } diff --git a/packages/server/src/documents/mod.rs b/packages/server/src/documents/mod.rs index 5fdfcd55..3ea32cdd 100644 --- a/packages/server/src/documents/mod.rs +++ b/packages/server/src/documents/mod.rs @@ -104,6 +104,7 @@ fn read_new_documents( for event in e_doc_reads.drain() { let source = event.0.text_document.text; let uri = event.0.text_document.uri; + log::info!(" reading document \"{uri}\""); let canon_uri = uri.clone().into_canonical(); if r_pending_reads.contains(&canon_uri) { @@ -122,6 +123,8 @@ fn update_existing_documents( ) -> anyhow::Result<()> { for event in e_doc_changes.drain() { let uri = event.0.text_document.uri; + log::info!(" updating document \"{uri}\""); + let Some(&entity) = r_documents.get(&uri) else { bail!(" Failed to find document entity for URI: {uri}"); }; @@ -153,6 +156,8 @@ fn handle_config_changes( mut r_pending_docs: ResMut, q_docs: Query<(&DocumentUri, &WgslSource)>, ) { + log::info!(" Handling configuration change"); + for (uri, source) in q_docs.iter() { if !r_pending_docs.contains_key(&**uri) { r_pending_docs.insert(uri.0.clone(), source.0.clone()); @@ -168,9 +173,13 @@ fn process_pending_documents( r_config: Res, ) { for (uri, source) in r_pending_docs.drain() { + log::info!(" Processing document \"{uri}\""); + let entity = if let Some(&entity) = r_documents.get(&uri) { + log::trace!(" Found entity in DocumentsMap"); entity } else { + log::trace!(" Spawning new entity"); let entity = cmd .spawn(( DocumentUri(uri.clone()), @@ -183,12 +192,18 @@ fn process_pending_documents( entity }; + log::trace!(" Document entity: {entity:?}"); let mut parser = ParseStream::from(source); let tree = parser.parse::().unwrap(); + log::trace!(" Parsed syntax tree"); let import_path_decl = find_import_path_decl(&tree); if let Some(import_path_decl) = import_path_decl { + log::trace!( + " Found import path declaration: {}", + import_path_decl.qualified_name() + ); register_module_path(&mut r_module_paths, import_path_decl, &uri); } @@ -198,11 +213,16 @@ fn process_pending_documents( comments, errors, } = parser.into_inner(); + log::trace!(" Extracted ParseResult with:"); + log::trace!(" {} tokens", tokens.len()); + log::trace!(" {} comments", comments.len()); + log::trace!(" {} errors", errors.len()); let needs_preprocessing = !errors.is_empty() && tokens .iter() .any(|token| matches!(token.kind(), TokenKind::Pragma)); + log::trace!(" Document needs preprocessing: {needs_preprocessing}"); if !needs_preprocessing { if let Some(imported_symbols) = collect_imported_symbols(&tree) { @@ -321,7 +341,7 @@ fn register_module_path(map: &mut ModulePathsMap, import_path_decl: &ImportPathD map.insert(module_path, uri.clone()); - eprintln!( + log::info!( " Module paths updated: `{}` -> {}", import_path_decl.qualified_name(), uri diff --git a/packages/server/src/ipc/mod.rs b/packages/server/src/ipc/mod.rs index 3537851f..f3289e37 100644 --- a/packages/server/src/ipc/mod.rs +++ b/packages/server/src/ipc/mod.rs @@ -94,7 +94,7 @@ fn start_event_loop( match msg { Message::Request(request) => { if let Err(err) = request::dispatch(&mut app.world, request) { - eprintln!("{err}"); + log::error!("{err}"); } } Message::Response(response) => { @@ -103,14 +103,14 @@ fn start_event_loop( (Some(result), None) => Ok(result), (None, Some(err)) => Err(err), (Some(result), Some(err)) => { - eprintln!("WARNING: Response from client has a result and an error."); - eprintln!(" Ignoring the error: {err:?}"); + log::warn!("Response from client has a result and an error."); + log::warn!(" Ignoring the error: {err:?}"); Ok(result) } (None, None) => { - eprintln!("WARNING: Response from client has no result and no error."); - eprintln!(" Ignoring response for request ID: {id}"); + log::warn!("Response from client has no result and no error."); + log::warn!(" Ignoring response for request ID: {id}"); app.update(); continue; @@ -121,7 +121,7 @@ fn start_event_loop( } Message::Notification(notification) => { if let Err(err) = notify::dispatch(&mut app.world, notification) { - eprintln!("{err}"); + log::error!("{err}"); } } } diff --git a/packages/server/src/ipc/notify.rs b/packages/server/src/ipc/notify.rs index 9b10dc7d..a1dc58dd 100644 --- a/packages/server/src/ipc/notify.rs +++ b/packages/server/src/ipc/notify.rs @@ -11,13 +11,14 @@ use lsp_types::{ DidCloseTextDocumentParams, DidOpenTextDocumentParams, NumberOrString, }; -// use super::GetUri; +use super::GetUri; pub fn register_events(app: &mut App) { app.add_event::() .add_event::() .add_event::() - .add_event::(); + .add_event::() + .add_event::(); } #[derive(Event, Clone, Debug, Deref, DerefMut)] @@ -38,12 +39,11 @@ pub struct CancelRequest(pub RequestId); pub(super) fn dispatch(world: &mut World, n: Notification) -> anyhow::Result<()> { use lsp_types::notification::Notification as _; - // TODO: Figure out how to do proper logging with filters and such - // if let Some(uri) = n.params.uri() { - // eprintln!("[Notification] {} : {uri}", n.method); - // } else { - // eprintln!("[Notification] {}", n.method); - // } + if let Some(uri) = n.params.uri() { + log::trace!("[Notification] {} : \"{uri}\"", n.method); + } else { + log::trace!("[Notification] {}", n.method); + } match &n.method[..] { DidOpenTextDocument::METHOD => { diff --git a/packages/server/src/ipc/request.rs b/packages/server/src/ipc/request.rs index 17ebe0e1..f2aa2c53 100644 --- a/packages/server/src/ipc/request.rs +++ b/packages/server/src/ipc/request.rs @@ -7,7 +7,7 @@ use lsp_types::{ SemanticTokensDeltaParams, SemanticTokensParams, SemanticTokensRangeParams, }; -// use super::GetUri; +use super::GetUri; use crate::lsp_extensions::{DebugAstRequest, DebugDocumentParams, DebugTokensRequest}; pub fn register_events(app: &mut App) { @@ -68,12 +68,11 @@ pub(super) fn dispatch(world: &mut World, r: lsp_server::Request) -> anyhow::Res }; use SemanticTokens::*; - // TODO: Figure out how to do proper logging with filters and such - // if let Some(uri) = r.params.uri() { - // eprintln!("[Request] {} : {uri}", r.method); - // } else { - // eprintln!("[Request] {}", r.method); - // } + if let Some(uri) = r.params.uri() { + log::trace!("[Request] {} [{}] : \"{uri}\"", r.method, r.id); + } else { + log::trace!("[Request] {} [{}]", r.method, r.id); + } match &r.method[..] { LspHoverRequest::METHOD => { diff --git a/packages/server/src/main.rs b/packages/server/src/main.rs index a1dddff4..ab1f5c7e 100644 --- a/packages/server/src/main.rs +++ b/packages/server/src/main.rs @@ -1,8 +1,10 @@ use bevy_app::App; use bevy_core::{TaskPoolPlugin, TypeRegistrationPlugin}; +use bevy_utils::tracing::Level; use config::ConfigPlugin; use declarations::DeclarationsPlugin; use dependencies::DependenciesPlugin; +use log::LogPlugin; use lsp_server::Connection; use crate::{ @@ -49,6 +51,10 @@ fn start() -> App { app.add_plugins(( TaskPoolPlugin::default(), TypeRegistrationPlugin, + LogPlugin { + level: Level::WARN, + filter: "warn,server=trace".into(), + }, ConfigPlugin, DocumentsPlugin, DeclarationsPlugin, diff --git a/packages/server/src/pre/mod.rs b/packages/server/src/pre/mod.rs index 75e5a8f2..6ead0eec 100644 --- a/packages/server/src/pre/mod.rs +++ b/packages/server/src/pre/mod.rs @@ -26,7 +26,7 @@ pub struct PruneResult { } pub fn prune(uri: &Url, source: Substr, defs: HashMap) -> PruneResult { - eprintln!(" Preprocessing {uri}"); + log::info!(" Preprocessing \"{uri}\""); let (parsed, source, _pre_parse_errors) = pre::parse(source); @@ -35,13 +35,16 @@ pub fn prune(uri: &Url, source: Substr, defs: HashMap) -> PruneR let (pruned, source_map, replacements, replacement_errors) = pruner.write_output(); - eprintln!("Pruned source for {uri}:"); + log::debug!("Pruned source for {uri}:"); for (idx, line) in pruned.lines().enumerate() { - eprintln!(" {:>4} | {line}", idx + 1); + log::debug!(" {:>4} | {line}", idx + 1); } - eprintln!("Source map for {uri}:"); - eprintln!("{source_map:#?}"); + log::debug!("Source map for \"{uri}\":"); + let source_map_dbg = format!("{source_map:#?}"); + for line in source_map_dbg.lines() { + log::debug!("{line}"); + } PruneResult { original: pruner.source, diff --git a/packages/server/src/pre/pruner.rs b/packages/server/src/pre/pruner.rs index dafab449..50213e35 100644 --- a/packages/server/src/pre/pruner.rs +++ b/packages/server/src/pre/pruner.rs @@ -255,14 +255,14 @@ impl Visitor for Pruner { rem }; - eprintln!("Defining `{def}` = `{value}`"); + // eprintln!("Defining `{def}` = `{value}`"); self.defs.insert(def.into(), value.into()); } else { - eprintln!("Defining `{def}`"); + // eprintln!("Defining `{def}`"); self.defs.insert(def.into(), String::new()); } } else { - eprintln!("Defining `{rem}`"); + // eprintln!("Defining `{rem}`"); self.defs.insert(rem.into(), String::new()); } } diff --git a/packages/server/src/references.rs b/packages/server/src/references.rs index 755c9a07..de03ece3 100644 --- a/packages/server/src/references.rs +++ b/packages/server/src/references.rs @@ -80,7 +80,7 @@ fn handle_requests( let include_decl = request.context.include_declaration; let Some(&entity) = r_docs.get(uri) else { - eprintln!("Failed to find document entity for URI: {uri}"); + log::error!("Failed to find document entity for URI: {uri}"); // TODO: Try again next update r_ipc.send(Message::Response(Response { diff --git a/packages/server/src/testing.rs b/packages/server/src/testing.rs index e82078b6..1192826d 100644 --- a/packages/server/src/testing.rs +++ b/packages/server/src/testing.rs @@ -153,7 +153,7 @@ fn handle_server_requests( ew_responses.send(ipc::Response(id, Ok(response))); } other => { - eprintln!("WARNING: Unhandled server request: {other}"); + log::warn!("Unhandled server request: {other}"); } } } diff --git a/packages/server/src/utils.rs b/packages/server/src/utils.rs index eaf6cfe6..f758da3d 100644 --- a/packages/server/src/utils.rs +++ b/packages/server/src/utils.rs @@ -6,7 +6,7 @@ use parser::{utils::ToRange, Span, Spanned}; pub fn log_error(result: Result<(), E>) { if let Err(err) = result { - eprintln!("{err}"); + log::error!("{err}"); } } diff --git a/packages/server/src/validation/conv.rs b/packages/server/src/validation/conv.rs index c57bc9ad..1796e0d9 100644 --- a/packages/server/src/validation/conv.rs +++ b/packages/server/src/validation/conv.rs @@ -45,7 +45,11 @@ impl<'a> IntoDiagnostics<'a> for WithSpan { fn into_diagnostics(self, kind: ErrorKind, data: &'a Self::Data) -> Vec { use NagaValidationError::*; - eprintln!("Converting naga validation error: {self:#?}"); + log::debug!("Converting naga validation error:"); + let self_dbg = format!("{self:#?}"); + for line in self_dbg.lines() { + log::debug!("{}", line.replace(" ", " ")); + } let (module, src, tokens, ast, scopes) = data;