mirror of
https://github.com/Strum355/mcshader-lsp.git
synced 2025-07-24 11:44:44 +00:00
fixed error off-by-one once and for all, and more restructuring+a load more to go until Im happy with it (aka never)
This commit is contained in:
parent
786e09bdcf
commit
e7221304da
29 changed files with 1319 additions and 1128 deletions
|
@ -8,12 +8,12 @@ edition = "2021"
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
glutin = "0.28"
|
||||
glutin = "0.29"
|
||||
gl = "0.14"
|
||||
url = "2.2"
|
||||
filesystem = { path = "../filesystem" }
|
||||
graph = { path = "../graph" }
|
||||
tower-lsp = "0.17.0"
|
||||
tower-lsp = "0.17"
|
||||
regex = "1.4"
|
||||
mockall = "0.11"
|
||||
logging = { path = "../logging" }
|
||||
|
|
|
@ -1,63 +1,64 @@
|
|||
use std::collections::HashMap;
|
||||
use core::cell::OnceCell;
|
||||
use filesystem::NormalizedPathBuf;
|
||||
use logging::debug;
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
use tower_lsp::lsp_types::*;
|
||||
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity};
|
||||
use url::Url;
|
||||
|
||||
use crate::ShaderValidator;
|
||||
use sourcefile::{SourceMapper, SourceNum};
|
||||
use crate::GPUVendor;
|
||||
use sourcefile::{SourceMapper, SourceNum, Sourcefile, Version, ROOT_SOURCE_NUM};
|
||||
|
||||
pub struct DiagnosticsParser<'a, T: ShaderValidator + ?Sized> {
|
||||
// line_offset: OnceCell<u32>,
|
||||
line_regex: OnceCell<Regex>,
|
||||
vendor_querier: &'a T,
|
||||
pub struct DiagnosticsParser {
|
||||
line_regex: Regex,
|
||||
line_offset: u32,
|
||||
}
|
||||
|
||||
impl<'a, T: ShaderValidator + ?Sized> DiagnosticsParser<'a, T> {
|
||||
pub fn new(vendor_querier: &'a T) -> Self {
|
||||
impl DiagnosticsParser {
|
||||
pub fn new(gpu_vendor: GPUVendor, doc_glsl_version: Version) -> Self {
|
||||
DiagnosticsParser {
|
||||
// line_offset: OnceCell::new(),
|
||||
line_regex: OnceCell::new(),
|
||||
vendor_querier,
|
||||
line_regex: DiagnosticsParser::get_line_regex(gpu_vendor),
|
||||
line_offset: DiagnosticsParser::get_line_offset(gpu_vendor, doc_glsl_version),
|
||||
}
|
||||
}
|
||||
|
||||
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<filepath>\d+)\((?P<linenum>\d+)\) : (?P<severity>error|warning) [A-C]\d+: (?P<output>.+)"#).unwrap()
|
||||
fn get_line_regex(gpu_vendor: GPUVendor) -> Regex {
|
||||
match gpu_vendor {
|
||||
GPUVendor::NVIDIA => {
|
||||
Regex::new(r#"^(?P<filepath>\d+)\((?P<linenum>\d+)\) : (?P<severity>error|warning) [A-C]\d+: (?P<output>.+)"#)
|
||||
}
|
||||
_ => Regex::new(
|
||||
r#"^(?P<severity>ERROR|WARNING): (?P<filepath>[^?<>*|"\n]+):(?P<linenum>\d+): (?:'.*' :|[a-z]+\(#\d+\)) +(?P<output>.+)$"#,
|
||||
)
|
||||
.unwrap(),
|
||||
})
|
||||
),
|
||||
}
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
// fn get_line_offset(&self) -> u32 {
|
||||
// *self.line_offset.get_or_init(|| match self.vendor_querier.vendor().as_str() {
|
||||
// "ATI Technologies" | "ATI Technologies Inc." | "AMD" => 0,
|
||||
// _ => 1,
|
||||
// })
|
||||
// }
|
||||
/// for certain NVIDIA GLSL versions, we need to offset the diagnostic number by -1 as those versions (incorrectly/inconsistently) state that:
|
||||
/// "After processing this directive (including its new-line), the implementation will behave as if it is compiling at line number line+1".
|
||||
/// So to get the correct behaviour (first line), with source strings being 0-based, we need to -1.
|
||||
fn get_line_offset(gpu_vendor: GPUVendor, doc_glsl_version: Version) -> u32 {
|
||||
match (gpu_vendor, doc_glsl_version) {
|
||||
(GPUVendor::NVIDIA, Version::Glsl110)
|
||||
| (GPUVendor::NVIDIA, Version::Glsl120)
|
||||
| (GPUVendor::NVIDIA, Version::Glsl130)
|
||||
| (GPUVendor::NVIDIA, Version::Glsl140)
|
||||
| (GPUVendor::NVIDIA, Version::Glsl150) => 1,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_diagnostics_output(
|
||||
&self,
|
||||
output: String,
|
||||
uri: &NormalizedPathBuf,
|
||||
source_mapper: &SourceMapper<NormalizedPathBuf>,
|
||||
// graph: &CachedStableGraph<NormalizedPathBuf, IncludeLine>,
|
||||
&self, output: String, uri: &NormalizedPathBuf, source_mapper: &SourceMapper<NormalizedPathBuf>,
|
||||
sources: &HashMap<&NormalizedPathBuf, &Sourcefile>,
|
||||
) -> HashMap<Url, Vec<Diagnostic>> {
|
||||
let output_lines = output.split('\n').collect::<Vec<&str>>();
|
||||
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = HashMap::with_capacity(output_lines.len());
|
||||
|
||||
debug!("diagnostics regex selected"; "regex" => self.get_line_regex() .as_str());
|
||||
debug!("diagnostics regex selected"; "regex" => self.line_regex .as_str());
|
||||
|
||||
for line in output_lines {
|
||||
let diagnostic_capture = match self.get_line_regex().captures(line) {
|
||||
let diagnostic_capture = match self.line_regex.captures(line) {
|
||||
Some(d) => d,
|
||||
None => continue,
|
||||
};
|
||||
|
@ -66,14 +67,22 @@ impl<'a, T: ShaderValidator + ?Sized> DiagnosticsParser<'a, T> {
|
|||
|
||||
let msg = diagnostic_capture.name("output").unwrap().as_str();
|
||||
|
||||
let line = match diagnostic_capture.name("linenum") {
|
||||
Some(c) => c.as_str().parse::<u32>().unwrap_or(0),
|
||||
None => 0,
|
||||
let source_num: SourceNum = match diagnostic_capture.name("filepath") {
|
||||
Some(o) => o.as_str().parse::<usize>().unwrap().into(),
|
||||
None => 0.into(),
|
||||
};
|
||||
|
||||
// TODO: line matching maybe
|
||||
/* let line_text = source_lines[line as usize];
|
||||
let leading_whitespace = line_text.len() - line_text.trim_start().len(); */
|
||||
let origin = match source_num {
|
||||
ROOT_SOURCE_NUM => uri,
|
||||
_ => source_mapper.get_node(source_num),
|
||||
};
|
||||
|
||||
let line = match diagnostic_capture.name("linenum") {
|
||||
Some(c) => {
|
||||
c.as_str().parse::<u32>().unwrap_or(0) - self.line_offset
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
|
||||
let severity = match diagnostic_capture.name("severity") {
|
||||
Some(c) => match c.as_str().to_lowercase().as_str() {
|
||||
|
@ -84,20 +93,14 @@ impl<'a, T: ShaderValidator + ?Sized> DiagnosticsParser<'a, T> {
|
|||
_ => DiagnosticSeverity::INFORMATION,
|
||||
};
|
||||
|
||||
let origin = match diagnostic_capture.name("filepath") {
|
||||
Some(o) => {
|
||||
let source_num: SourceNum = o.as_str().parse::<usize>().unwrap().into();
|
||||
source_mapper.get_node(source_num)
|
||||
}
|
||||
None => uri,
|
||||
};
|
||||
let source = sources[origin];
|
||||
let (start, end) = source.linemap().line_range_for_position(Position::new(line, 0));
|
||||
let line_text = &source.source[start..end.unwrap_or(source.source.len() - 1)];
|
||||
|
||||
let diagnostic = Diagnostic {
|
||||
range: Range::new(
|
||||
/* Position::new(line, leading_whitespace as u64),
|
||||
Position::new(line, line_text.len() as u64) */
|
||||
Position::new(line-1, 0),
|
||||
Position::new(line-1, 1000),
|
||||
Position::new(line, (line_text.len() - line_text.trim_start().len()) as u32),
|
||||
Position::new(line, line_text.len() as u32),
|
||||
),
|
||||
severity: Some(severity),
|
||||
source: Some("mcglsl".to_string()),
|
||||
|
@ -119,21 +122,20 @@ impl<'a, T: ShaderValidator + ?Sized> DiagnosticsParser<'a, T> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod diagnostics_test {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use filesystem::NormalizedPathBuf;
|
||||
use sourcefile::SourceMapper;
|
||||
use sourcefile::{SourceMapper, Sourcefile};
|
||||
use trim_margin::MarginTrimmable;
|
||||
use url::Url;
|
||||
|
||||
use crate::{diagnostics_parser::DiagnosticsParser, MockShaderValidator};
|
||||
use crate::diagnostics_parser::DiagnosticsParser;
|
||||
|
||||
#[test]
|
||||
#[logging_macro::scope]
|
||||
fn test_nvidia_diagnostics() {
|
||||
fn test_nvidia_diagnostics_glsl150() {
|
||||
logging::scope(&logging::logger().new(slog_o!("driver" => "nvidia")), || {
|
||||
let mut mockgl = MockShaderValidator::new();
|
||||
mockgl.expect_vendor().returning(|| "NVIDIA Corporation".into());
|
||||
|
||||
let output = "0(9) : error C0000: syntax error, unexpected '}', expecting ',' or ';' at token \"}\"";
|
||||
let output = "0(1) : error C0000: syntax error, unexpected '}', expecting ',' or ';' at token \"}\"";
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
let path: NormalizedPathBuf = "/home/noah/.minecraft/shaderpacks/test/shaders/final.fsh".into();
|
||||
|
@ -143,9 +145,47 @@ mod diagnostics_test {
|
|||
let mut source_mapper = SourceMapper::new(0);
|
||||
source_mapper.get_num(&path);
|
||||
|
||||
let parser = DiagnosticsParser::new(&mockgl);
|
||||
let parser = DiagnosticsParser::new(crate::GPUVendor::NVIDIA, sourcefile::Version::Glsl150);
|
||||
|
||||
let results = parser.parse_diagnostics_output(output.to_string(), &path.parent().unwrap(), &source_mapper);
|
||||
let source = Sourcefile::new(
|
||||
"sample text".to_string(),
|
||||
path.clone(),
|
||||
path.parent().and_then(|p| p.parent()).unwrap(),
|
||||
);
|
||||
let sources = HashMap::from_iter(vec![(&path, &source)]);
|
||||
|
||||
let results = parser.parse_diagnostics_output(output.to_string(), &path, &source_mapper, &sources);
|
||||
|
||||
assert_eq!(results.len(), 1);
|
||||
let first = results.into_iter().next().unwrap();
|
||||
assert_eq!(first.0, Url::from_file_path(path).unwrap());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[logging_macro::scope]
|
||||
fn test_nvidia_diagnostics_glsl330() {
|
||||
logging::scope(&logging::logger().new(slog_o!("driver" => "nvidia")), || {
|
||||
let output = "0(0) : error C0000: syntax error, unexpected '}', expecting ',' or ';' at token \"}\"";
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
let path: NormalizedPathBuf = "/home/noah/.minecraft/shaderpacks/test/shaders/final.fsh".into();
|
||||
#[cfg(target_family = "windows")]
|
||||
let path: NormalizedPathBuf = "c:\\home\\noah\\.minecraft\\shaderpacks\\test\\shaders\\final.fsh".into();
|
||||
|
||||
let mut source_mapper = SourceMapper::new(0);
|
||||
source_mapper.get_num(&path);
|
||||
|
||||
let parser = DiagnosticsParser::new(crate::GPUVendor::NVIDIA, sourcefile::Version::Glsl330);
|
||||
|
||||
let source = Sourcefile::new(
|
||||
"sample text".to_string(),
|
||||
path.clone(),
|
||||
path.parent().and_then(|p| p.parent()).unwrap(),
|
||||
);
|
||||
let sources = HashMap::from_iter(vec![(&path, &source)]);
|
||||
|
||||
let results = parser.parse_diagnostics_output(output.to_string(), &path, &source_mapper, &sources);
|
||||
|
||||
assert_eq!(results.len(), 1);
|
||||
let first = results.into_iter().next().unwrap();
|
||||
|
@ -157,14 +197,13 @@ mod diagnostics_test {
|
|||
#[logging_macro::scope]
|
||||
fn test_amd_diagnostics() {
|
||||
logging::scope(&logging::logger().new(slog_o!("driver" => "amd")), || {
|
||||
let mut mockgl = MockShaderValidator::new();
|
||||
mockgl.expect_vendor().returning(|| "ATI Technologies".into());
|
||||
|
||||
let output = r#"
|
||||
|ERROR: 0:0: '' : syntax error: #line
|
||||
|ERROR: 0:1: '' : syntax error: #line
|
||||
|ERROR: 0:10: '' : syntax error: #line
|
||||
|ERROR: 0:15: 'varying' : syntax error: syntax error
|
||||
"#.trim_margin().unwrap();
|
||||
|ERROR: 0:2: 'varying' : syntax error: syntax error
|
||||
"#
|
||||
.trim_margin()
|
||||
.unwrap();
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
let path: NormalizedPathBuf = "/home/noah/.minecraft/shaderpacks/test/shaders/final.fsh".into();
|
||||
|
@ -174,9 +213,21 @@ mod diagnostics_test {
|
|||
let mut source_mapper = SourceMapper::new(0);
|
||||
source_mapper.get_num(&path);
|
||||
|
||||
let parser = DiagnosticsParser::new(&mockgl);
|
||||
let parser = DiagnosticsParser::new(crate::GPUVendor::AMD, sourcefile::Version::Glsl150);
|
||||
|
||||
let results = parser.parse_diagnostics_output(output, &path.parent().unwrap(), &source_mapper);
|
||||
let source = Sourcefile::new(
|
||||
"|int main() {
|
||||
| hello_world();
|
||||
|}"
|
||||
.to_string()
|
||||
.trim_margin()
|
||||
.unwrap(),
|
||||
path.clone(),
|
||||
path.parent().and_then(|p| p.parent()).unwrap(),
|
||||
);
|
||||
let sources = HashMap::from_iter(vec![(&path, &source)]);
|
||||
|
||||
let results = parser.parse_diagnostics_output(output, &path, &source_mapper, &sources);
|
||||
|
||||
assert_eq!(results.len(), 1);
|
||||
let first = results.into_iter().next().unwrap();
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use std::ffi::{CStr, CString};
|
||||
use std::ptr;
|
||||
|
||||
use glutin::platform::unix::EventLoopExtUnix;
|
||||
use glutin::event_loop::EventLoopBuilder;
|
||||
use glutin::platform::unix::EventLoopBuilderExtUnix;
|
||||
use logging::info;
|
||||
|
||||
use crate::ShaderValidator;
|
||||
|
@ -12,7 +13,8 @@ pub(crate) struct Context {
|
|||
|
||||
impl Context {
|
||||
pub fn default() -> Context {
|
||||
let events_loop = glutin::event_loop::EventLoop::<()>::new_any_thread();
|
||||
let events_loop = EventLoopBuilder::new().with_any_thread(true).build();
|
||||
// let events_loop = glutin::event_loop::EventLoop::<()>::new_any_thread();
|
||||
let gl_window = glutin::ContextBuilder::new()
|
||||
.build_headless(&*events_loop, glutin::dpi::PhysicalSize::new(1, 1))
|
||||
.unwrap();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue