mirror of
https://github.com/Strum355/mcshader-lsp.git
synced 2025-07-23 19:25:51 +00:00
cpp style #line and diagnostics per-file per lint
This commit is contained in:
parent
c322abe9af
commit
e56d182e3c
9 changed files with 278 additions and 138 deletions
6
server/src/consts.rs
Normal file
6
server/src/consts.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
pub static SOURCE: &str = "mc-glsl";
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub static INCLUDE_DIRECTIVE: &str = "#extension GL_GOOGLE_include_directive : require\n";
|
||||
|
||||
pub static CPP_LINE_DIRECTIVE: &str = "#extension GL_GOOGLE_cpp_style_line_directive : require\n";
|
|
@ -1,11 +1,8 @@
|
|||
use petgraph::stable_graph::NodeIndex;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::graph::CachedStableGraph;
|
||||
|
||||
use anyhow::{Result, Error};
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
struct VisitCount {
|
||||
node: NodeIndex,
|
||||
|
@ -47,7 +44,7 @@ impl <'a> Dfs<'a> {
|
|||
let cycle_nodes: Vec<NodeIndex> = self.cycle.iter().map(|n| n.node).collect();
|
||||
return Err(
|
||||
Error::new(
|
||||
CycleError::new(&cycle_nodes, *child, self.graph)
|
||||
error::CycleError::new(&cycle_nodes, *child, self.graph)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -103,31 +100,57 @@ impl <'a> Iterator for Dfs<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub struct CycleError(Vec<String>);
|
||||
pub mod error {
|
||||
use petgraph::stable_graph::NodeIndex;
|
||||
|
||||
impl CycleError {
|
||||
fn new(nodes: &[NodeIndex], current_node: NodeIndex, graph: &CachedStableGraph) -> Self {
|
||||
let mut resolved_nodes: Vec<String> = nodes.iter().map(|i| graph.get_node(*i).clone()).collect();
|
||||
resolved_nodes.push(graph.get_node(current_node).clone());
|
||||
CycleError(resolved_nodes)
|
||||
}
|
||||
}
|
||||
use thiserror::Error;
|
||||
|
||||
impl Display for CycleError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut disp = String::new();
|
||||
disp.push_str(format!("Include cycle detected:\n{} imports ", self.0[0]).as_str());
|
||||
for p in &self.0[1..self.0.len()-1] {
|
||||
disp.push_str(format!("\n{}, which imports ", *p).as_str());
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
use crate::{graph::CachedStableGraph, consts};
|
||||
|
||||
use rust_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub struct CycleError(Vec<String>);
|
||||
|
||||
impl CycleError {
|
||||
pub fn new(nodes: &[NodeIndex], current_node: NodeIndex, graph: &CachedStableGraph) -> Self {
|
||||
let mut resolved_nodes: Vec<String> = nodes.iter().map(|i| graph.get_node(*i).clone()).collect();
|
||||
resolved_nodes.push(graph.get_node(current_node).clone());
|
||||
CycleError(resolved_nodes)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for CycleError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut disp = String::new();
|
||||
disp.push_str(format!("Include cycle detected:\n{} imports ", self.0[0]).as_str());
|
||||
for p in &self.0[1..self.0.len()-1] {
|
||||
disp.push_str(format!("\n{}, which imports ", *p).as_str());
|
||||
}
|
||||
disp.push_str(format!("\n{}", self.0[self.0.len()-1]).as_str());
|
||||
f.write_str(disp.as_str())
|
||||
}
|
||||
disp.push_str(format!("\n{}", self.0[self.0.len()-1]).as_str());
|
||||
f.write_str(disp.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for CycleError {
|
||||
fn into(self) -> String {
|
||||
format!("{}", self)
|
||||
impl Into<Diagnostic> for CycleError {
|
||||
fn into(self) -> Diagnostic {
|
||||
Diagnostic{
|
||||
severity: Some(DiagnosticSeverity::Error),
|
||||
range: Range::new(Position::new(0, 0), Position::new(0, 500)),
|
||||
source: Some(consts::SOURCE.into()),
|
||||
message: self.into(),
|
||||
code: None,
|
||||
tags: None,
|
||||
related_information: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for CycleError {
|
||||
fn into(self) -> String {
|
||||
format!("{}", self)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ use petgraph::Direction;
|
|||
use petgraph::stable_graph::EdgeIndex;
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::IncludePosition;
|
||||
|
||||
|
@ -34,16 +33,15 @@ impl CachedStableGraph {
|
|||
/// and caches the result in the `HashMap`. Complexity is **O(1)** if the value
|
||||
/// is cached (which should always be the case), else **O(n)** where **n** is
|
||||
/// the number of node indices, as an exhaustive search must be done.
|
||||
pub fn find_node(&mut self, name: impl Into<String>) -> Option<NodeIndex> {
|
||||
let name_str = name.into();
|
||||
match self.cache.get(&name_str) {
|
||||
pub fn find_node(&mut self, name: &str) -> Option<NodeIndex> {
|
||||
match self.cache.get(name) {
|
||||
Some(n) => Some(*n),
|
||||
None => {
|
||||
// If the string is not in cache, O(n) search the graph (i know...) and then cache the NodeIndex
|
||||
// for later
|
||||
let n = self.graph.node_indices().find(|n| self.graph[*n] == name_str);
|
||||
let n = self.graph.node_indices().find(|n| self.graph[*n] == name);
|
||||
if let Some(n) = n {
|
||||
self.cache.insert(name_str, n);
|
||||
self.cache.insert(name.to_string(), n);
|
||||
}
|
||||
n
|
||||
}
|
||||
|
@ -58,15 +56,16 @@ impl CachedStableGraph {
|
|||
self.graph.edge_weight(self.graph.find_edge(parent, child).unwrap()).unwrap()
|
||||
}
|
||||
|
||||
pub fn remove_node(&mut self, name: impl Into<String>) {
|
||||
let idx = self.cache.remove(&name.into());
|
||||
#[allow(dead_code)]
|
||||
pub fn remove_node(&mut self, name: &str) {
|
||||
let idx = self.cache.remove(name);
|
||||
if let Some(idx) = idx {
|
||||
self.graph.remove_node(idx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_node(&mut self, name: impl Into<String>) -> NodeIndex {
|
||||
let name_str = name.into();
|
||||
pub fn add_node(&mut self, name: &str) -> NodeIndex {
|
||||
let name_str = name.to_string();
|
||||
let idx = self.graph.add_node(name_str.clone());
|
||||
self.cache.insert(name_str.clone(), idx);
|
||||
self.reverse_index.insert(idx, name_str);
|
||||
|
@ -78,10 +77,12 @@ impl CachedStableGraph {
|
|||
self.graph.add_edge(parent, child, IncludePosition{filepath: child_path, line, start, end})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn edge_weights(&self, node: NodeIndex) -> Vec<IncludePosition> {
|
||||
self.graph.edges(node).map(|e| e.weight().clone()).collect()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn child_node_names(&self, node: NodeIndex) -> Vec<String> {
|
||||
self.graph.neighbors(node).map(|n| self.reverse_index.get(&n).unwrap().clone()).collect()
|
||||
}
|
||||
|
@ -90,6 +91,7 @@ impl CachedStableGraph {
|
|||
self.graph.neighbors(node).collect()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn parent_node_names(&self, node: NodeIndex) -> Vec<String> {
|
||||
self.graph.neighbors_directed(node, Direction::Incoming).map(|n| self.reverse_index.get(&n).unwrap().clone()).collect()
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ use std::cell::RefCell;
|
|||
use std::collections::{HashMap, LinkedList};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::cmp::max;
|
||||
use std::io::{stdin, stdout, BufRead, BufReader, Write};
|
||||
use std::ops::Add;
|
||||
use std::process;
|
||||
|
@ -35,6 +36,7 @@ mod provider;
|
|||
mod lsp_ext;
|
||||
mod dfs;
|
||||
mod merge_views;
|
||||
mod consts;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
@ -46,7 +48,6 @@ lazy_static! {
|
|||
static ref RE_INCLUDE_EXTENSION: Regex = Regex::new(r#"#extension GL_GOOGLE_include_directive ?: ?require"#).unwrap();
|
||||
}
|
||||
|
||||
static SOURCE: &str = "mc-glsl";
|
||||
|
||||
fn main() {
|
||||
let stdin = stdin();
|
||||
|
@ -105,7 +106,7 @@ pub struct IncludePosition {
|
|||
|
||||
impl Display for IncludePosition {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(f, "{{{}, l {}, s, {}, e {}}}", self.filepath, self.line, self.start, self.end)
|
||||
write!(f, "{{path: '{}', line: {}}}", self.filepath, self.line)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,7 +162,7 @@ impl MinecraftShaderLanguageServer {
|
|||
for path in file_iter {
|
||||
let includes = self.find_includes(root, path.as_str());
|
||||
|
||||
let idx = self.graph.borrow_mut().add_node(path.clone());
|
||||
let idx = self.graph.borrow_mut().add_node(&path);
|
||||
|
||||
//eprintln!("adding {} with\n{:?}", path.clone(), includes);
|
||||
|
||||
|
@ -231,7 +232,7 @@ impl MinecraftShaderLanguageServer {
|
|||
includes
|
||||
}
|
||||
|
||||
pub fn lint(&self, uri: &str) -> Result<Vec<Diagnostic>> {
|
||||
pub fn lint(&self, uri: &str) -> Result<HashMap<Url, Vec<Diagnostic>>> {
|
||||
// get all top level ancestors of this file
|
||||
let file_ancestors = match self.get_file_toplevel_ancestors(uri) {
|
||||
Ok(opt) => match opt {
|
||||
|
@ -240,12 +241,11 @@ impl MinecraftShaderLanguageServer {
|
|||
},
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
let mut all_sources: HashMap<String, String> = HashMap::new();
|
||||
|
||||
|
||||
eprintln!("ancestors for {}:\n{:?}", uri, file_ancestors.iter().map(|e| self.graph.borrow().graph.node_weight(*e).unwrap().clone()).collect::<Vec<String>>());
|
||||
|
||||
let mut diagnostics = Vec::new();
|
||||
|
||||
let mut all_sources: HashMap<String, String> = HashMap::new();
|
||||
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = HashMap::new();//Vec::new();
|
||||
|
||||
if file_ancestors.is_empty() {
|
||||
let root = self.graph.borrow_mut().find_node(uri).unwrap();
|
||||
|
@ -253,16 +253,9 @@ impl MinecraftShaderLanguageServer {
|
|||
let tree = match self.get_dfs_for_node(root) {
|
||||
Ok(tree) => tree,
|
||||
Err(e) => {
|
||||
let e = e.downcast::<dfs::CycleError>().unwrap();
|
||||
return Ok(vec![Diagnostic{
|
||||
severity: Some(DiagnosticSeverity::Error),
|
||||
range: Range::new(Position::new(0, 0), Position::new(0, 500)),
|
||||
source: Some(SOURCE.into()),
|
||||
message: e.into(),
|
||||
code: None,
|
||||
tags: None,
|
||||
related_information: None,
|
||||
}])
|
||||
let e = e.downcast::<dfs::error::CycleError>().unwrap();
|
||||
diagnostics.insert(Url::from_file_path(uri).unwrap(), vec![e.into()]);
|
||||
return Ok(diagnostics);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -284,22 +277,17 @@ impl MinecraftShaderLanguageServer {
|
|||
let nodes = match self.get_dfs_for_node(*root) {
|
||||
Ok(nodes) => nodes,
|
||||
Err(e) => {
|
||||
let e = e.downcast::<dfs::CycleError>().unwrap();
|
||||
return Ok(vec![Diagnostic{
|
||||
severity: Some(DiagnosticSeverity::Error),
|
||||
range: Range::new(Position::new(0, 0), Position::new(0, 500)),
|
||||
source: Some(SOURCE.into()),
|
||||
message: e.into(),
|
||||
code: None,
|
||||
tags: None,
|
||||
related_information: None,
|
||||
}])
|
||||
let e = e.downcast::<dfs::error::CycleError>().unwrap();
|
||||
diagnostics.insert(Url::from_file_path(uri).unwrap(), vec![e.into()]);
|
||||
return Ok(diagnostics);
|
||||
}
|
||||
};
|
||||
let sources = self.load_sources(&nodes)?;
|
||||
all_trees.push(nodes);
|
||||
all_sources.extend(sources);
|
||||
}
|
||||
|
||||
//self.graph.borrow().
|
||||
|
||||
for tree in all_trees {
|
||||
let graph = self.graph.borrow();
|
||||
|
@ -314,16 +302,22 @@ impl MinecraftShaderLanguageServer {
|
|||
}
|
||||
};
|
||||
|
||||
for (path, _) in all_sources {
|
||||
diagnostics.entry(Url::from_file_path(path).unwrap()).or_default();
|
||||
}
|
||||
|
||||
Ok(diagnostics)
|
||||
}
|
||||
|
||||
fn parse_validator_stdout(&self, stdout: &str, source: &str) -> Vec<Diagnostic> {
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
let source_lines: Vec<&str> = source.split('\n').collect();
|
||||
stdout.split('\n').for_each(|line| {
|
||||
fn parse_validator_stdout(&self, stdout: &str, 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 => return
|
||||
None => continue
|
||||
};
|
||||
|
||||
eprintln!("match {:?}", diagnostic_capture);
|
||||
|
@ -331,16 +325,16 @@ impl MinecraftShaderLanguageServer {
|
|||
let msg = diagnostic_capture.get(4).unwrap().as_str().trim();
|
||||
|
||||
if msg.starts_with("compilation terminated") {
|
||||
return
|
||||
continue;
|
||||
}
|
||||
|
||||
let line = match diagnostic_capture.get(3) {
|
||||
let line = max(match diagnostic_capture.get(3) {
|
||||
Some(c) => match c.as_str().parse::<u64>() {
|
||||
Ok(i) => i,
|
||||
Err(_) => 0,
|
||||
},
|
||||
None => 0,
|
||||
} - 1;
|
||||
}, 2) - 2;
|
||||
|
||||
// TODO: line matching maybe
|
||||
/* let line_text = source_lines[line as usize];
|
||||
|
@ -355,6 +349,10 @@ impl MinecraftShaderLanguageServer {
|
|||
_ => DiagnosticSeverity::Information,
|
||||
};
|
||||
|
||||
let origin = match diagnostic_capture.get(2) {
|
||||
Some(o) => o.as_str().to_string(),
|
||||
None => "".to_string(),
|
||||
};
|
||||
|
||||
let diagnostic = Diagnostic {
|
||||
range: Range::new(
|
||||
|
@ -365,14 +363,20 @@ impl MinecraftShaderLanguageServer {
|
|||
),
|
||||
code: None,
|
||||
severity: Some(severity),
|
||||
source: Some(SOURCE.into()),
|
||||
source: Some(consts::SOURCE.into()),
|
||||
message: msg.into(),
|
||||
related_information: None,
|
||||
tags: None,
|
||||
};
|
||||
|
||||
diagnostics.push(diagnostic);
|
||||
});
|
||||
let origin_url = Url::from_file_path(origin).unwrap();
|
||||
match diagnostics.get_mut(&origin_url) {//.get_or_insert(Vec::new());
|
||||
Some(d) => d.push(diagnostic),
|
||||
None => {
|
||||
diagnostics.insert(origin_url, vec![diagnostic]);
|
||||
},
|
||||
};
|
||||
}
|
||||
diagnostics
|
||||
}
|
||||
|
||||
|
@ -415,15 +419,12 @@ impl MinecraftShaderLanguageServer {
|
|||
}
|
||||
|
||||
fn invoke_validator(&self, source: LinkedList<&str>) -> Result<String> {
|
||||
eprintln!("validator bin path: {}", self.config.glslang_validator_path);
|
||||
let cmd = process::Command::new(&self.config.glslang_validator_path)
|
||||
.args(&["--stdin", "-S", "frag"])
|
||||
.stdin(process::Stdio::piped())
|
||||
.stdout(process::Stdio::piped())
|
||||
.spawn();
|
||||
|
||||
eprintln!("invoking validator");
|
||||
|
||||
let mut child = cmd?;//.expect("glslangValidator failed to spawn");
|
||||
let stdin = child.stdin.as_mut().expect("no stdin handle found");
|
||||
|
||||
|
@ -441,12 +442,15 @@ impl MinecraftShaderLanguageServer {
|
|||
Ok(stdout)
|
||||
}
|
||||
|
||||
pub fn publish_diagnostic(&self, diagnostics: Vec<Diagnostic>, uri: impl Into<Url>, document_version: Option<i64>) {
|
||||
self.endpoint.send_notification(PublishDiagnostics::METHOD, PublishDiagnosticsParams {
|
||||
uri: uri.into(),
|
||||
diagnostics,
|
||||
version: document_version,
|
||||
}).expect("failed to publish diagnostics");
|
||||
pub fn publish_diagnostic(&self, diagnostics: HashMap<Url, Vec<Diagnostic>>, document_version: Option<i64>) {
|
||||
eprintln!("DIAGNOSTICS:\n{:?}", diagnostics);
|
||||
for (uri, diagnostics) in diagnostics {
|
||||
self.endpoint.send_notification(PublishDiagnostics::METHOD, PublishDiagnosticsParams {
|
||||
uri,
|
||||
diagnostics,
|
||||
version: document_version,
|
||||
}).expect("failed to publish diagnostics");
|
||||
}
|
||||
}
|
||||
|
||||
fn set_status(&self, status: impl Into<String>, message: impl Into<String>, icon: impl Into<String>) {
|
||||
|
@ -551,7 +555,7 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer {
|
|||
fn did_open_text_document(&mut self, params: DidOpenTextDocumentParams) {
|
||||
eprintln!("opened doc {}", params.text_document.uri);
|
||||
match self.lint(params.text_document.uri.path()/* , params.text_document.text */) {
|
||||
Ok(diagnostics) => self.publish_diagnostic(diagnostics, params.text_document.uri, None),
|
||||
Ok(diagnostics) => self.publish_diagnostic(diagnostics, None),
|
||||
Err(e) => eprintln!("error linting: {}", e),
|
||||
}
|
||||
}
|
||||
|
@ -573,7 +577,7 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer {
|
|||
|
||||
/*let file_content = fs::read(path).unwrap(); */
|
||||
match self.lint(path.as_str()/* , String::from_utf8(file_content).unwrap() */) {
|
||||
Ok(diagnostics) => self.publish_diagnostic(diagnostics, params.text_document.uri, None),
|
||||
Ok(diagnostics) => self.publish_diagnostic(diagnostics, None),
|
||||
Err(e) => eprintln!("error linting: {}", e),
|
||||
}
|
||||
}
|
||||
|
@ -679,7 +683,7 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer {
|
|||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
let node = match self.graph.borrow_mut().find_node(curr_doc) {
|
||||
let node = match self.graph.borrow_mut().find_node(&curr_doc) {
|
||||
Some(n) => n,
|
||||
None => {
|
||||
completable.complete(Ok(vec![]));
|
||||
|
|
|
@ -6,12 +6,7 @@ use core::slice::Iter;
|
|||
|
||||
use petgraph::stable_graph::NodeIndex;
|
||||
|
||||
use crate::graph::CachedStableGraph;
|
||||
|
||||
#[allow(dead_code)]
|
||||
static INCLUDE_DIRECTIVE: &str = "#extension GL_GOOGLE_include_directive : require";
|
||||
#[allow(dead_code)]
|
||||
static CPP_LINE_DIRECTIVE: &str = "#extension GL_GOOGLE_cpp_style_line_directive : require";
|
||||
use crate::{graph::CachedStableGraph, consts};
|
||||
|
||||
pub struct MergeViewGenerator<'a> {
|
||||
sources: &'a mut HashMap<String, String>,
|
||||
|
@ -38,16 +33,31 @@ impl <'a> MergeViewGenerator<'a> {
|
|||
let first_path = self.graph.get_node(first).clone();
|
||||
|
||||
last_offset_set.insert(first_path.clone(), 0);
|
||||
|
||||
self.add_line_directive_extension(&first_path, &mut merge_list, &mut last_offset_set);
|
||||
|
||||
self.create_merge_views(nodes_iter, &mut merge_list, &mut last_offset_set);
|
||||
|
||||
// now we add a view of the remainder of the root file
|
||||
let offset = *last_offset_set.get(&first_path).unwrap();
|
||||
merge_list.push_back(&self.sources.get(&first_path).unwrap().as_str()[offset..]);
|
||||
merge_list.push_back(&self.sources.get(&first_path).unwrap()[offset..]);
|
||||
|
||||
merge_list
|
||||
}
|
||||
|
||||
fn add_line_directive_extension(&'a self, root_path: &str, merge_list: &mut LinkedList<&'a str>, last_offset_set: &mut HashMap<String, usize>) {
|
||||
let root_source = self.sources.get(root_path).unwrap();
|
||||
let (char_offset, _) = self.char_offset_for_line(1, root_source);
|
||||
merge_list.push_back(&root_source[..char_offset]);
|
||||
merge_list.push_back(&consts::CPP_LINE_DIRECTIVE[..]);
|
||||
let line_directive = format!("#line 2 \"{}\"\n", root_path);
|
||||
self.line_directives.borrow_mut().push(line_directive);
|
||||
unsafe {
|
||||
self.unsafe_get_and_insert(merge_list);
|
||||
}
|
||||
last_offset_set.insert(root_path.into(), char_offset);
|
||||
}
|
||||
|
||||
fn create_merge_views(
|
||||
&'a self,
|
||||
mut nodes: Peekable<Iter<(NodeIndex, Option<NodeIndex>)>>,
|
||||
|
@ -66,19 +76,10 @@ impl <'a> MergeViewGenerator<'a> {
|
|||
let child_path = self.graph.get_node(child).clone();
|
||||
|
||||
let source = self.sources.get(&parent_path).unwrap();
|
||||
let mut char_for_line: usize = 0;
|
||||
let mut char_following_line: usize = 0;
|
||||
for (n, line) in source.as_str().lines().enumerate() {
|
||||
if n == edge.line {
|
||||
char_following_line += line.len()+1;
|
||||
break;
|
||||
}
|
||||
char_for_line += line.len()+1;
|
||||
char_following_line = char_for_line;
|
||||
}
|
||||
let (char_for_line, char_following_line) = self.char_offset_for_line(edge.line, source);
|
||||
|
||||
let offset = *last_offset_set.insert(parent_path.clone(), char_following_line).get_or_insert(0);
|
||||
merge_list.push_back(&source.as_str()[offset..char_for_line]);
|
||||
merge_list.push_back(&source[offset..char_for_line]);
|
||||
self.add_opening_line_directive(&child_path, merge_list);
|
||||
|
||||
match nodes.peek() {
|
||||
|
@ -87,7 +88,7 @@ impl <'a> MergeViewGenerator<'a> {
|
|||
// if the next element is not a child of this element, we dump the rest of this elements source
|
||||
if next.1.unwrap() != child {
|
||||
let source = self.sources.get(&child_path).unwrap();
|
||||
merge_list.push_back(&source.as_str()[..]);
|
||||
merge_list.push_back(&source[..]);
|
||||
// +2 because edge.line is 0 indexed but #line is 1 indexed and references the *following* line
|
||||
self.add_closing_line_directive(edge.line+2, &parent_path, merge_list);
|
||||
}
|
||||
|
@ -97,7 +98,7 @@ impl <'a> MergeViewGenerator<'a> {
|
|||
let offset = *last_offset_set.get(&child_path).unwrap();
|
||||
let source = self.sources.get(&child_path).unwrap();
|
||||
if offset <= source.len() {
|
||||
merge_list.push_back(&source.as_str()[offset..]);
|
||||
merge_list.push_back(&source[offset..]);
|
||||
}
|
||||
|
||||
// +2 because edge.line is 0 indexed but #line is 1 indexed and references the *following* line
|
||||
|
@ -106,15 +107,31 @@ impl <'a> MergeViewGenerator<'a> {
|
|||
},
|
||||
None => {
|
||||
let source = self.sources.get(&child_path).unwrap();
|
||||
merge_list.push_back(&source.as_str()[..]);
|
||||
merge_list.push_back(&source[..]);
|
||||
// +2 because edge.line is 0 indexed but #line is 1 indexed and references the *following* line
|
||||
self.add_closing_line_directive(edge.line+2, &parent_path, merge_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns the character offset + 1 of the end of line number `line` and the character
|
||||
// offset + 1 for the end of the line after the previous one
|
||||
fn char_offset_for_line(&self, line_num: usize, source: &str) -> (usize, usize) {
|
||||
let mut char_for_line: usize = 0;
|
||||
let mut char_following_line: usize = 0;
|
||||
for (n, line) in source.lines().enumerate() {
|
||||
if n == line_num {
|
||||
char_following_line += line.len()+1;
|
||||
break;
|
||||
}
|
||||
char_for_line += line.len()+1;
|
||||
char_following_line = char_for_line;
|
||||
}
|
||||
(char_for_line, char_following_line)
|
||||
}
|
||||
|
||||
fn add_opening_line_directive(&self, path: &str, merge_list: &mut LinkedList<&str>) {
|
||||
let line_directive = format!("#line 1 {}\n", path);
|
||||
let line_directive = format!("#line 1 \"{}\"\n", path);
|
||||
self.line_directives.borrow_mut().push(line_directive);
|
||||
unsafe {
|
||||
self.unsafe_get_and_insert(merge_list);
|
||||
|
@ -126,12 +143,12 @@ impl <'a> MergeViewGenerator<'a> {
|
|||
// a #line directive
|
||||
let line_directive = if let Some(l) = merge_list.back() {
|
||||
if l.starts_with("\n#line") {
|
||||
format!("#line {} {}\n", line, path)
|
||||
format!("#line {} \"{}\"\n", line, path)
|
||||
} else {
|
||||
format!("\n#line {} {}\n", line, path)
|
||||
format!("\n#line {} \"{}\"\n", line, path)
|
||||
}
|
||||
} else {
|
||||
format!("\n#line {} {}\n", line, path)
|
||||
format!("\n#line {} \"{}\"\n", line, path)
|
||||
};
|
||||
|
||||
self.line_directives.borrow_mut().push(line_directive);
|
||||
|
@ -143,6 +160,6 @@ impl <'a> MergeViewGenerator<'a> {
|
|||
unsafe fn unsafe_get_and_insert(&self, merge_list: &mut LinkedList<&str>) {
|
||||
// :^)
|
||||
let vec_ptr_offset = self.line_directives.borrow().as_ptr().add(self.line_directives.borrow().len()-1);
|
||||
merge_list.push_back(&vec_ptr_offset.as_ref().unwrap().as_str()[..]);
|
||||
merge_list.push_back(&vec_ptr_offset.as_ref().unwrap()[..]);
|
||||
}
|
||||
}
|
|
@ -208,12 +208,29 @@ fn test_collect_root_ancestors() {
|
|||
let idx0 = graph.add_node("0");
|
||||
let idx1 = graph.add_node("1");
|
||||
let idx2 = graph.add_node("2");
|
||||
let idx3 = graph.add_node("3");
|
||||
|
||||
graph.add_edge(idx0, idx1, 2, 0, 0);
|
||||
graph.add_edge(idx1, idx2, 3, 0, 0);
|
||||
graph.add_edge(idx3, idx1, 4, 0, 0);
|
||||
|
||||
// 0 3
|
||||
// |/
|
||||
// 1
|
||||
// |
|
||||
// 2
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx2);
|
||||
assert_eq!(roots, vec![idx0]);
|
||||
assert_eq!(roots, vec![idx3, idx0]);
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx1);
|
||||
assert_eq!(roots, vec![idx3, idx0]);
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx0);
|
||||
assert_eq!(roots, vec![]);
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx3);
|
||||
assert_eq!(roots, vec![]);
|
||||
}
|
||||
{
|
||||
let mut graph = graph::CachedStableGraph::new();
|
||||
|
@ -227,8 +244,23 @@ fn test_collect_root_ancestors() {
|
|||
graph.add_edge(idx0, idx2, 3, 0, 0);
|
||||
graph.add_edge(idx1, idx3, 5, 0, 0);
|
||||
|
||||
// 0
|
||||
// / \
|
||||
// 1 2
|
||||
// /
|
||||
// 3
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx3);
|
||||
assert_eq!(roots, vec![idx0]);
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx2);
|
||||
assert_eq!(roots, vec![idx0]);
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx1);
|
||||
assert_eq!(roots, vec![idx0]);
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx0);
|
||||
assert_eq!(roots, vec![]);
|
||||
}
|
||||
{
|
||||
let mut graph = graph::CachedStableGraph::new();
|
||||
|
@ -242,8 +274,55 @@ fn test_collect_root_ancestors() {
|
|||
graph.add_edge(idx2, idx3, 3, 0, 0);
|
||||
graph.add_edge(idx1, idx3, 5, 0, 0);
|
||||
|
||||
// 0
|
||||
// |
|
||||
// 1
|
||||
// \
|
||||
// 2 \
|
||||
// \ /
|
||||
// 3
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx3);
|
||||
assert_eq!(roots, vec![idx0, idx2]);
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx2);
|
||||
assert_eq!(roots, vec![]);
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx1);
|
||||
assert_eq!(roots, vec![idx0]);
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx0);
|
||||
assert_eq!(roots, vec![]);
|
||||
}
|
||||
{
|
||||
let mut graph = graph::CachedStableGraph::new();
|
||||
|
||||
let idx0 = graph.add_node("0");
|
||||
let idx1 = graph.add_node("1");
|
||||
let idx2 = graph.add_node("2");
|
||||
let idx3 = graph.add_node("3");
|
||||
|
||||
graph.add_edge(idx0, idx1, 2, 0, 0);
|
||||
graph.add_edge(idx1, idx2, 4, 0, 0);
|
||||
graph.add_edge(idx1, idx3, 6, 0, 0);
|
||||
|
||||
// 0
|
||||
// |
|
||||
// 1
|
||||
// / \
|
||||
// 2 3
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx3);
|
||||
assert_eq!(roots, vec![idx0]);
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx2);
|
||||
assert_eq!(roots, vec![idx0]);
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx1);
|
||||
assert_eq!(roots, vec![idx0]);
|
||||
|
||||
let roots = graph.collect_root_ancestors(idx0);
|
||||
assert_eq!(roots, vec![]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,8 +487,8 @@ fn test_generate_merge_list_01() {
|
|||
|
||||
let (_tmp_dir, tmp_path) = copy_to_and_set_root("./testdata/01", &mut server);
|
||||
|
||||
let final_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/{}", tmp_path, "final.fsh"));
|
||||
let common_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/{}", tmp_path, "common.glsl"));
|
||||
let final_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/{}", tmp_path, "final.fsh"));
|
||||
let common_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/{}", tmp_path, "common.glsl"));
|
||||
|
||||
server.graph.borrow_mut().add_edge(final_idx, common_idx, 2, 0, 0);
|
||||
|
||||
|
@ -430,6 +509,7 @@ fn test_generate_merge_list_01() {
|
|||
let merge_file = tmp_path.clone() + "/shaders/final.fsh.merge";
|
||||
|
||||
let mut truth = String::from_utf8(fs::read::<String>(merge_file).unwrap()).unwrap();
|
||||
truth = truth.replacen("!!", &(tmp_path.clone()+"/shaders/final.fsh"), 1);
|
||||
truth = truth.replacen("!!", &(tmp_path.clone()+"/shaders/"+"common.glsl"), 1);
|
||||
truth = truth.replace("!!", &(tmp_path+"/shaders/"+"final.fsh"));
|
||||
|
||||
|
@ -444,10 +524,10 @@ fn test_generate_merge_list_02() {
|
|||
|
||||
let (_tmp_dir, tmp_path) = copy_to_and_set_root("./testdata/02", &mut server);
|
||||
|
||||
let final_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/{}", tmp_path, "final.fsh"));
|
||||
let test_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/utils/{}", tmp_path, "test.glsl"));
|
||||
let burger_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/utils/{}", tmp_path, "burger.glsl"));
|
||||
let sample_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/utils/{}", tmp_path, "sample.glsl"));
|
||||
let final_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/{}", tmp_path, "final.fsh"));
|
||||
let test_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/utils/{}", tmp_path, "test.glsl"));
|
||||
let burger_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/utils/{}", tmp_path, "burger.glsl"));
|
||||
let sample_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/utils/{}", tmp_path, "sample.glsl"));
|
||||
|
||||
server.graph.borrow_mut().add_edge(final_idx, sample_idx, 2, 0, 0);
|
||||
server.graph.borrow_mut().add_edge(sample_idx, burger_idx, 4, 0, 0);
|
||||
|
@ -471,6 +551,7 @@ fn test_generate_merge_list_02() {
|
|||
|
||||
let mut truth = String::from_utf8(fs::read::<String>(merge_file).unwrap()).unwrap();
|
||||
|
||||
truth = truth.replacen("!!", &(tmp_path.clone()+"/shaders/final.fsh"), 1);
|
||||
for file in &["sample.glsl", "burger.glsl", "sample.glsl", "test.glsl", "sample.glsl"] {
|
||||
let path = tmp_path.clone();
|
||||
truth = truth.replacen("!!", &format!("{}/shaders/utils/{}", path, file), 1);
|
||||
|
@ -488,10 +569,10 @@ fn test_generate_merge_list_03() {
|
|||
|
||||
let (_tmp_dir, tmp_path) = copy_to_and_set_root("./testdata/03", &mut server);
|
||||
|
||||
let final_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/{}", tmp_path, "final.fsh"));
|
||||
let test_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/utils/{}", tmp_path, "test.glsl"));
|
||||
let burger_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/utils/{}", tmp_path, "burger.glsl"));
|
||||
let sample_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/utils/{}", tmp_path, "sample.glsl"));
|
||||
let final_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/{}", tmp_path, "final.fsh"));
|
||||
let test_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/utils/{}", tmp_path, "test.glsl"));
|
||||
let burger_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/utils/{}", tmp_path, "burger.glsl"));
|
||||
let sample_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/utils/{}", tmp_path, "sample.glsl"));
|
||||
|
||||
server.graph.borrow_mut().add_edge(final_idx, sample_idx, 2, 0, 0);
|
||||
server.graph.borrow_mut().add_edge(sample_idx, burger_idx, 4, 0, 0);
|
||||
|
@ -515,6 +596,7 @@ fn test_generate_merge_list_03() {
|
|||
|
||||
let mut truth = String::from_utf8(fs::read::<String>(merge_file).unwrap()).unwrap();
|
||||
|
||||
truth = truth.replacen("!!", &(tmp_path.clone()+"/shaders/final.fsh"), 1);
|
||||
for file in &["sample.glsl", "burger.glsl", "sample.glsl", "test.glsl", "sample.glsl"] {
|
||||
let path = tmp_path.clone();
|
||||
truth = truth.replacen("!!", &format!("{}/shaders/utils/{}", path, file), 1);
|
||||
|
|
6
server/testdata/01/final.fsh.merge
vendored
6
server/testdata/01/final.fsh.merge
vendored
|
@ -1,10 +1,12 @@
|
|||
#version 120
|
||||
#extension GL_GOOGLE_cpp_style_line_directive : require
|
||||
#line 2 "!!"
|
||||
|
||||
#line 1 !!
|
||||
#line 1 "!!"
|
||||
float test() {
|
||||
return 0.5;
|
||||
}
|
||||
#line 4 !!
|
||||
#line 4 "!!"
|
||||
|
||||
void main() {
|
||||
gl_FragColor[0] = vec4(0.0);
|
||||
|
|
14
server/testdata/02/final.fsh.merge
vendored
14
server/testdata/02/final.fsh.merge
vendored
|
@ -1,26 +1,28 @@
|
|||
#version 120
|
||||
#extension GL_GOOGLE_cpp_style_line_directive : require
|
||||
#line 2 "!!"
|
||||
|
||||
#line 1 !!
|
||||
#line 1 "!!"
|
||||
int sample() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
#line 1 !!
|
||||
#line 1 "!!"
|
||||
void burger() {
|
||||
// sample text
|
||||
}
|
||||
#line 6 !!
|
||||
#line 6 "!!"
|
||||
|
||||
#line 1 !!
|
||||
#line 1 "!!"
|
||||
float test() {
|
||||
return 3.0;
|
||||
}
|
||||
#line 8 !!
|
||||
#line 8 "!!"
|
||||
|
||||
int sample_more() {
|
||||
return 5;
|
||||
}
|
||||
#line 4 !!
|
||||
#line 4 "!!"
|
||||
|
||||
void main() {
|
||||
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
|
14
server/testdata/03/final.fsh.merge
vendored
14
server/testdata/03/final.fsh.merge
vendored
|
@ -1,22 +1,24 @@
|
|||
#version 120
|
||||
#extension GL_GOOGLE_cpp_style_line_directive : require
|
||||
#line 2 "!!"
|
||||
|
||||
#line 1 !!
|
||||
#line 1 "!!"
|
||||
int sample() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
#line 1 !!
|
||||
#line 1 "!!"
|
||||
void burger() {
|
||||
// sample text
|
||||
}
|
||||
#line 6 !!
|
||||
#line 6 "!!"
|
||||
|
||||
#line 1 !!
|
||||
#line 1 "!!"
|
||||
float test() {
|
||||
return 3.0;
|
||||
}
|
||||
#line 8 !!
|
||||
#line 4 !!
|
||||
#line 8 "!!"
|
||||
#line 4 "!!"
|
||||
|
||||
void main() {
|
||||
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue