From d3365c3bff01a19f2c6545d9dac5cca5f1a67e61 Mon Sep 17 00:00:00 2001 From: Noah Santschi-Cooney Date: Sun, 3 Apr 2022 21:31:18 +0100 Subject: [PATCH] big heckin reworkerino to use the standard #line directive as per spec --- server/Cargo.lock | 63 ++---- server/Cargo.toml | 46 +---- server/Makefile | 2 +- server/logging/Cargo.toml | 13 ++ server/{src/logging.rs => logging/src/lib.rs} | 11 +- server/logging_macro/Cargo.toml | 12 ++ server/logging_macro/src/lib.rs | 24 +++ server/main/Cargo.toml | 35 ++++ server/{ => main}/src/commands/graph_dot.rs | 0 .../src/commands/merged_includes.rs | 4 +- server/{ => main}/src/commands/mod.rs | 0 server/{ => main}/src/commands/parse_tree.rs | 0 server/{ => main}/src/configuration.rs | 0 server/{ => main}/src/consts.rs | 0 server/{ => main}/src/dfs.rs | 2 + server/main/src/diagnostics_parser.rs | 194 ++++++++++++++++++ server/{ => main}/src/graph.rs | 2 + server/{ => main}/src/lsp_ext.rs | 0 server/{ => main}/src/main.rs | 54 +++-- server/{ => main}/src/merge_views.rs | 167 ++++++++++----- server/{ => main}/src/navigation.rs | 4 +- server/{ => main}/src/opengl.rs | 15 +- server/main/src/source_mapper.rs | 52 +++++ server/{ => main}/src/test.rs | 10 +- server/{ => main}/src/url_norm.rs | 0 server/{ => main}/testdata/01/common.glsl | 0 server/{ => main}/testdata/01/final.fsh | 0 server/main/testdata/01/final.fsh.merge | 11 + server/{ => main}/testdata/02/final.fsh | 0 server/{ => main}/testdata/02/final.fsh.merge | 14 +- .../{ => main}/testdata/02/utils/burger.glsl | 0 .../{ => main}/testdata/02/utils/sample.glsl | 0 server/{ => main}/testdata/02/utils/test.glsl | 0 server/{ => main}/testdata/03/final.fsh | 0 server/{ => main}/testdata/03/final.fsh.merge | 14 +- .../{ => main}/testdata/03/utils/burger.glsl | 0 .../{ => main}/testdata/03/utils/sample.glsl | 0 server/{ => main}/testdata/03/utils/test.glsl | 0 server/{ => main}/testdata/04/final.fsh | 0 server/main/testdata/04/final.fsh.merge | 23 +++ .../{ => main}/testdata/04/lib/matrices.glsl | 0 .../{ => main}/testdata/04/utils/stuff1.glsl | 0 .../{ => main}/testdata/04/utils/stuff2.glsl | 0 .../testdata/04/utils/utilities.glsl | 0 server/{ => main}/testdata/05/common.glsl | 0 server/{ => main}/testdata/05/final.fsh | 0 server/{ => main}/testdata/05/final.fsh.merge | 0 .../{ => main}/testdata/05/test/banana.glsl | 0 .../{ => main}/testdata/05/test/burger.glsl | 0 server/src/diagnostics_parser.rs | 162 --------------- server/testdata/01/final.fsh.merge | 13 -- server/testdata/04/final.fsh.merge | 25 --- 52 files changed, 574 insertions(+), 398 deletions(-) create mode 100644 server/logging/Cargo.toml rename server/{src/logging.rs => logging/src/lib.rs} (92%) create mode 100644 server/logging_macro/Cargo.toml create mode 100644 server/logging_macro/src/lib.rs create mode 100644 server/main/Cargo.toml rename server/{ => main}/src/commands/graph_dot.rs (100%) rename server/{ => main}/src/commands/merged_includes.rs (95%) rename server/{ => main}/src/commands/mod.rs (100%) rename server/{ => main}/src/commands/parse_tree.rs (100%) rename server/{ => main}/src/configuration.rs (100%) rename server/{ => main}/src/consts.rs (100%) rename server/{ => main}/src/dfs.rs (99%) create mode 100644 server/main/src/diagnostics_parser.rs rename server/{ => main}/src/graph.rs (99%) rename server/{ => main}/src/lsp_ext.rs (100%) rename server/{ => main}/src/main.rs (93%) rename server/{ => main}/src/merge_views.rs (81%) rename server/{ => main}/src/navigation.rs (94%) rename server/{ => main}/src/opengl.rs (88%) create mode 100644 server/main/src/source_mapper.rs rename server/{ => main}/src/test.rs (98%) rename server/{ => main}/src/url_norm.rs (100%) rename server/{ => main}/testdata/01/common.glsl (100%) rename server/{ => main}/testdata/01/final.fsh (100%) create mode 100644 server/main/testdata/01/final.fsh.merge rename server/{ => main}/testdata/02/final.fsh (100%) rename server/{ => main}/testdata/02/final.fsh.merge (57%) rename server/{ => main}/testdata/02/utils/burger.glsl (100%) rename server/{ => main}/testdata/02/utils/sample.glsl (100%) rename server/{ => main}/testdata/02/utils/test.glsl (100%) rename server/{ => main}/testdata/03/final.fsh (100%) rename server/{ => main}/testdata/03/final.fsh.merge (53%) rename server/{ => main}/testdata/03/utils/burger.glsl (100%) rename server/{ => main}/testdata/03/utils/sample.glsl (100%) rename server/{ => main}/testdata/03/utils/test.glsl (100%) rename server/{ => main}/testdata/04/final.fsh (100%) create mode 100644 server/main/testdata/04/final.fsh.merge rename server/{ => main}/testdata/04/lib/matrices.glsl (100%) rename server/{ => main}/testdata/04/utils/stuff1.glsl (100%) rename server/{ => main}/testdata/04/utils/stuff2.glsl (100%) rename server/{ => main}/testdata/04/utils/utilities.glsl (100%) rename server/{ => main}/testdata/05/common.glsl (100%) rename server/{ => main}/testdata/05/final.fsh (100%) rename server/{ => main}/testdata/05/final.fsh.merge (100%) rename server/{ => main}/testdata/05/test/banana.glsl (100%) rename server/{ => main}/testdata/05/test/burger.glsl (100%) delete mode 100644 server/src/diagnostics_parser.rs delete mode 100644 server/testdata/01/final.fsh.merge delete mode 100644 server/testdata/04/final.fsh.merge diff --git a/server/Cargo.lock b/server/Cargo.lock index 1e22ef2..5584513 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -61,21 +61,6 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" -[[package]] -name = "bit-set" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - [[package]] name = "bitflags" version = "1.2.1" @@ -131,15 +116,6 @@ dependencies = [ "libc", ] -[[package]] -name = "chan" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d14956a3dae065ffaa0d92ece848ab4ced88d32361e7fdfbfd653a5c454a1ed8" -dependencies = [ - "rand 0.3.23", -] - [[package]] name = "cocoa" version = "0.24.0" @@ -700,6 +676,26 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "logging" +version = "0.9.5" +dependencies = [ + "lazy_static", + "rand 0.8.5", + "slog", + "slog-atomic", + "slog-scope", + "slog-term", +] + +[[package]] +name = "logging_macro" +version = "0.9.5" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "lsp-types" version = "0.86.0" @@ -739,30 +735,25 @@ name = "mcshader-lsp" version = "0.9.5" dependencies = [ "anyhow", - "arc-swap", - "bit-set", - "chan", - "ctor", "fs_extra", "gl", "glutin", "hamcrest2", "lazy_static", + "logging", + "logging_macro", "mockall", "once_cell", "path-slash", "percent-encoding", "petgraph", "pretty_assertions", - "rand 0.8.5", "regex", "rust_lsp", "serde", "serde_json", "slog", - "slog-atomic", "slog-scope", - "slog-term", "tempdir", "thiserror", "tree-sitter", @@ -1205,16 +1196,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -dependencies = [ - "libc", - "rand 0.4.6", -] - [[package]] name = "rand" version = "0.4.6" diff --git a/server/Cargo.toml b/server/Cargo.toml index 1e02ff5..533392d 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -1,40 +1,6 @@ -[package] -name = "mcshader-lsp" -version = "0.9.5" -authors = ["Noah Santschi-Cooney "] -edition = "2021" - -[dependencies] -rust_lsp = { git = "https://github.com/Strum355/RustLSP", branch = "master" } -serde_json = "1.0" -serde = "1.0" -walkdir = "2.3" -petgraph = "0.6" -lazy_static = "1.4" -regex = "1.4" -chan = "0.1" -url = "2.2" -percent-encoding = "2.1" -anyhow = "1.0" -bit-set = "0.5" -thiserror = "1.0" -glutin = "0.28" -gl = "0.14" -ctor = "0.1" -mockall = "0.11" -path-slash = "0.1" -slog = { version = "2.7", features = [ "max_level_trace", "release_max_level_trace" ] } -slog-term = "2.9" -slog-scope = "4.4" -slog-atomic = "3.1" -once_cell = "1.7" -rand = "0.8" -arc-swap = "1.5.0" -tree-sitter = "0.20.6" -tree-sitter-glsl = "0.1.2" - -[dev-dependencies] -tempdir = "0.3" -fs_extra = "1.2" -hamcrest2 = "*" -pretty_assertions = "1.1" \ No newline at end of file +[workspace] +members = [ + "main", + "logging", + "logging_macro" +] \ No newline at end of file diff --git a/server/Makefile b/server/Makefile index 509b9af..867c64c 100644 --- a/server/Makefile +++ b/server/Makefile @@ -4,7 +4,7 @@ watchtest: RUST_BACKTRACE=0 cargo watch -x test -i Makefile test: - RUST_LIB_BACKTRACE=0 RUST_BACKTRACE=0 cargo test + RUST_LIB_BACKTRACE=0 RUST_BACKTRACE=0 cargo test -- --nocapture --color always build: cargo build diff --git a/server/logging/Cargo.toml b/server/logging/Cargo.toml new file mode 100644 index 0000000..0254091 --- /dev/null +++ b/server/logging/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "logging" +version = "0.9.5" +authors = ["Noah Santschi-Cooney "] +edition = "2021" + +[dependencies] +slog = { version = "2.7", features = [ "max_level_trace", "release_max_level_trace" ] } +slog-term = "2.9" +slog-scope = "4.4" +slog-atomic = "3.1" +rand = "0.8" +lazy_static = "1.4" \ No newline at end of file diff --git a/server/src/logging.rs b/server/logging/src/lib.rs similarity index 92% rename from server/src/logging.rs rename to server/logging/src/lib.rs index cbdb3ca..36d7f53 100644 --- a/server/src/logging.rs +++ b/server/logging/src/lib.rs @@ -2,7 +2,10 @@ use rand::{rngs, Rng}; use slog::slog_o; use slog_scope::GlobalLoggerGuard; use slog_term::{FullFormat, PlainSyncDecorator}; -use std::{cell::RefCell, io::Stderr, sync::Arc}; +use std::{cell::RefCell, sync::Arc}; + +use std::io::Stderr; + use lazy_static::lazy_static; use slog::*; use slog_atomic::*; @@ -13,9 +16,7 @@ fn new_trace_id() -> String { } pub fn slog_with_trace_id(f: F) { - slog_scope::scope(&slog_scope::logger().new(slog_o!("trace" => new_trace_id())), || { - f() - }) + slog_scope::scope(&slog_scope::logger().new(slog_o!("trace" => new_trace_id())), f) } pub fn set_logger_with_level(level: Level) -> GlobalLoggerGuard { @@ -39,4 +40,4 @@ lazy_static! { let logger = logger_base(Level::Info).fuse(); AtomicSwitch::new(logger) }; -} \ No newline at end of file +} diff --git a/server/logging_macro/Cargo.toml b/server/logging_macro/Cargo.toml new file mode 100644 index 0000000..fdf9b43 --- /dev/null +++ b/server/logging_macro/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "logging_macro" +version = "0.9.5" +authors = ["Noah Santschi-Cooney "] +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0" +syn = { version = "1.0", features = [ "full" ] } \ No newline at end of file diff --git a/server/logging_macro/src/lib.rs b/server/logging_macro/src/lib.rs new file mode 100644 index 0000000..99052bb --- /dev/null +++ b/server/logging_macro/src/lib.rs @@ -0,0 +1,24 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, parse_quote, ItemFn}; + +#[proc_macro_attribute] +pub fn log_scope(_args: TokenStream, function: TokenStream) -> TokenStream { + let mut function = parse_macro_input!(function as ItemFn); + + let function_name = function.sig.ident.to_string(); + + let stmts = function.block.stmts; + + function.block = Box::new(parse_quote!({ + use slog::{slog_o, FnValue, Level}; + use std::thread::current; + + let _guard = logging::set_logger_with_level(Level::Trace); + slog_scope::scope(&slog_scope::logger().new(slog_o!("test_name" => #function_name, "thread_num" => FnValue(|_| format!("{:?}", current().id())))), || { + #(#stmts)* + }); + })); + + TokenStream::from(quote!(#function)) +} diff --git a/server/main/Cargo.toml b/server/main/Cargo.toml new file mode 100644 index 0000000..18cc1dd --- /dev/null +++ b/server/main/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "mcshader-lsp" +version = "0.9.5" +authors = ["Noah Santschi-Cooney "] +edition = "2021" + +[dependencies] +rust_lsp = { git = "https://github.com/Strum355/RustLSP", branch = "master" } +serde_json = "1.0" +serde = "1.0" +walkdir = "2.3" +petgraph = "0.6" +lazy_static = "1.4" +regex = "1.4" +url = "2.2" +percent-encoding = "2.1" +anyhow = "1.0" +thiserror = "1.0" +glutin = "0.28" +gl = "0.14" +mockall = "0.11" +path-slash = "0.1" +slog = { version = "2.7", features = [ "max_level_trace", "release_max_level_trace" ] } +slog-scope = "4.4" +once_cell = "1.7" +tree-sitter = "0.20.6" +tree-sitter-glsl = "0.1.2" +logging = { path = "../logging" } +logging_macro = { path = "../logging_macro" } + +[dev-dependencies] +tempdir = "0.3" +fs_extra = "1.2" +hamcrest2 = "*" +pretty_assertions = "1.1" \ No newline at end of file diff --git a/server/src/commands/graph_dot.rs b/server/main/src/commands/graph_dot.rs similarity index 100% rename from server/src/commands/graph_dot.rs rename to server/main/src/commands/graph_dot.rs diff --git a/server/src/commands/merged_includes.rs b/server/main/src/commands/merged_includes.rs similarity index 95% rename from server/src/commands/merged_includes.rs rename to server/main/src/commands/merged_includes.rs index 2f9a185..3c9fea8 100644 --- a/server/src/commands/merged_includes.rs +++ b/server/main/src/commands/merged_includes.rs @@ -15,6 +15,7 @@ use std::fs; use crate::dfs; use crate::merge_views::FilialTuple; +use crate::source_mapper::SourceMapper; use crate::{graph::CachedStableGraph, merge_views, url_norm::FromJson}; use super::Invokeable; @@ -100,8 +101,9 @@ impl Invokeable for VirtualMergedDocument { }; all_sources.extend(sources); + let mut source_mapper = SourceMapper::new(all_sources.len()); let graph = self.graph.borrow(); - let view = merge_views::generate_merge_list(&tree, &all_sources, &graph); + let view = merge_views::generate_merge_list(&tree, &all_sources, &graph, &mut source_mapper); return Ok(serde_json::value::Value::String(view)); } return Err(format_err!( diff --git a/server/src/commands/mod.rs b/server/main/src/commands/mod.rs similarity index 100% rename from server/src/commands/mod.rs rename to server/main/src/commands/mod.rs diff --git a/server/src/commands/parse_tree.rs b/server/main/src/commands/parse_tree.rs similarity index 100% rename from server/src/commands/parse_tree.rs rename to server/main/src/commands/parse_tree.rs diff --git a/server/src/configuration.rs b/server/main/src/configuration.rs similarity index 100% rename from server/src/configuration.rs rename to server/main/src/configuration.rs diff --git a/server/src/consts.rs b/server/main/src/consts.rs similarity index 100% rename from server/src/consts.rs rename to server/main/src/consts.rs diff --git a/server/src/dfs.rs b/server/main/src/dfs.rs similarity index 99% rename from server/src/dfs.rs rename to server/main/src/dfs.rs index acb1c39..dfba565 100644 --- a/server/src/dfs.rs +++ b/server/main/src/dfs.rs @@ -166,6 +166,7 @@ mod dfs_test { use crate::{dfs, IncludePosition}; #[test] + #[logging_macro::log_scope] fn test_graph_dfs() { { let mut graph = CachedStableGraph::new(); @@ -272,6 +273,7 @@ mod dfs_test { } #[test] + #[logging_macro::log_scope] fn test_graph_dfs_cycle() { { let mut graph = CachedStableGraph::new(); diff --git a/server/main/src/diagnostics_parser.rs b/server/main/src/diagnostics_parser.rs new file mode 100644 index 0000000..df2f20b --- /dev/null +++ b/server/main/src/diagnostics_parser.rs @@ -0,0 +1,194 @@ +use std::{collections::HashMap, lazy::OnceCell, path::Path}; + +use regex::Regex; +use rust_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range}; +use slog_scope::debug; +use url::Url; + +use crate::{ + consts, + graph::CachedStableGraph, + opengl, + source_mapper::{SourceMapper, SourceNum}, +}; + +pub struct DiagnosticsParser<'a, T: opengl::ShaderValidator + ?Sized> { + line_offset: OnceCell, + line_regex: OnceCell, + vendor_querier: &'a T, +} + +impl<'a, T: opengl::ShaderValidator + ?Sized> DiagnosticsParser<'a, T> { + pub fn new(vendor_querier: &'a T) -> Self { + DiagnosticsParser { + line_offset: OnceCell::new(), + line_regex: OnceCell::new(), + vendor_querier, + } + } + + fn get_line_regex(&self) -> &Regex { + self.line_regex.get_or_init(|| match self.vendor_querier.vendor().as_str() { + "NVIDIA Corporation" => { + Regex::new(r#"^(?P\d+)\((?P\d+)\) : (?Perror|warning) [A-C]\d+: (?P.+)"#).unwrap() + } + _ => Regex::new(r#"^(?PERROR|WARNING): (?P[^?<>*|"\n]+):(?P\d+): '[a-z]*' : (?P.+)$"#) + .unwrap(), + }) + } + + fn get_line_offset(&self) -> u32 { + *self.line_offset.get_or_init(|| match self.vendor_querier.vendor().as_str() { + "ATI Technologies" => 0, + _ => 2, + }) + } + + pub fn parse_diagnostics_output( + &self, output: String, uri: &Path, source_mapper: &SourceMapper, graph: &CachedStableGraph, + ) -> HashMap> { + let output_lines = output.split('\n').collect::>(); + let mut diagnostics: HashMap> = HashMap::with_capacity(output_lines.len()); + + debug!("diagnostics regex selected"; "regex" => self.get_line_regex() .as_str()); + + for line in output_lines { + let diagnostic_capture = match self.get_line_regex().captures(line) { + Some(d) => d, + None => continue, + }; + + debug!("found match for output line"; "line" => line, "capture" => format!("{:?}", diagnostic_capture)); + + let msg = diagnostic_capture.name("output").unwrap().as_str(); + + let line = match diagnostic_capture.name("linenum") { + Some(c) => c.as_str().parse::().unwrap_or(0), + None => 0, + } - self.get_line_offset(); + + // TODO: line matching maybe + /* let line_text = source_lines[line as usize]; + let leading_whitespace = line_text.len() - line_text.trim_start().len(); */ + + let severity = match diagnostic_capture.name("severity") { + Some(c) => match c.as_str().to_lowercase().as_str() { + "error" => DiagnosticSeverity::Error, + "warning" => DiagnosticSeverity::Warning, + _ => DiagnosticSeverity::Information, + }, + _ => DiagnosticSeverity::Information, + }; + + let origin = match diagnostic_capture.name("filepath") { + Some(o) => { + let source_num: SourceNum = o.as_str().parse::().unwrap().into(); + let graph_node = source_mapper.get_node(source_num); + graph.get_node(graph_node).to_str().unwrap().to_string() + } + None => uri.to_str().unwrap().to_string(), + }; + + let diagnostic = Diagnostic { + range: Range::new( + /* Position::new(line, leading_whitespace as u64), + Position::new(line, line_text.len() as u64) */ + Position::new(line, 0), + Position::new(line, 1000), + ), + code: None, + severity: Some(severity), + source: Some(consts::SOURCE.into()), + message: msg.trim().into(), + related_information: None, + tags: None, + code_description: Option::None, + data: Option::None, + }; + + let origin_url = Url::from_file_path(origin).unwrap(); + match diagnostics.get_mut(&origin_url) { + Some(d) => d.push(diagnostic), + None => { + diagnostics.insert(origin_url, vec![diagnostic]); + } + }; + } + diagnostics + } +} + +#[cfg(test)] +mod diagnostics_test { + use std::path::PathBuf; + + use slog::{slog_o, Level}; + use url::Url; + + use crate::{ + diagnostics_parser::DiagnosticsParser, opengl::MockShaderValidator, source_mapper::SourceMapper, test::new_temp_server, + }; + + #[test] + #[logging_macro::log_scope] + fn test_nvidia_diagnostics() { + slog_scope::scope(&slog_scope::logger().new(slog_o!("driver" => "nvidia")), || { + let mut mockgl = MockShaderValidator::new(); + mockgl.expect_vendor().returning(|| "NVIDIA Corporation".into()); + let server = new_temp_server(Some(Box::new(mockgl))); + + let output = "0(9) : error C0000: syntax error, unexpected '}', expecting ',' or ';' at token \"}\""; + + #[cfg(target_family = "unix")] + let path: PathBuf = "/home/noah/.minecraft/shaderpacks/test/shaders/final.fsh".into(); + #[cfg(target_family = "windows")] + let path: PathBuf = "c:\\home\\noah\\.minecraft\\shaderpacks\\test\\shaders\\final.fsh".into(); + + let mut source_mapper = SourceMapper::new(0); + source_mapper.get_num(server.graph.borrow_mut().add_node(&path)); + + let parser = DiagnosticsParser::new(server.opengl_context.as_ref()); + + let results = + parser.parse_diagnostics_output(output.to_string(), path.parent().unwrap(), &source_mapper, &server.graph.borrow()); + + assert_eq!(results.len(), 1); + let first = results.into_iter().next().unwrap(); + assert_eq!(first.0, Url::from_file_path(path).unwrap()); + server.endpoint.request_shutdown(); + }); + } + + #[test] + #[logging_macro::log_scope] + fn test_amd_diagnostics() { + slog_scope::scope(&slog_scope::logger().new(slog_o!("driver" => "amd")), || { + let mut mockgl = MockShaderValidator::new(); + mockgl.expect_vendor().returning(|| "ATI Technologies".into()); + let server = new_temp_server(Some(Box::new(mockgl))); + + let output = "ERROR: 0:1: '' : syntax error: #line +ERROR: 0:10: '' : syntax error: #line +ERROR: 0:15: 'varying' : syntax error: syntax error +"; + + #[cfg(target_family = "unix")] + let path: PathBuf = "/home/noah/.minecraft/shaderpacks/test/shaders/final.fsh".into(); + #[cfg(target_family = "windows")] + let path: PathBuf = "c:\\home\\noah\\.minecraft\\shaderpacks\\test\\shaders\\final.fsh".into(); + + let mut source_mapper = SourceMapper::new(0); + source_mapper.get_num(server.graph.borrow_mut().add_node(&path)); + + let parser = DiagnosticsParser::new(server.opengl_context.as_ref()); + + let results = + parser.parse_diagnostics_output(output.to_string(), path.parent().unwrap(), &source_mapper, &server.graph.borrow()); + + assert_eq!(results.len(), 1); + let first = results.into_iter().next().unwrap(); + assert_eq!(first.1.len(), 3); + server.endpoint.request_shutdown(); + }); + } +} diff --git a/server/src/graph.rs b/server/main/src/graph.rs similarity index 99% rename from server/src/graph.rs rename to server/main/src/graph.rs index 81f07c1..3891392 100644 --- a/server/src/graph.rs +++ b/server/main/src/graph.rs @@ -170,6 +170,7 @@ mod graph_test { use crate::{graph::CachedStableGraph, IncludePosition}; #[test] + #[logging_macro::log_scope] fn test_graph_two_connected_nodes() { let mut graph = CachedStableGraph::new(); @@ -211,6 +212,7 @@ mod graph_test { } #[test] + #[logging_macro::log_scope] fn test_collect_root_ancestors() { { let mut graph = CachedStableGraph::new(); diff --git a/server/src/lsp_ext.rs b/server/main/src/lsp_ext.rs similarity index 100% rename from server/src/lsp_ext.rs rename to server/main/src/lsp_ext.rs diff --git a/server/src/main.rs b/server/main/src/main.rs similarity index 93% rename from server/src/main.rs rename to server/main/src/main.rs index 7dcf249..ef0b0eb 100644 --- a/server/src/main.rs +++ b/server/main/src/main.rs @@ -1,3 +1,5 @@ +#![feature(once_cell)] + use merge_views::FilialTuple; use rust_lsp::jsonrpc::{method_types::*, *}; use rust_lsp::lsp::*; @@ -45,11 +47,11 @@ mod consts; mod dfs; mod diagnostics_parser; mod graph; -mod logging; mod lsp_ext; mod merge_views; mod navigation; mod opengl; +mod source_mapper; mod url_norm; #[cfg(test)] @@ -317,9 +319,11 @@ impl MinecraftShaderLanguageServer { all_sources.extend(self.load_sources(&tree)?); + let mut source_mapper = source_mapper::SourceMapper::new(all_sources.len()); + let view = { let graph = self.graph.borrow(); - merge_views::generate_merge_list(&tree, &all_sources, &graph) + merge_views::generate_merge_list(&tree, &all_sources, &graph, &mut source_mapper) }; let root_path = self.graph.borrow().get_node(root); @@ -347,18 +351,17 @@ impl MinecraftShaderLanguageServer { return Ok(diagnostics); }; - let stdout = match self.opengl_context.clone().validate(tree_type, view) { + let stdout = match self.compile_shader_source(&view, tree_type, &root_path) { Some(s) => s, None => { back_fill(&all_sources, &mut diagnostics); return Ok(diagnostics); } }; - diagnostics.extend(diagnostics_parser::parse_diagnostics_output( - stdout, - uri, - self.opengl_context.as_ref(), - )); + + let diagnostics_parser = diagnostics_parser::DiagnosticsParser::new(self.opengl_context.as_ref()); + + diagnostics.extend(diagnostics_parser.parse_diagnostics_output(stdout, uri, &source_mapper, &self.graph.borrow())); } else { let mut all_trees: Vec<(TreeType, Vec<(NodeIndex, Option<_>)>)> = Vec::new(); @@ -399,20 +402,22 @@ impl MinecraftShaderLanguageServer { } for tree in all_trees { + // bit over-zealous in allocation but better than having to resize + let mut source_mapper = source_mapper::SourceMapper::new(all_sources.len()); let view = { let graph = self.graph.borrow(); - merge_views::generate_merge_list(&tree.1, &all_sources, &graph) + merge_views::generate_merge_list(&tree.1, &all_sources, &graph, &mut source_mapper) }; - let stdout = match self.opengl_context.clone().validate(tree.0, view) { + let root_path = self.graph.borrow().get_node(tree.1[0].0); + let stdout = match self.compile_shader_source(&view, tree.0, &root_path) { Some(s) => s, None => continue, }; - diagnostics.extend(diagnostics_parser::parse_diagnostics_output( - stdout, - uri, - self.opengl_context.as_ref(), - )); + + let diagnostics_parser = diagnostics_parser::DiagnosticsParser::new(self.opengl_context.as_ref()); + + diagnostics.extend(diagnostics_parser.parse_diagnostics_output(stdout, uri, &source_mapper, &self.graph.borrow())); } }; @@ -420,6 +425,17 @@ impl MinecraftShaderLanguageServer { Ok(diagnostics) } + fn compile_shader_source(&self, source: &str, tree_type: TreeType, path: &Path) -> Option { + let result = self.opengl_context.clone().validate(tree_type, source); + match &result { + Some(output) => { + info!("compilation errors reported"; "errors" => format!("`{}`", output.replace('\n', "\\n")), "tree_root" => path.to_str().unwrap()) + } + None => info!("compilation reported no errors"; "tree_root" => path.to_str().unwrap()), + }; + result + } + pub fn get_dfs_for_node(&self, root: NodeIndex) -> Result, dfs::error::CycleError> { let graph_ref = self.graph.borrow(); @@ -674,22 +690,22 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer { fn goto_definition(&mut self, params: TextDocumentPositionParams, completable: LSCompletable>) { logging::slog_with_trace_id(|| { let parser = &mut self.tree_sitter.borrow_mut(); - let parser_ctx = match navigation::ParserContext::new(parser, params.text_document.uri.clone()) { + let parser_ctx = match navigation::ParserContext::new(parser, ¶ms.text_document.uri) { Ok(ctx) => ctx, Err(e) => { return completable.complete(Err(MethodError { code: 42069, - message: format!("error building parser context: {}", e), + message: format!("error building parser context: {}", e.context(params.text_document.uri)), data: (), })) } }; - match parser_ctx.find_definitions(params.text_document.uri, params.position) { + match parser_ctx.find_definitions(¶ms.text_document.uri, params.position) { Ok(locations) => completable.complete(Ok(locations)), Err(e) => completable.complete(Err(MethodError { code: 42069, - message: format!("error finding definitions: {}", e), + message: format!("error finding definitions: {}", e.context(params.text_document.uri)), data: (), })), } diff --git a/server/src/merge_views.rs b/server/main/src/merge_views.rs similarity index 81% rename from server/src/merge_views.rs rename to server/main/src/merge_views.rs index e1f6f4a..8ddc73f 100644 --- a/server/src/merge_views.rs +++ b/server/main/src/merge_views.rs @@ -10,13 +10,16 @@ use core::slice::Iter; use petgraph::stable_graph::NodeIndex; use crate::graph::CachedStableGraph; +use crate::source_mapper::SourceMapper; /// FilialTuple represents a tuple with a child at index 0 /// and a parent at index 1. Parent can be nullable in the case of /// the child being a top level node in the tree. pub type FilialTuple = (NodeIndex, Option); -pub fn generate_merge_list<'a>(nodes: &'a [FilialTuple], sources: &'a HashMap, graph: &'a CachedStableGraph) -> String { +pub fn generate_merge_list<'a>( + nodes: &'a [FilialTuple], sources: &'a HashMap, graph: &'a CachedStableGraph, source_mapper: &mut SourceMapper, +) -> String { // contains additionally inserted lines such as #line and other directives, preamble defines etc let mut extra_lines: Vec = Vec::new(); extra_lines.reserve((nodes.len() * 2) + 2); @@ -36,18 +39,24 @@ pub fn generate_merge_list<'a>(nodes: &'a [FilialTuple], sources: &'a HashMap::new(); @@ -60,6 +69,7 @@ pub fn generate_merge_list<'a>(nodes: &'a [FilialTuple], sources: &'a HashMap(nodes: &'a [FilialTuple], sources: &'a HashMap( nodes: &mut Peekable>, merge_list: &mut LinkedList<&'a str>, last_offset_set: &mut HashMap, graph: &'a CachedStableGraph, sources: &'a HashMap, extra_lines: &mut Vec, stack: &mut VecDeque, + source_mapper: &mut SourceMapper, ) { loop { let n = match nodes.next() { @@ -100,7 +111,7 @@ fn create_merge_views<'a>( .insert((parent, stack.back().copied()), char_following_line) .get_or_insert(0); merge_list.push_back(&parent_source[offset..char_for_line]); - add_opening_line_directive(&child_path, merge_list, extra_lines); + add_opening_line_directive(&child_path, child, merge_list, extra_lines, source_mapper); match nodes.peek() { Some(next) => { @@ -118,7 +129,7 @@ fn create_merge_views<'a>( merge_list.push_back(&child_source[..offset]); last_offset_set.insert((child, Some(parent)), 0); // +2 because edge.line is 0 indexed but #line is 1 indexed and references the *following* line - add_closing_line_directive(edge.line + 2, &parent_path, merge_list, extra_lines); + add_closing_line_directive(edge.line + 2, &parent_path, parent, merge_list, extra_lines, source_mapper); // if the next pair's parent is not the current pair's parent, we need to bubble up if stack.contains(&next.1.unwrap()) { return; @@ -127,7 +138,16 @@ fn create_merge_views<'a>( } stack.push_back(parent); - create_merge_views(nodes, merge_list, last_offset_set, graph, sources, extra_lines, stack); + create_merge_views( + nodes, + merge_list, + last_offset_set, + graph, + sources, + extra_lines, + stack, + source_mapper, + ); stack.pop_back(); let offset = *last_offset_set.get(&(child, Some(parent))).unwrap(); @@ -144,7 +164,7 @@ fn create_merge_views<'a>( } // +2 because edge.line is 0 indexed but #line is 1 indexed and references the *following* line - add_closing_line_directive(edge.line + 2, &parent_path, merge_list, extra_lines); + add_closing_line_directive(edge.line + 2, &parent_path, parent, merge_list, extra_lines, source_mapper); // we need to check the next item at the point of original return further down the callstack if nodes.peek().is_some() && stack.contains(&nodes.peek().unwrap().1.unwrap()) { @@ -161,7 +181,7 @@ fn create_merge_views<'a>( merge_list.push_back(&child_source[..offset]); last_offset_set.insert((child, Some(parent)), 0); // +2 because edge.line is 0 indexed but #line is 1 indexed and references the *following* line - add_closing_line_directive(edge.line + 2, &parent_path, merge_list, extra_lines); + add_closing_line_directive(edge.line + 2, &parent_path, parent, merge_list, extra_lines, source_mapper); } } } @@ -191,38 +211,63 @@ fn find_version_offset(source: &str) -> usize { .map_or(0, |(i, _)| i) } -fn add_preamble<'a>( - version_line_offset: usize, version_char_offset: usize, path: &str, source: &'a str, merge_list: &mut LinkedList<&'a str>, - extra_lines: &mut Vec, -) { - // TODO: Optifine #define preabmle - merge_list.push_back(&source[..version_char_offset]); - let google_line_directive = format!( - "#extension GL_GOOGLE_cpp_style_line_directive : enable\n#line {} \"{}\"\n", - // +2 because 0 indexed but #line is 1 indexed and references the *following* line - version_line_offset + 2, - path, - ); - extra_lines.push(google_line_directive); - unsafe_get_and_insert(merge_list, extra_lines); -} +// fn add_preamble<'a>( +// version_line_offset: usize, version_char_offset: usize, path: &Path, node: NodeIndex, source: &'a str, +// merge_list: &mut LinkedList<&'a str>, extra_lines: &mut Vec, source_mapper: &mut SourceMapper, +// ) { +// // TODO: Optifine #define preabmle +// merge_list.push_back(&source[..version_char_offset]); +// let google_line_directive = format!( +// "#extension GL_GOOGLE_cpp_style_line_directive : enable\n#line {} {} // {}\n", +// // +2 because 0 indexed but #line is 1 indexed and references the *following* line +// version_line_offset + 2, +// source_mapper.get_num(node), +// path.to_str().unwrap().replace('\\', "\\\\"), +// ); +// extra_lines.push(google_line_directive); +// unsafe_get_and_insert(merge_list, extra_lines); +// } -fn add_opening_line_directive(path: &Path, merge_list: &mut LinkedList<&str>, extra_lines: &mut Vec) { - let line_directive = format!("#line 1 \"{}\"\n", path.to_str().unwrap().replace('\\', "\\\\")); +fn add_opening_line_directive( + path: &Path, node: NodeIndex, merge_list: &mut LinkedList<&str>, extra_lines: &mut Vec, source_mapper: &mut SourceMapper, +) { + let line_directive = format!( + "#line 1 {} // {}\n", + source_mapper.get_num(node), + path.to_str().unwrap().replace('\\', "\\\\") + ); extra_lines.push(line_directive); unsafe_get_and_insert(merge_list, extra_lines); } -fn add_closing_line_directive(line: usize, path: &Path, merge_list: &mut LinkedList<&str>, extra_lines: &mut Vec) { +fn add_closing_line_directive( + line: usize, path: &Path, node: NodeIndex, merge_list: &mut LinkedList<&str>, extra_lines: &mut Vec, + source_mapper: &mut SourceMapper, +) { // Optifine doesn't seem to add a leading newline if the previous line was a #line directive let line_directive = if let Some(l) = merge_list.back() { if l.trim().starts_with("#line") { - format!("#line {} \"{}\"\n", line, path.to_str().unwrap().replace('\\', "\\\\")) + format!( + "#line {} {} // {}\n", + line, + source_mapper.get_num(node), + path.to_str().unwrap().replace('\\', "\\\\") + ) } else { - format!("\n#line {} \"{}\"\n", line, path.to_str().unwrap().replace('\\', "\\\\")) + format!( + "\n#line {} {} // {}\n", + line, + source_mapper.get_num(node), + path.to_str().unwrap().replace('\\', "\\\\") + ) } } else { - format!("\n#line {} \"{}\"\n", line, path.to_str().unwrap().replace('\\', "\\\\")) + format!( + "\n#line {} {} // {}\n", + line, + source_mapper.get_num(node), + path.to_str().unwrap().replace('\\', "\\\\") + ) }; extra_lines.push(line_directive); @@ -243,10 +288,12 @@ mod merge_view_test { use std::path::PathBuf; use crate::merge_views::generate_merge_list; + use crate::source_mapper::SourceMapper; use crate::test::{copy_to_and_set_root, new_temp_server}; use crate::IncludePosition; #[test] + #[logging_macro::log_scope] fn test_generate_merge_list_01() { let mut server = new_temp_server(None); @@ -273,16 +320,17 @@ mod merge_view_test { let sources = server.load_sources(&nodes).unwrap(); let graph_borrow = server.graph.borrow(); - let result = generate_merge_list(&nodes, &sources, &graph_borrow); + let mut source_mapper = SourceMapper::new(0); + let result = generate_merge_list(&nodes, &sources, &graph_borrow, &mut source_mapper); let merge_file = tmp_path.join("shaders").join("final.fsh.merge"); let mut truth = fs::read_to_string(merge_file).unwrap(); - truth = truth.replacen( - "!!", - &tmp_path.join("shaders").join("final.fsh").to_str().unwrap().replace('\\', "\\\\"), - 1, - ); + // truth = truth.replacen( + // "!!", + // &tmp_path.join("shaders").join("final.fsh").to_str().unwrap().replace('\\', "\\\\"), + // 1, + // ); truth = truth.replacen( "!!", &tmp_path.join("shaders").join("common.glsl").to_str().unwrap().replace('\\', "\\\\"), @@ -297,6 +345,7 @@ mod merge_view_test { } #[test] + #[logging_macro::log_scope] fn test_generate_merge_list_02() { let mut server = new_temp_server(None); @@ -341,17 +390,18 @@ mod merge_view_test { let sources = server.load_sources(&nodes).unwrap(); let graph_borrow = server.graph.borrow(); - let result = generate_merge_list(&nodes, &sources, &graph_borrow); + let mut source_mapper = SourceMapper::new(0); + let result = generate_merge_list(&nodes, &sources, &graph_borrow, &mut source_mapper); let merge_file = tmp_path.join("shaders").join("final.fsh.merge"); let mut truth = fs::read_to_string(merge_file).unwrap(); - truth = truth.replacen( - "!!", - &tmp_path.join("shaders").join("final.fsh").to_str().unwrap().replace('\\', "\\\\"), - 1, - ); + // truth = truth.replacen( + // "!!", + // &tmp_path.join("shaders").join("final.fsh").to_str().unwrap().replace('\\', "\\\\"), + // 1, + // ); for file in &["sample.glsl", "burger.glsl", "sample.glsl", "test.glsl", "sample.glsl"] { let path = tmp_path.clone(); @@ -377,6 +427,7 @@ mod merge_view_test { } #[test] + #[logging_macro::log_scope] fn test_generate_merge_list_03() { let mut server = new_temp_server(None); @@ -421,17 +472,18 @@ mod merge_view_test { let sources = server.load_sources(&nodes).unwrap(); let graph_borrow = server.graph.borrow(); - let result = generate_merge_list(&nodes, &sources, &graph_borrow); + let mut source_mapper = SourceMapper::new(0); + let result = generate_merge_list(&nodes, &sources, &graph_borrow, &mut source_mapper); let merge_file = tmp_path.join("shaders").join("final.fsh.merge"); let mut truth = fs::read_to_string(merge_file).unwrap(); - truth = truth.replacen( - "!!", - &tmp_path.join("shaders").join("final.fsh").to_str().unwrap().replace('\\', "\\\\"), - 1, - ); + // truth = truth.replacen( + // "!!", + // &tmp_path.join("shaders").join("final.fsh").to_str().unwrap().replace('\\', "\\\\"), + // 1, + // ); for file in &["sample.glsl", "burger.glsl", "sample.glsl", "test.glsl", "sample.glsl"] { let path = tmp_path.clone(); @@ -457,6 +509,7 @@ mod merge_view_test { } #[test] + #[logging_macro::log_scope] fn test_generate_merge_list_04() { let mut server = new_temp_server(None); @@ -510,14 +563,15 @@ mod merge_view_test { let sources = server.load_sources(&nodes).unwrap(); let graph_borrow = server.graph.borrow(); - let result = generate_merge_list(&nodes, &sources, &graph_borrow); + let mut source_mapper = SourceMapper::new(0); + let result = generate_merge_list(&nodes, &sources, &graph_borrow, &mut source_mapper); let merge_file = tmp_path.join("shaders").join("final.fsh.merge"); let mut truth = fs::read_to_string(merge_file).unwrap(); for file in &[ - PathBuf::new().join("final.fsh").to_str().unwrap(), + // PathBuf::new().join("final.fsh").to_str().unwrap(), PathBuf::new().join("utils").join("utilities.glsl").to_str().unwrap(), PathBuf::new().join("utils").join("stuff1.glsl").to_str().unwrap(), PathBuf::new().join("utils").join("utilities.glsl").to_str().unwrap(), @@ -528,7 +582,6 @@ mod merge_view_test { PathBuf::new().join("final.fsh").to_str().unwrap(), ] { let path = tmp_path.clone(); - //path.f truth = truth.replacen("!!", &path.join("shaders").join(file).to_str().unwrap().replace('\\', "\\\\"), 1); } diff --git a/server/src/navigation.rs b/server/main/src/navigation.rs similarity index 94% rename from server/src/navigation.rs rename to server/main/src/navigation.rs index e5bc52c..cb90928 100644 --- a/server/src/navigation.rs +++ b/server/main/src/navigation.rs @@ -24,7 +24,7 @@ pub struct ParserContext<'a> { } impl<'a> ParserContext<'a> { - pub fn new(parser: &'a mut Parser, document_uri: Url) -> Result { + pub fn new(parser: &'a mut Parser, document_uri: &Url) -> Result { let source = read_to_string(document_uri.path())?; let tree = parser.parse(&source, None).unwrap(); @@ -32,7 +32,7 @@ impl<'a> ParserContext<'a> { Ok(ParserContext { source, tree, parser }) } - pub fn find_definitions(&self, document_uri: Url, point: Position) -> Result> { + pub fn find_definitions(&self, document_uri: &Url, point: Position) -> Result> { let current_node = match self.find_node_at_point(point) { Some(node) => node, None => return Ok(vec![]), diff --git a/server/src/opengl.rs b/server/main/src/opengl.rs similarity index 88% rename from server/src/opengl.rs rename to server/main/src/opengl.rs index 73099ae..9954e44 100644 --- a/server/src/opengl.rs +++ b/server/main/src/opengl.rs @@ -8,7 +8,7 @@ use mockall::automock; #[cfg_attr(test, automock)] pub trait ShaderValidator { - fn validate(&self, tree_type: super::TreeType, source: String) -> Option; + fn validate(&self, tree_type: super::TreeType, source: &str) -> Option; fn vendor(&self) -> String; } @@ -42,7 +42,7 @@ impl OpenGlContext { gl_ctx } - unsafe fn compile_and_get_shader_log(&self, shader: gl::types::GLuint, source: String) -> Option { + unsafe fn compile_and_get_shader_log(&self, shader: gl::types::GLuint, source: &str) -> Option { let mut success = i32::from(gl::FALSE); let c_str_frag = CString::new(source).unwrap(); gl::ShaderSource(shader, 1, &c_str_frag.as_ptr(), ptr::null()); @@ -71,8 +71,8 @@ impl OpenGlContext { } impl ShaderValidator for OpenGlContext { - fn validate(&self, tree_type: super::TreeType, source: String) -> Option { - let result = unsafe { + fn validate(&self, tree_type: super::TreeType, source: &str) -> Option { + unsafe { match tree_type { crate::TreeType::Fragment => { // Fragment shader @@ -95,14 +95,7 @@ impl ShaderValidator for OpenGlContext { self.compile_and_get_shader_log(compute_shader, source) } } - }; - - match &result { - Some(output) => info!("compilation errors reported"; "errors" => format!("`{}`", output.replace('\n', "\\n"))), - None => info!("compilation reported no errors"), } - - result } fn vendor(&self) -> String { diff --git a/server/main/src/source_mapper.rs b/server/main/src/source_mapper.rs new file mode 100644 index 0000000..efcad0d --- /dev/null +++ b/server/main/src/source_mapper.rs @@ -0,0 +1,52 @@ +use std::{collections::HashMap, fmt::Display}; + +use petgraph::graph::NodeIndex; + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct SourceNum(usize); + +impl Display for SourceNum { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(format!("{}", self.0).as_str()) + } +} + +impl From for SourceNum { + fn from(val: usize) -> Self { + SourceNum(val) + } +} + +// Maps from a graph node index to a virtual OpenGL +// source number (for when building the merged source view), +// and in reverse (for when mapping from GLSL error source numbers to their source path). +// What is a source number: https://community.khronos.org/t/what-is-source-string-number/70976 +pub struct SourceMapper { + next: SourceNum, + mapping: HashMap, + reverse_mapping: Vec, +} + +impl SourceMapper { + pub fn new(capacity: usize) -> Self { + SourceMapper { + next: SourceNum(0), + mapping: HashMap::with_capacity(capacity), + reverse_mapping: Vec::with_capacity(capacity), + } + } + + pub fn get_num(&mut self, node: NodeIndex) -> SourceNum { + let num = &*self.mapping.entry(node).or_insert_with(|| { + let next = self.next; + self.next.0 += 1; + self.reverse_mapping.push(node); + next + }); + *num + } + + pub fn get_node(&self, num: SourceNum) -> NodeIndex { + self.reverse_mapping[num.0] + } +} diff --git a/server/src/test.rs b/server/main/src/test.rs similarity index 98% rename from server/src/test.rs rename to server/main/src/test.rs index 9a77810..afb4761 100644 --- a/server/src/test.rs +++ b/server/main/src/test.rs @@ -5,8 +5,6 @@ use std::io::Result; use pretty_assertions::assert_eq; -use slog::o; -use slog::Logger; use tempdir::TempDir; use fs_extra::{copy_items, dir}; @@ -37,8 +35,6 @@ pub fn new_temp_server(opengl_context: Option>) let endpoint = LSPEndpoint::create_lsp_output_with_output_stream(|| StdoutNewline { s: Box::new(io::sink()) }); let context = opengl_context.unwrap_or_else(|| Box::new(opengl::MockShaderValidator::new())); - let logger = Logger::root(slog::Discard, o!()); - let guard = slog_scope::set_global_logger(logger); MinecraftShaderLanguageServer { endpoint, @@ -46,7 +42,7 @@ pub fn new_temp_server(opengl_context: Option>) root: "".into(), command_provider: None, opengl_context: context.into(), - log_guard: Some(guard), + log_guard: None, tree_sitter: Rc::new(RefCell::new(Parser::new())), } } @@ -82,6 +78,7 @@ fn copy_to_tmp_dir(test_path: &str) -> (Rc, PathBuf) { #[allow(deprecated)] #[test] +#[logging_macro::log_scope] fn test_empty_initialize() { let mut server = new_temp_server(None); @@ -130,6 +127,7 @@ fn test_empty_initialize() { #[allow(deprecated)] #[test] +#[logging_macro::log_scope] fn test_01_initialize() { let mut server = new_temp_server(None); @@ -189,7 +187,9 @@ fn test_01_initialize() { assert_eq!(server.graph.borrow().graph.edge_weight(edge).unwrap().line, 2); } +#[allow(deprecated)] #[test] +#[logging_macro::log_scope] fn test_05_initialize() { let mut server = new_temp_server(None); diff --git a/server/src/url_norm.rs b/server/main/src/url_norm.rs similarity index 100% rename from server/src/url_norm.rs rename to server/main/src/url_norm.rs diff --git a/server/testdata/01/common.glsl b/server/main/testdata/01/common.glsl similarity index 100% rename from server/testdata/01/common.glsl rename to server/main/testdata/01/common.glsl diff --git a/server/testdata/01/final.fsh b/server/main/testdata/01/final.fsh similarity index 100% rename from server/testdata/01/final.fsh rename to server/main/testdata/01/final.fsh diff --git a/server/main/testdata/01/final.fsh.merge b/server/main/testdata/01/final.fsh.merge new file mode 100644 index 0000000..7c606b6 --- /dev/null +++ b/server/main/testdata/01/final.fsh.merge @@ -0,0 +1,11 @@ +#version 120 + +#line 1 1 // !! +float test() { + return 0.5; +} +#line 4 0 // !! + +void main() { + gl_FragColor[0] = vec4(0.0); +} \ No newline at end of file diff --git a/server/testdata/02/final.fsh b/server/main/testdata/02/final.fsh similarity index 100% rename from server/testdata/02/final.fsh rename to server/main/testdata/02/final.fsh diff --git a/server/testdata/02/final.fsh.merge b/server/main/testdata/02/final.fsh.merge similarity index 57% rename from server/testdata/02/final.fsh.merge rename to server/main/testdata/02/final.fsh.merge index 78c9367..6e6d776 100644 --- a/server/testdata/02/final.fsh.merge +++ b/server/main/testdata/02/final.fsh.merge @@ -1,28 +1,26 @@ #version 120 -#extension GL_GOOGLE_cpp_style_line_directive : enable -#line 2 "!!" -#line 1 "!!" +#line 1 1 // !! int sample() { return 5; } -#line 1 "!!" +#line 1 2 // !! void burger() { // sample text } -#line 6 "!!" +#line 6 1 // !! -#line 1 "!!" +#line 1 3 // !! float test() { return 3.0; } -#line 8 "!!" +#line 8 1 // !! int sample_more() { return 5; } -#line 4 "!!" +#line 4 0 // !! void main() { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); diff --git a/server/testdata/02/utils/burger.glsl b/server/main/testdata/02/utils/burger.glsl similarity index 100% rename from server/testdata/02/utils/burger.glsl rename to server/main/testdata/02/utils/burger.glsl diff --git a/server/testdata/02/utils/sample.glsl b/server/main/testdata/02/utils/sample.glsl similarity index 100% rename from server/testdata/02/utils/sample.glsl rename to server/main/testdata/02/utils/sample.glsl diff --git a/server/testdata/02/utils/test.glsl b/server/main/testdata/02/utils/test.glsl similarity index 100% rename from server/testdata/02/utils/test.glsl rename to server/main/testdata/02/utils/test.glsl diff --git a/server/testdata/03/final.fsh b/server/main/testdata/03/final.fsh similarity index 100% rename from server/testdata/03/final.fsh rename to server/main/testdata/03/final.fsh diff --git a/server/testdata/03/final.fsh.merge b/server/main/testdata/03/final.fsh.merge similarity index 53% rename from server/testdata/03/final.fsh.merge rename to server/main/testdata/03/final.fsh.merge index a328117..f317989 100644 --- a/server/testdata/03/final.fsh.merge +++ b/server/main/testdata/03/final.fsh.merge @@ -1,24 +1,22 @@ #version 120 -#extension GL_GOOGLE_cpp_style_line_directive : enable -#line 2 "!!" -#line 1 "!!" +#line 1 1 // !! int sample() { return 5; } -#line 1 "!!" +#line 1 2 // !! void burger() { // sample text } -#line 6 "!!" +#line 6 1 // !! -#line 1 "!!" +#line 1 3 // !! float test() { return 3.0; } -#line 8 "!!" -#line 4 "!!" +#line 8 1 // !! +#line 4 0 // !! void main() { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); diff --git a/server/testdata/03/utils/burger.glsl b/server/main/testdata/03/utils/burger.glsl similarity index 100% rename from server/testdata/03/utils/burger.glsl rename to server/main/testdata/03/utils/burger.glsl diff --git a/server/testdata/03/utils/sample.glsl b/server/main/testdata/03/utils/sample.glsl similarity index 100% rename from server/testdata/03/utils/sample.glsl rename to server/main/testdata/03/utils/sample.glsl diff --git a/server/testdata/03/utils/test.glsl b/server/main/testdata/03/utils/test.glsl similarity index 100% rename from server/testdata/03/utils/test.glsl rename to server/main/testdata/03/utils/test.glsl diff --git a/server/testdata/04/final.fsh b/server/main/testdata/04/final.fsh similarity index 100% rename from server/testdata/04/final.fsh rename to server/main/testdata/04/final.fsh diff --git a/server/main/testdata/04/final.fsh.merge b/server/main/testdata/04/final.fsh.merge new file mode 100644 index 0000000..49da4ac --- /dev/null +++ b/server/main/testdata/04/final.fsh.merge @@ -0,0 +1,23 @@ +#version 120 + +#line 1 1 // !! +#line 1 2 // !! +void stuff1() { + +} +#line 2 1 // !! +#line 1 3 // !! +void stuff2() { + +} +#line 3 1 // !! +#line 4 0 // !! +#line 1 4 // !! +void matrix() { + +} +#line 5 0 // !! + +void main() { + +} \ No newline at end of file diff --git a/server/testdata/04/lib/matrices.glsl b/server/main/testdata/04/lib/matrices.glsl similarity index 100% rename from server/testdata/04/lib/matrices.glsl rename to server/main/testdata/04/lib/matrices.glsl diff --git a/server/testdata/04/utils/stuff1.glsl b/server/main/testdata/04/utils/stuff1.glsl similarity index 100% rename from server/testdata/04/utils/stuff1.glsl rename to server/main/testdata/04/utils/stuff1.glsl diff --git a/server/testdata/04/utils/stuff2.glsl b/server/main/testdata/04/utils/stuff2.glsl similarity index 100% rename from server/testdata/04/utils/stuff2.glsl rename to server/main/testdata/04/utils/stuff2.glsl diff --git a/server/testdata/04/utils/utilities.glsl b/server/main/testdata/04/utils/utilities.glsl similarity index 100% rename from server/testdata/04/utils/utilities.glsl rename to server/main/testdata/04/utils/utilities.glsl diff --git a/server/testdata/05/common.glsl b/server/main/testdata/05/common.glsl similarity index 100% rename from server/testdata/05/common.glsl rename to server/main/testdata/05/common.glsl diff --git a/server/testdata/05/final.fsh b/server/main/testdata/05/final.fsh similarity index 100% rename from server/testdata/05/final.fsh rename to server/main/testdata/05/final.fsh diff --git a/server/testdata/05/final.fsh.merge b/server/main/testdata/05/final.fsh.merge similarity index 100% rename from server/testdata/05/final.fsh.merge rename to server/main/testdata/05/final.fsh.merge diff --git a/server/testdata/05/test/banana.glsl b/server/main/testdata/05/test/banana.glsl similarity index 100% rename from server/testdata/05/test/banana.glsl rename to server/main/testdata/05/test/banana.glsl diff --git a/server/testdata/05/test/burger.glsl b/server/main/testdata/05/test/burger.glsl similarity index 100% rename from server/testdata/05/test/burger.glsl rename to server/main/testdata/05/test/burger.glsl diff --git a/server/src/diagnostics_parser.rs b/server/src/diagnostics_parser.rs deleted file mode 100644 index b473896..0000000 --- a/server/src/diagnostics_parser.rs +++ /dev/null @@ -1,162 +0,0 @@ -use std::{collections::HashMap, path::Path}; - -use once_cell::sync::OnceCell; - -use regex::Regex; -use rust_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range}; -use url::Url; - -use crate::{consts, opengl}; - -static RE_DIAGNOSTIC: OnceCell = OnceCell::new(); -fn diagnostics_regex(vendor: &T) -> &'static Regex -where - T: opengl::ShaderValidator + ?Sized, -{ - RE_DIAGNOSTIC.get_or_init(|| match vendor.vendor().as_str() { - "NVIDIA Corporation" => { - Regex::new(r#"^(?P[^?<>*|"]+)\((?P\d+)\) : (?Perror|warning) [A-C]\d+: (?P.+)"#).unwrap() - } - _ => { - Regex::new(r#"^(?PERROR|WARNING): (?P[^?<>*|"\n]+):(?P\d+): '[a-z]*' : (?P.+)$"#).unwrap() - } - }) -} - -static LINE_NUM_OFFSET: OnceCell = OnceCell::new(); -fn line_number_offset(vendor: &T) -> &'static u32 -where - T: opengl::ShaderValidator + ?Sized, -{ - LINE_NUM_OFFSET.get_or_init(|| match vendor.vendor().as_str() { - "ATI Technologies" => 0, - _ => 2, - }) -} - -pub fn parse_diagnostics_output(output: String, uri: &Path, vendor_querier: &T) -> HashMap> -where - T: opengl::ShaderValidator + ?Sized, -{ - let output_lines = output.split('\n'); - let mut diagnostics: HashMap> = HashMap::with_capacity(output_lines.count()); - let output_lines = output.split('\n'); - - for line in output_lines { - let diagnostic_capture = match diagnostics_regex(vendor_querier).captures(line) { - Some(d) => d, - None => continue, - }; - - // info!("match {:?}", diagnostic_capture); - - let msg = diagnostic_capture.name("output").unwrap().as_str(); - - let line = match diagnostic_capture.name("linenum") { - Some(c) => c.as_str().parse::().unwrap_or(0), - None => 0, - } - line_number_offset(vendor_querier); - - // TODO: line matching maybe - /* let line_text = source_lines[line as usize]; - let leading_whitespace = line_text.len() - line_text.trim_start().len(); */ - - let severity = match diagnostic_capture.name("severity") { - Some(c) => match c.as_str().to_lowercase().as_str() { - "error" => DiagnosticSeverity::Error, - "warning" => DiagnosticSeverity::Warning, - _ => DiagnosticSeverity::Information, - }, - _ => DiagnosticSeverity::Information, - }; - - let origin = match diagnostic_capture.name("filepath") { - Some(o) => { - if o.as_str() == "0" { - uri.to_str().unwrap().to_string() - } else { - o.as_str().to_string() - } - } - None => uri.to_str().unwrap().to_string(), - }; - - let diagnostic = Diagnostic { - range: Range::new( - /* Position::new(line, leading_whitespace as u64), - Position::new(line, line_text.len() as u64) */ - Position::new(line, 0), - Position::new(line, 1000), - ), - code: None, - severity: Some(severity), - source: Some(consts::SOURCE.into()), - message: msg.trim().into(), - related_information: None, - tags: None, - code_description: Option::None, - data: Option::None, - }; - - let origin_url = Url::from_file_path(origin).unwrap(); - match diagnostics.get_mut(&origin_url) { - Some(d) => d.push(diagnostic), - None => { - diagnostics.insert(origin_url, vec![diagnostic]); - } - }; - } - diagnostics -} - -#[cfg(test)] -mod diagnostics_test { - use std::{path::PathBuf, str::FromStr}; - - use crate::{diagnostics_parser::parse_diagnostics_output, opengl::MockShaderValidator, test::new_temp_server}; - - #[test] - fn test_nvidia_diagnostics() { - let mut mockgl = MockShaderValidator::new(); - mockgl.expect_vendor().returning(|| "NVIDIA Corporation".into()); - let server = new_temp_server(Some(Box::new(mockgl))); - - let output = "/home/noah/.minecraft/shaderpacks/test/shaders/final.fsh(9) : error C0000: syntax error, unexpected '}', expecting ',' or ';' at token \"}\""; - - let results = parse_diagnostics_output( - output.to_string(), - &PathBuf::from_str("/home/noah/.minecraft/shaderpacks/test").unwrap(), - server.opengl_context.as_ref(), - ); - - assert_eq!(results.len(), 1); - let first = results.into_iter().next().unwrap(); - assert_eq!( - first.0, - url::Url::from_file_path("/home/noah/.minecraft/shaderpacks/test/shaders/final.fsh").unwrap() - ); - server.endpoint.request_shutdown(); - } - - #[test] - fn test_amd_diagnostics() { - let mut mockgl = MockShaderValidator::new(); - mockgl.expect_vendor().returning(|| "ATI Technologies".into()); - let server = new_temp_server(Some(Box::new(mockgl))); - - let output = "ERROR: 0:1: '' : syntax error: #line -ERROR: 0:10: '' : syntax error: #line -ERROR: 0:15: 'varying' : syntax error: syntax error -"; - - let results = parse_diagnostics_output( - output.to_string(), - &PathBuf::from_str("/home/test").unwrap(), - server.opengl_context.as_ref(), - ); - assert_eq!(results.len(), 1); - let first = results.into_iter().next().unwrap(); - assert_eq!(first.1.len(), 3); - server.endpoint.request_shutdown(); - } -} diff --git a/server/testdata/01/final.fsh.merge b/server/testdata/01/final.fsh.merge deleted file mode 100644 index f6cdd6e..0000000 --- a/server/testdata/01/final.fsh.merge +++ /dev/null @@ -1,13 +0,0 @@ -#version 120 -#extension GL_GOOGLE_cpp_style_line_directive : enable -#line 2 "!!" - -#line 1 "!!" -float test() { - return 0.5; -} -#line 4 "!!" - -void main() { - gl_FragColor[0] = vec4(0.0); -} \ No newline at end of file diff --git a/server/testdata/04/final.fsh.merge b/server/testdata/04/final.fsh.merge deleted file mode 100644 index 47d97af..0000000 --- a/server/testdata/04/final.fsh.merge +++ /dev/null @@ -1,25 +0,0 @@ -#version 120 -#extension GL_GOOGLE_cpp_style_line_directive : enable -#line 2 "!!" - -#line 1 "!!" -#line 1 "!!" -void stuff1() { - -} -#line 2 "!!" -#line 1 "!!" -void stuff2() { - -} -#line 3 "!!" -#line 4 "!!" -#line 1 "!!" -void matrix() { - -} -#line 5 "!!" - -void main() { - -} \ No newline at end of file