mirror of
https://github.com/Strum355/mcshader-lsp.git
synced 2025-08-04 00:49:17 +00:00
extract out diagnostics parser. pls submit AMD lint output in github issues
This commit is contained in:
parent
d3c0869288
commit
f8dd31ca81
4 changed files with 128 additions and 80 deletions
110
server/src/diagnostics_parser.rs
Normal file
110
server/src/diagnostics_parser.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
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<Regex> = OnceCell::new();
|
||||
fn diagnostics_regex<T>(vendor: &T) -> &'static Regex
|
||||
where
|
||||
T: opengl::ShaderValidator + ?Sized,
|
||||
{
|
||||
RE_DIAGNOSTIC.get_or_init(|| match vendor.vendor().as_str() {
|
||||
"NVIDIA" => {
|
||||
Regex::new(r#"^(?P<filepath>[^?<>*|"]+)\((?P<linenum>\d+)\) : (?P<severity>error|warning) [A-C]\d+: (?P<output>.+)"#).unwrap()
|
||||
}
|
||||
_ => {
|
||||
Regex::new(r#"^(?P<severity>ERROR|WARNING): (?P<filepath>[^?<>*|"\n]+):(?P<linenum>\d+): '[a-z]*' : (?P<output>.+)$"#).unwrap()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
static LINE_NUM_OFFSET: OnceCell<u32> = OnceCell::new();
|
||||
fn line_number_offset<T>(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<T>(output: String, uri: &Path, vendor_querier: &T) -> HashMap<Url, Vec<Diagnostic>>
|
||||
where
|
||||
T: opengl::ShaderValidator + ?Sized,
|
||||
{
|
||||
let output_lines = output.split('\n');
|
||||
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = 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::<u32>().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
|
||||
}
|
|
@ -39,6 +39,7 @@ use regex::Regex;
|
|||
use lazy_static::lazy_static;
|
||||
|
||||
mod commands;
|
||||
mod diagnostics_parser;
|
||||
mod configuration;
|
||||
mod consts;
|
||||
mod dfs;
|
||||
|
@ -53,7 +54,6 @@ mod url_norm;
|
|||
mod test;
|
||||
|
||||
lazy_static! {
|
||||
static ref RE_DIAGNOSTIC: Regex = Regex::new(r#"^(?P<filepath>[^?<>*|"]+)\((?P<linenum>\d+)\) : (?P<severity>error|warning) [A-C]\d+: (?P<output>.+)"#).unwrap();
|
||||
static ref RE_VERSION: Regex = Regex::new(r#"#version [\d]{3}"#).unwrap();
|
||||
static ref RE_INCLUDE: Regex = Regex::new(r#"^(?:\s)*?(?:#include) "(.+)"\r?"#).unwrap();
|
||||
static ref RE_INCLUDE_EXTENSION: Regex = Regex::new(r#"#extension GL_GOOGLE_include_directive ?: ?require"#).unwrap();
|
||||
|
@ -352,7 +352,7 @@ impl MinecraftShaderLanguageServer {
|
|||
return Ok(diagnostics);
|
||||
}
|
||||
};
|
||||
diagnostics.extend(self.parse_validator_stdout(uri, stdout, ""));
|
||||
diagnostics.extend(diagnostics_parser::parse_diagnostics_output(stdout, uri, self.opengl_context.as_ref()));
|
||||
} else {
|
||||
let mut all_trees: Vec<(TreeType, Vec<(NodeIndex, Option<_>)>)> = Vec::new();
|
||||
|
||||
|
@ -402,7 +402,7 @@ impl MinecraftShaderLanguageServer {
|
|||
Some(s) => s,
|
||||
None => continue,
|
||||
};
|
||||
diagnostics.extend(self.parse_validator_stdout(uri, stdout, ""));
|
||||
diagnostics.extend(diagnostics_parser::parse_diagnostics_output(stdout, uri, self.opengl_context.as_ref()));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -410,78 +410,6 @@ impl MinecraftShaderLanguageServer {
|
|||
Ok(diagnostics)
|
||||
}
|
||||
|
||||
fn parse_validator_stdout(&self, uri: &Path, stdout: String, _source: &str) -> HashMap<Url, Vec<Diagnostic>> {
|
||||
let stdout_lines = stdout.split('\n');
|
||||
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = HashMap::with_capacity(stdout_lines.count());
|
||||
let stdout_lines = stdout.split('\n');
|
||||
|
||||
for line in stdout_lines {
|
||||
let diagnostic_capture = match RE_DIAGNOSTIC.captures(line) {
|
||||
Some(d) => d,
|
||||
None => continue
|
||||
};
|
||||
|
||||
eprintln!("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::<u32>().unwrap_or(0),
|
||||
None => 0,
|
||||
} - 2;
|
||||
|
||||
// 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() {
|
||||
"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
|
||||
}
|
||||
|
||||
pub fn get_dfs_for_node(&self, root: NodeIndex) -> Result<Vec<(NodeIndex, Option<NodeIndex>)>, dfs::error::CycleError> {
|
||||
let graph_ref = self.graph.borrow();
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ use mockall::automock;
|
|||
#[cfg_attr(test, automock)]
|
||||
pub trait ShaderValidator {
|
||||
fn validate(&self, tree_type: super::TreeType, source: String) -> Option<String>;
|
||||
fn vendor(&self) -> String;
|
||||
}
|
||||
|
||||
pub struct OpenGlContext {
|
||||
|
@ -103,4 +104,8 @@ impl ShaderValidator for OpenGlContext {
|
|||
|
||||
result
|
||||
}
|
||||
|
||||
fn vendor(&self) -> String {
|
||||
unsafe { String::from_utf8(CStr::from_ptr(gl::GetString(gl::VENDOR) as *const _).to_bytes().to_vec()).unwrap() }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ use std::io::Result;
|
|||
use hamcrest2::prelude::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use slog::Logger;
|
||||
use slog::o;
|
||||
use slog::Logger;
|
||||
use tempdir::TempDir;
|
||||
|
||||
use petgraph::algo::is_cyclic_directed;
|
||||
|
@ -898,11 +898,12 @@ fn test_nvidia_diagnostics() {
|
|||
|
||||
let output = "/home/noah/.minecraft/shaderpacks/test/shaders/final.fsh(9) : error C0000: syntax error, unexpected '}', expecting ',' or ';' at token \"}\"";
|
||||
|
||||
let results = server.parse_validator_stdout(
|
||||
&PathBuf::from_str("/home/noah/.minecraft/shaderpacks/test").unwrap(),
|
||||
let results = diagnostics_parser::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!(
|
||||
|
@ -923,7 +924,11 @@ ERROR: 0:10: '' : syntax error: #line
|
|||
ERROR: 0:15: 'varying' : syntax error: syntax error
|
||||
";
|
||||
|
||||
let results = server.parse_validator_stdout(&PathBuf::from_str("/home/test").unwrap(), output.to_string(), "");
|
||||
let results = diagnostics_parser::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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue