Windows support

Migrated to PathBuf over &str and String for paths, long overdue
This commit is contained in:
Noah Santschi-Cooney 2021-02-01 02:37:19 +00:00
parent 539a9fb111
commit 7d5a46470b
10 changed files with 325 additions and 337 deletions

56
server/Cargo.lock generated
View file

@ -35,10 +35,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407"
[[package]]
name = "anyhow"
version = "1.0.37"
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee67c11feeac938fae061b232e38e0b6d94f97a9df10e6271319325ac4c56a86"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "anyhow"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
[[package]]
name = "autocfg"
@ -982,6 +991,15 @@ dependencies = [
"shared_library",
]
[[package]]
name = "output_vt100"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "owned_ttf_parser"
version = "0.6.0"
@ -1016,6 +1034,12 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "path-slash"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cacbb3c4ff353b534a67fb8d7524d00229da4cb1dc8c79f4db96e375ab5b619"
[[package]]
name = "percent-encoding"
version = "2.1.0"
@ -1067,6 +1091,18 @@ dependencies = [
"treeline",
]
[[package]]
name = "pretty_assertions"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
dependencies = [
"ansi_term",
"ctor",
"difference",
"output_vt100",
]
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
@ -1253,18 +1289,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.118"
version = "1.0.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.118"
version = "1.0.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df"
checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
dependencies = [
"proc-macro2",
"quote",
@ -1342,9 +1378,9 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "syn"
version = "1.0.58"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5"
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
dependencies = [
"proc-macro2",
"quote",
@ -1483,8 +1519,10 @@ dependencies = [
"hamcrest2",
"lazy_static",
"mockall",
"path-slash",
"percent-encoding",
"petgraph",
"pretty_assertions",
"regex",
"rust_lsp",
"serde",

View file

@ -7,7 +7,7 @@ edition = "2018"
[dependencies]
rust_lsp = { git = "https://github.com/Strum355/RustLSP", branch = "master" }
serde_json = "1.0.61"
serde = "1.0.118"
serde = "1.0.123"
walkdir = "2.3.1"
petgraph = "0.5.1"
lazy_static = "1.4.0"
@ -15,15 +15,17 @@ regex = "1.4.3"
chan = "0.1.23"
url = "2.2.0"
percent-encoding = "2.1.0"
anyhow = "1.0.37"
anyhow = "1.0.38"
bit-set = "0.5.2"
thiserror = "1.0.23"
glutin = "0.26.0"
gl = "0.14.0"
ctor = "0.1.18"
mockall = "0.9.0"
path-slash = "0.1.4"
[dev-dependencies]
tempdir = "0.3.7"
fs_extra = "1.2.0"
hamcrest2 = "*"
pretty_assertions = "0.6.1"

View file

@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::{collections::HashMap, path::PathBuf, str::FromStr};
use std::rc::Rc;
use std::cell::RefCell;
use std::fs::OpenOptions;
@ -28,7 +28,7 @@ impl CustomCommandProvider {
}
}
pub fn execute(&self, command: &str, args: Vec<Value>, root_path: &str) -> Result<Value, String> {
pub fn execute(&self, command: &str, args: Vec<Value>, root_path: &PathBuf) -> Result<Value, String> {
if self.commands.contains_key(command) {
return self.commands.get(command).unwrap().run_command(root_path, args);
}
@ -37,7 +37,7 @@ impl CustomCommandProvider {
}
pub trait Invokeable {
fn run_command(&self, root: &str, arguments: Vec<Value>) -> Result<Value, String>;
fn run_command(&self, root: &PathBuf, arguments: Vec<Value>) -> Result<Value, String>;
}
pub struct GraphDotCommand {
@ -45,9 +45,9 @@ pub struct GraphDotCommand {
}
impl Invokeable for GraphDotCommand {
fn run_command(&self, root: &str, _: Vec<Value>) -> Result<Value, String> {
let filepath = String::from(root) + "/graph.dot";
eprintln!("generating dot file at {}", filepath);
fn run_command(&self, root: &PathBuf, _: Vec<Value>) -> Result<Value, String> {
let filepath = root.join("graph.dot");
eprintln!("generating dot file at {:?}", filepath);
let mut file = OpenOptions::new()
.truncate(true)
.write(true)
@ -59,7 +59,7 @@ impl Invokeable for GraphDotCommand {
let graph = self.graph.as_ref();
file.seek(std::io::SeekFrom::Start(0))?;
file.write_all(dot::Dot::new(&(graph.borrow().graph)).to_string().as_bytes())?;
file.write_all(dot::Dot::new(&graph.borrow().graph).to_string().as_bytes())?;
file.flush()?;
file.seek(std::io::SeekFrom::Start(0))?;
Ok(())
@ -78,10 +78,10 @@ pub struct VirtualMergedDocument {
impl VirtualMergedDocument {
// TODO: DUPLICATE CODE
fn get_file_toplevel_ancestors(&self, uri: &str) -> Result<Option<Vec<petgraph::stable_graph::NodeIndex>>> {
fn get_file_toplevel_ancestors(&self, uri: &PathBuf) -> Result<Option<Vec<petgraph::stable_graph::NodeIndex>>> {
let curr_node = match self.graph.borrow_mut().find_node(uri) {
Some(n) => n,
None => return Err(anyhow!("node not found {}", uri)),
None => return Err(anyhow!("node not found {:?}", uri)),
};
let roots = self.graph.borrow().collect_root_ancestors(curr_node);
if roots.is_empty() {
@ -98,20 +98,20 @@ impl VirtualMergedDocument {
dfs.collect::<Result<Vec<_>, _>>()
}
pub fn load_sources(&self, nodes: &[(NodeIndex, Option<NodeIndex>)]) -> Result<HashMap<String, String>> {
pub fn load_sources(&self, nodes: &[(NodeIndex, Option<NodeIndex>)]) -> Result<HashMap<PathBuf, String>> {
let mut sources = HashMap::new();
for node in nodes {
let graph = self.graph.borrow();
let path = graph.get_node(node.0);
if sources.contains_key(path) {
if sources.contains_key(&path) {
continue;
}
let source = match fs::read_to_string(path) {
let source = match fs::read_to_string(&path) {
Ok(s) => s,
Err(e) => return Err(anyhow!("error reading {}: {}", path, e))
Err(e) => return Err(anyhow!("error reading {:?}: {}", path, e))
};
sources.insert(path.clone(), source);
}
@ -121,9 +121,12 @@ impl VirtualMergedDocument {
}
impl Invokeable for VirtualMergedDocument {
fn run_command(&self, root: &str, arguments: Vec<Value>) -> Result<Value, String> {
fn run_command(&self, root: &PathBuf, arguments: Vec<Value>) -> Result<Value, String> {
let path = arguments.get(0).unwrap().to_string();
let path = String::from(path.trim_start_matches('"').trim_end_matches('"'));
let path = percent_encoding::percent_decode_str(
path.trim_start_matches('"').trim_end_matches('"').strip_prefix("/").unwrap()
).decode_utf8().unwrap();
let path = PathBuf::from_str(&path).unwrap();
let file_ancestors = match self.get_file_toplevel_ancestors(&path) {
Ok(opt) => match opt {
@ -136,7 +139,7 @@ impl Invokeable for VirtualMergedDocument {
//eprintln!("ancestors for {}:\n\t{:?}", path, file_ancestors.iter().map(|e| self.graph.borrow().graph.node_weight(*e).unwrap().clone()).collect::<Vec<String>>());
// the set of all filepath->content. TODO: change to Url?
let mut all_sources: HashMap<String, String> = HashMap::new();
let mut all_sources: HashMap<PathBuf, String> = HashMap::new();
// if we are a top-level file (this has to be one of the set defined by Optifine, right?)
if file_ancestors.is_empty() {
@ -157,6 +160,6 @@ impl Invokeable for VirtualMergedDocument {
let view = merge_views::generate_merge_list(&tree, &all_sources, &graph);
return Ok(serde_json::value::Value::String(view));
}
return Err(format!("{} is not a top-level file aka has ancestors", path.trim_start_matches(&(String::from(root) + "/"))))
return Err(format!("{:?} is not a top-level file aka has ancestors", path.strip_prefix(root).unwrap()))
}
}

View file

@ -103,18 +103,18 @@ pub mod error {
use thiserror::Error;
use std::fmt::{Debug, Display};
use std::{fmt::{Debug, Display}, path::PathBuf};
use crate::{graph::CachedStableGraph, consts};
use rust_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range};
#[derive(Debug, Error)]
pub struct CycleError(Vec<String>);
pub struct CycleError(Vec<PathBuf>);
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();
let mut resolved_nodes: Vec<PathBuf> = nodes.iter().map(|i| graph.get_node(*i).clone()).collect();
resolved_nodes.push(graph.get_node(current_node).clone());
CycleError(resolved_nodes)
}
@ -123,11 +123,11 @@ pub mod 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());
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{:?}, which imports ", *p).as_str());
}
disp.push_str(format!("\n{}", self.0[self.0.len()-1]).as_str());
disp.push_str(format!("\n{:?}", self.0[self.0.len()-1]).as_str());
f.write_str(disp.as_str())
}
}

View file

@ -3,7 +3,7 @@ use petgraph::stable_graph::NodeIndex;
use petgraph::Direction;
use petgraph::stable_graph::EdgeIndex;
use std::collections::{HashMap, HashSet};
use std::{collections::{HashMap, HashSet}, path::PathBuf, str::FromStr};
use super::IncludePosition;
@ -14,10 +14,10 @@ pub struct CachedStableGraph {
// StableDiGraph is used as it allows for String node values, essential for
// generating the GraphViz DOT render.
pub graph: StableDiGraph<String, IncludePosition>,
cache: HashMap<String, NodeIndex>,
cache: HashMap<PathBuf, NodeIndex>,
// Maps a node index to its abstracted string representation.
// Mainly used as the graph is based on NodeIndex and
reverse_index: HashMap<NodeIndex, String>,
reverse_index: HashMap<NodeIndex, PathBuf>,
}
impl CachedStableGraph {
@ -33,23 +33,23 @@ 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: &str) -> Option<NodeIndex> {
pub fn find_node(&mut self, name: &PathBuf) -> 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);
let n = self.graph.node_indices().find(|n| self.graph[*n] == name.to_str().unwrap().to_string());
if let Some(n) = n {
self.cache.insert(name.to_string(), n);
self.cache.insert(name.into(), n);
}
n
}
}
}
pub fn get_node(&self, node: NodeIndex) -> &String {
&self.graph[node]
pub fn get_node(&self, node: NodeIndex) -> PathBuf {
PathBuf::from_str(&self.graph[node]).unwrap()
}
pub fn get_edge_meta(&self, parent: NodeIndex, child: NodeIndex) -> &IncludePosition {
@ -57,21 +57,20 @@ impl CachedStableGraph {
}
#[allow(dead_code)]
pub fn remove_node(&mut self, name: &str) {
pub fn remove_node(&mut self, name: &PathBuf) {
let idx = self.cache.remove(name);
if let Some(idx) = idx {
self.graph.remove_node(idx);
}
}
pub fn add_node(&mut self, name: &str) -> NodeIndex {
pub fn add_node(&mut self, name: &PathBuf) -> NodeIndex {
if let Some(idx) = self.cache.get(name) {
return *idx;
}
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);
let idx = self.graph.add_node(name.to_str().unwrap().to_string());
self.cache.insert(name.clone(), idx);
self.reverse_index.insert(idx, name.clone());
idx
}
@ -90,11 +89,11 @@ impl CachedStableGraph {
}
#[allow(dead_code)]
pub fn child_node_names(&self, node: NodeIndex) -> Vec<String> {
pub fn child_node_names(&self, node: NodeIndex) -> Vec<PathBuf> {
self.graph.neighbors(node).map(|n| self.reverse_index.get(&n).unwrap().clone()).collect()
}
pub fn child_node_meta(&self, node: NodeIndex) -> Vec<(String, IncludePosition)> {
pub fn child_node_meta(&self, node: NodeIndex) -> Vec<(PathBuf, IncludePosition)> {
self.graph.neighbors(node).map(|n| {
let edge = self.graph.find_edge(node, n).unwrap();
let edge_meta = self.graph.edge_weight(edge).unwrap();
@ -107,7 +106,7 @@ impl CachedStableGraph {
}
#[allow(dead_code)]
pub fn parent_node_names(&self, node: NodeIndex) -> Vec<String> {
pub fn parent_node_names(&self, node: NodeIndex) -> Vec<PathBuf> {
self.graph.neighbors_directed(node, Direction::Incoming).map(|n| self.reverse_index.get(&n).unwrap().clone()).collect()
}

View file

@ -5,25 +5,25 @@ use rust_lsp::lsp_types::{*, notification::*};
use petgraph::stable_graph::NodeIndex;
use serde_json::Value;
use url_norm::FromUrl;
use walkdir::WalkDir;
use std::cell::RefCell;
use std::{cell::RefCell, ffi::OsString, path::{Path, PathBuf}, str::FromStr};
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::RandomState;
use std::convert::{TryFrom, TryInto};
use std::fmt::{Display, Formatter, Debug};
use std::io::{stdin, stdout, BufRead, BufReader};
use std::ops::Add;
use std::rc::Rc;
use std::fs;
use std::iter::{Extend, FromIterator};
use path_slash::PathBufExt;
use anyhow::{Result, anyhow};
use chan::WaitGroup;
use percent_encoding::percent_decode_str;
use regex::Regex;
use lazy_static::lazy_static;
@ -35,6 +35,7 @@ mod dfs;
mod merge_views;
mod consts;
mod opengl;
mod url_norm;
#[cfg(test)]
mod test;
@ -57,7 +58,7 @@ fn main() {
endpoint: endpoint_output.clone(),
graph: Rc::new(RefCell::new(cache_graph)),
wait: WaitGroup::new(),
root: "".to_string(),
root: "".into(),
command_provider: None,
opengl_context: Rc::new(opengl::OpenGLContext::new())
};
@ -84,7 +85,7 @@ struct MinecraftShaderLanguageServer {
endpoint: Endpoint,
graph: Rc<RefCell<graph::CachedStableGraph>>,
wait: WaitGroup,
root: String,
root: PathBuf,
command_provider: Option<commands::CustomCommandProvider>,
opengl_context: Rc<dyn opengl::ShaderValidator>
}
@ -132,7 +133,7 @@ impl MinecraftShaderLanguageServer {
}
pub fn gen_initial_graph(&self) {
eprintln!("root of project is {}", self.root);
eprintln!("root of project is {:?}", self.root);
// filter directories and files not ending in any of the 3 extensions
WalkDir::new(&self.root).into_iter().filter_map(|entry| {
@ -155,7 +156,7 @@ impl MinecraftShaderLanguageServer {
return None;
}
Some(String::from(path.to_str().unwrap()))
Some(entry.into_path())
}).for_each(|path| {
// iterate all valid found files, search for includes, add a node into the graph for each
// file and add a file->includes KV into the map
@ -166,10 +167,10 @@ impl MinecraftShaderLanguageServer {
//std::thread::sleep(std::time::Duration::from_secs(1));
}
fn add_file_and_includes_to_graph(&self, path: &str) {
fn add_file_and_includes_to_graph(&self, path: &PathBuf) {
let includes = self.find_includes(path);
let idx = self.graph.borrow_mut().add_node(path);
let idx = self.graph.borrow_mut().add_node(&path);
//eprintln!("adding {} with\n{:?}", path.clone(), includes);
for include in includes {
@ -177,12 +178,12 @@ impl MinecraftShaderLanguageServer {
}
}
fn add_include(&self, include: (String, IncludePosition), node: NodeIndex) {
fn add_include(&self, include: (PathBuf, IncludePosition), node: NodeIndex) {
let child = self.graph.borrow_mut().add_node(&include.0);
self.graph.borrow_mut().add_edge(node, child, include.1);
}
pub fn find_includes(&self, file: &str) -> Vec<(String, IncludePosition)> {
pub fn find_includes(&self, file: &PathBuf) -> Vec<(PathBuf, IncludePosition)> {
let mut includes = Vec::default();
let buf = BufReader::new(std::fs::File::open(file).unwrap());
@ -204,10 +205,12 @@ impl MinecraftShaderLanguageServer {
let start = cap.start();
let end = cap.end();
let mut path: String = cap.as_str().into();
if !path.starts_with('/') {
path.insert(0, '/');
// TODO: difference between / and not
if path.starts_with('/') {
path = path.strip_prefix('/').unwrap().to_string();
}
let full_include = String::from(&self.root).add("/shaders").add(path.as_str());
let full_include = self.root.join("shaders").join(PathBuf::from_slash(&path));
includes.push((
full_include,
IncludePosition {
@ -222,18 +225,18 @@ impl MinecraftShaderLanguageServer {
includes
}
fn update_includes(&self, file: &str) {
fn update_includes(&self, file: &PathBuf) {
let includes = self.find_includes(file);
let idx = match self.graph.borrow_mut().find_node(file) {
let idx = match self.graph.borrow_mut().find_node(&file) {
None => {
return
},
Some(n) => n,
};
let prev_children: HashSet<(std::string::String, IncludePosition), RandomState> = HashSet::from_iter(self.graph.borrow().child_node_meta(idx));
let new_children: HashSet<(std::string::String, IncludePosition), RandomState> = HashSet::from_iter(includes.iter().map(|e| e.clone()));
let prev_children: HashSet<_, RandomState> = HashSet::from_iter(self.graph.borrow().child_node_meta(idx));
let new_children: HashSet<_, RandomState> = HashSet::from_iter(includes.iter().map(|e| e.clone()));
let to_be_added = new_children.difference(&prev_children);
let to_be_removed = prev_children.difference(&new_children);
@ -248,7 +251,7 @@ impl MinecraftShaderLanguageServer {
}
}
pub fn lint(&self, uri: &str) -> Result<HashMap<Url, Vec<Diagnostic>>> {
pub fn lint(&self, uri: &PathBuf) -> 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 {
@ -258,15 +261,15 @@ impl MinecraftShaderLanguageServer {
Err(e) => return Err(e),
};
eprintln!("ancestors for {}:\n\t{:?}", uri, file_ancestors.iter().map(|e| self.graph.borrow().graph.node_weight(*e).unwrap().clone()).collect::<Vec<String>>());
eprintln!("ancestors for {:?}:\n\t{:?}", uri, file_ancestors.iter().map(|e| PathBuf::from_str(&self.graph.borrow().graph.node_weight(*e).unwrap().clone()).unwrap()).collect::<Vec<PathBuf>>());
// the set of all filepath->content. TODO: change to Url?
let mut all_sources: HashMap<String, String> = HashMap::new();
let mut all_sources: HashMap<PathBuf, String> = HashMap::new();
// the set of filepath->list of diagnostics to report
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = HashMap::new();
// we want to backfill the diagnostics map with all linked sources
let back_fill = |all_sources: &HashMap<String, String>, diagnostics: &mut HashMap<Url, Vec<Diagnostic>>| {
let back_fill = |all_sources, diagnostics: &mut HashMap<Url, Vec<Diagnostic>>| {
for (path, _) in all_sources {
diagnostics.entry(Url::from_file_path(path).unwrap()).or_default();
}
@ -275,7 +278,7 @@ impl MinecraftShaderLanguageServer {
// if we are a top-level file (this has to be one of the set defined by Optifine, right?)
if file_ancestors.is_empty() {
// gather the list of all descendants
let root = self.graph.borrow_mut().find_node(uri).unwrap();
let root = self.graph.borrow_mut().find_node(&uri).unwrap();
let tree = match self.get_dfs_for_node(root) {
Ok(tree) => tree,
Err(e) => {
@ -292,14 +295,14 @@ impl MinecraftShaderLanguageServer {
};
let root_path = self.graph.borrow().get_node(root).clone();
let tree_type = if root_path.ends_with(".fsh") {
let tree_type = if root_path.extension().unwrap() == "fsh" {
TreeType::Fragment
} else if root_path.ends_with(".vsh") {
} else if root_path.extension().unwrap() == "vsh" {
TreeType::Vertex
} else if root_path.ends_with(".gsh") {
} else if root_path.extension().unwrap() == "gsh" {
TreeType::Geometry
} else {
eprintln!("got a non fsh|vsh as a file root ancestor: {}", root_path);
eprintln!("got a non fsh|vsh ({:?}) as a file root ancestor: {:?}", root_path.extension().unwrap(), root_path);
back_fill(&all_sources, &mut diagnostics);
return Ok(diagnostics)
};
@ -326,14 +329,14 @@ impl MinecraftShaderLanguageServer {
};
let root_path = self.graph.borrow().get_node(*root).clone();
let tree_type = if root_path.ends_with(".fsh") {
let tree_type = if root_path.extension().unwrap() == "fsh" {
TreeType::Fragment
} else if root_path.ends_with(".vsh") {
} else if root_path.extension().unwrap() == "vsh" {
TreeType::Vertex
} else if root_path.ends_with(".gsh") {
} else if root_path.extension().unwrap() == "gsh" {
TreeType::Geometry
} else {
eprintln!("got a non fsh|vsh as a file root ancestor: {}", root_path);
eprintln!("got a non fsh|vsh ({:?}) as a file root ancestor: {:?}", root_path.extension().unwrap(), root_path);
continue;
};
@ -360,7 +363,7 @@ impl MinecraftShaderLanguageServer {
Ok(diagnostics)
}
fn parse_validator_stdout(&self, uri: &str, stdout: String, _source: &str) -> HashMap<Url, Vec<Diagnostic>> {
fn parse_validator_stdout(&self, uri: &PathBuf, 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');
@ -399,12 +402,12 @@ impl MinecraftShaderLanguageServer {
let origin = match diagnostic_capture.name("filepath") {
Some(o) => {
if o.as_str().to_string() == "0" {
uri.to_string()
uri.to_str().unwrap().to_string()
} else {
o.as_str().to_string()
}
},
None => uri.to_string(),
None => uri.to_str().unwrap().to_string(),
};
let diagnostic = Diagnostic {
@ -443,20 +446,20 @@ impl MinecraftShaderLanguageServer {
dfs.collect::<Result<Vec<_>, _>>()
}
pub fn load_sources(&self, nodes: &[(NodeIndex, Option<NodeIndex>)]) -> Result<HashMap<String, String>> {
pub fn load_sources(&self, nodes: &[(NodeIndex, Option<NodeIndex>)]) -> Result<HashMap<PathBuf, String>> {
let mut sources = HashMap::new();
for node in nodes {
let graph = self.graph.borrow();
let path = graph.get_node(node.0);
if sources.contains_key(path) {
if sources.contains_key(&path) {
continue;
}
let source = match fs::read_to_string(path) {
let source = match fs::read_to_string(&path) {
Ok(s) => s,
Err(e) => return Err(anyhow!("error reading {}: {}", path, e))
Err(e) => return Err(anyhow!("error reading {:?}: {}", path, e))
};
sources.insert(path.clone(), source);
}
@ -464,10 +467,10 @@ impl MinecraftShaderLanguageServer {
Ok(sources)
}
fn get_file_toplevel_ancestors(&self, uri: &str) -> Result<Option<Vec<petgraph::stable_graph::NodeIndex>>> {
fn get_file_toplevel_ancestors(&self, uri: &PathBuf) -> Result<Option<Vec<petgraph::stable_graph::NodeIndex>>> {
let curr_node = match self.graph.borrow_mut().find_node(uri) {
Some(n) => n,
None => return Err(anyhow!("node not found {}", uri)),
None => return Err(anyhow!("node not found {:?}", uri)),
};
let roots = self.graph.borrow().collect_root_ancestors(curr_node);
if roots.is_empty() {
@ -526,8 +529,8 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer {
},
));
let root_path: String = match params.root_uri {
Some(uri) => uri.path().into(),
let root = match params.root_uri {
Some(uri) => PathBuf::from_url(uri),
None => {
completable.complete(Err(MethodError {
code: 42069,
@ -547,14 +550,6 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer {
self.set_status("loading", "Building dependency graph...", "$(loading~spin)");
let root: String = match percent_decode_str(root_path.as_ref()).decode_utf8() {
Ok(s) => s.into(),
Err(e) => {
self.set_status("failed", format!("{}", e), "$(close)");
return
},
};
self.root = root;
self.gen_initial_graph();
@ -581,10 +576,11 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer {
fn did_open_text_document(&mut self, params: DidOpenTextDocumentParams) {
//eprintln!("opened doc {}", params.text_document.uri);
if self.graph.borrow_mut().find_node(params.text_document.uri.path()) == None {
self.add_file_and_includes_to_graph(params.text_document.uri.path());
let path = PathBuf::from_url(params.text_document.uri);
if self.graph.borrow_mut().find_node(&path) == None {
self.add_file_and_includes_to_graph(&path);
}
match self.lint(params.text_document.uri.path()/* , params.text_document.text */) {
match self.lint(&path) {
Ok(diagnostics) => self.publish_diagnostic(diagnostics, None),
Err(e) => eprintln!("error linting: {}", e),
}
@ -597,11 +593,10 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer {
fn did_save_text_document(&mut self, params: DidSaveTextDocumentParams) {
eprintln!("saved doc {}", params.text_document.uri);
let path: String = percent_encoding::percent_decode_str(params.text_document.uri.path()).decode_utf8().unwrap().into();
let path = PathBuf::from_url(params.text_document.uri);
self.update_includes(&path);
match self.lint(path.as_str()) {
match self.lint(&path) {
Ok(diagnostics) => self.publish_diagnostic(diagnostics, None),
Err(e) => eprintln!("error linting: {}", e),
}
@ -692,11 +687,7 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer {
.text_document
.uri
.to_file_path()
.unwrap()
.as_os_str()
.to_str()
.unwrap()
.to_string();
.unwrap();
let node = match self.graph.borrow_mut().find_node(&curr_doc) {
Some(n) => n,
None => {
@ -713,9 +704,8 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer {
.filter_map(|child| {
let graph = self.graph.borrow();
let value = graph.get_edge_meta(node, child);
let path: std::ffi::OsString = graph.get_node(child).try_into().unwrap();
let path = std::path::Path::new(&path);
let url = match Url::from_file_path(path) {
let path = graph.get_node(child);
let url = match Url::from_file_path(&path) {
Ok(url) => url,
Err(e) => {
eprintln!("error converting {:?} into url: {:?}", path, e);
@ -737,8 +727,7 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer {
tooltip: None,
data: None,
})
})
.collect();
}).collect();
eprintln!("links: {:?}", edges);
completable.complete(Ok(edges));
}

View file

@ -1,4 +1,4 @@
use std::collections::{HashMap, LinkedList, VecDeque};
use std::{collections::{HashMap, LinkedList, VecDeque}, path::PathBuf};
use std::iter::Peekable;
use std::cmp::min;
@ -10,7 +10,7 @@ use crate::graph::CachedStableGraph;
pub fn generate_merge_list<'a>(
nodes: &'a [(NodeIndex, Option<NodeIndex>)],
sources: &'a HashMap<String, String>,
sources: &'a HashMap<PathBuf, String>,
graph: &'a CachedStableGraph
) -> String {
let mut line_directives: Vec<String> = Vec::new();
@ -20,7 +20,7 @@ pub fn generate_merge_list<'a>(
line_directives.reserve(nodes.len() * 2);
let mut last_offset_set: HashMap<String, usize> = HashMap::new();
let mut last_offset_set: HashMap<PathBuf, usize> = HashMap::new();
let mut nodes_iter = nodes.iter().peekable();
@ -29,10 +29,16 @@ pub fn generate_merge_list<'a>(
last_offset_set.insert(first_path.clone(), 0);
let line_ending_offset = if is_crlf(sources.get(&first_path).unwrap()) {
2
} else {
1
};
// stack to keep track of the depth first traversal
let mut stack = VecDeque::<NodeIndex>::new();
create_merge_views(&mut nodes_iter, &mut merge_list, &mut last_offset_set, graph, sources, &mut line_directives, &mut stack);
create_merge_views(&mut nodes_iter, &mut merge_list, &mut last_offset_set, graph, sources, &mut line_directives, &mut stack, line_ending_offset);
// now we add a view of the remainder of the root file
let offset = *last_offset_set.get(&first_path).unwrap();
@ -52,14 +58,19 @@ pub fn generate_merge_list<'a>(
merged
}
fn is_crlf(source: &String) -> bool {
source.contains("\r\n")
}
fn create_merge_views<'a>(
nodes: &mut Peekable<Iter<(NodeIndex, Option<NodeIndex>)>>,
merge_list: &mut LinkedList<&'a str>,
last_offset_set: &mut HashMap<String, usize>,
last_offset_set: &mut HashMap<PathBuf, usize>,
graph: &'a CachedStableGraph,
sources: &'a HashMap<String, String>,
sources: &'a HashMap<PathBuf, String>,
line_directives: &mut Vec<String>,
stack: &mut VecDeque<NodeIndex>,
line_ending_offset: usize,
) {
loop {
@ -75,7 +86,7 @@ fn create_merge_views<'a>(
let child_path = graph.get_node(child).clone();
let parent_source = sources.get(&parent_path).unwrap();
let (char_for_line, char_following_line) = char_offset_for_line(edge.line, parent_source);
let (char_for_line, char_following_line) = char_offset_for_line(edge.line, parent_source, line_ending_offset);
let offset = *last_offset_set.insert(parent_path.clone(), char_following_line).get_or_insert(0);
merge_list.push_back(&parent_source[offset..char_for_line]);
@ -90,7 +101,7 @@ fn create_merge_views<'a>(
// if ends in \n\n, we want to exclude the last \n for some reason. Ask optilad
let offset = {
match child_source.ends_with("\n") {
true => child_source.len()-1,
true => child_source.len()-line_ending_offset,
false => child_source.len(),
}
};
@ -106,7 +117,7 @@ fn create_merge_views<'a>(
}
stack.push_back(parent);
create_merge_views(nodes, merge_list, last_offset_set, graph, sources, line_directives, stack);
create_merge_views(nodes, merge_list, last_offset_set, graph, sources, line_directives, stack, line_ending_offset);
stack.pop_back();
let offset = *last_offset_set.get(&child_path).unwrap();
@ -114,7 +125,7 @@ fn create_merge_views<'a>(
// this evaluates to false once the file contents have been exhausted aka offset = child_source.len() + 1
let end_offset = {
match child_source.ends_with("\n") {
true => 1/* child_source.len()-1 */,
true => line_ending_offset/* child_source.len()-1 */,
false => 0/* child_source.len() */,
}
};
@ -137,7 +148,7 @@ fn create_merge_views<'a>(
// if ends in \n\n, we want to exclude the last \n for some reason. Ask optilad
let offset = {
match child_source.ends_with("\n") {
true => child_source.len()-1,
true => child_source.len()-line_ending_offset,
false => child_source.len(),
}
};
@ -152,36 +163,36 @@ fn create_merge_views<'a>(
// 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(line_num: usize, source: &str) -> (usize, usize) {
fn char_offset_for_line(line_num: usize, source: &str, line_ending_offset: usize) -> (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;
char_following_line += line.len()+line_ending_offset;
break;
}
char_for_line += line.len()+1;
char_for_line += line.len()+line_ending_offset;
char_following_line = char_for_line;
}
(char_for_line, char_following_line)
}
fn add_opening_line_directive(path: &str, merge_list: &mut LinkedList<&str>, line_directives: &mut Vec<String>) {
let line_directive = format!("#line 1 \"{}\"\n", path);
fn add_opening_line_directive(path: &PathBuf, merge_list: &mut LinkedList<&str>, line_directives: &mut Vec<String>) {
let line_directive = format!("#line 1 \"{}\"\n", path.to_str().unwrap().replace("\\", "\\\\"));
line_directives.push(line_directive);
unsafe_get_and_insert(merge_list, line_directives);
}
fn add_closing_line_directive(line: usize, path: &str, merge_list: &mut LinkedList<&str>, line_directives: &mut Vec<String>) {
fn add_closing_line_directive(line: usize, path: &PathBuf, merge_list: &mut LinkedList<&str>, line_directives: &mut Vec<String>) {
// 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)
format!("#line {} \"{}\"\n", line, path.to_str().unwrap().replace("\\", "\\\\"))
} else {
format!("\n#line {} \"{}\"\n", line, path)
format!("\n#line {} \"{}\"\n", line, path.to_str().unwrap().replace("\\", "\\\\"))
}
} else {
format!("\n#line {} \"{}\"\n", line, path)
format!("\n#line {} \"{}\"\n", line, path.to_str().unwrap().replace("\\", "\\\\"))
};
line_directives.push(line_directive);

View file

@ -4,6 +4,7 @@ use std::io;
use std::io::Result;
use hamcrest2::prelude::*;
use pretty_assertions::assert_eq;
use tempdir::TempDir;
@ -42,7 +43,7 @@ fn new_temp_server() -> MinecraftShaderLanguageServer {
endpoint,
graph: Rc::new(RefCell::new(graph::CachedStableGraph::new())),
wait: WaitGroup::new(),
root: "".to_string(),
root: "".into(),
command_provider: None,
opengl_context: Rc::new(opengl::MockShaderValidator::new()),
}
@ -52,30 +53,27 @@ fn copy_files(files: &str, dest: &TempDir) {
let opts = &dir::CopyOptions::new();
let files = fs::read_dir(files)
.unwrap()
.map(|e| String::from(e.unwrap().path().as_os_str().to_str().unwrap()))
.map(|e| String::from(e.unwrap().path().to_str().unwrap()))
.collect::<Vec<String>>();
copy_items(&files, dest.path().join("shaders"), opts).unwrap();
}
fn copy_to_and_set_root(
test_path: &str,
server: &mut MinecraftShaderLanguageServer,
) -> (Rc<TempDir>, String) {
fn copy_to_and_set_root(test_path: &str, server: &mut MinecraftShaderLanguageServer,) -> (Rc<TempDir>, PathBuf) {
let (_tmp_dir, tmp_path) = copy_to_tmp_dir(test_path);
server.root = format!("{}{}", "file://", tmp_path);
server.root = tmp_path.clone();//format!("{}{}", "file://", tmp_path);
(_tmp_dir, tmp_path)
}
fn copy_to_tmp_dir(test_path: &str) -> (Rc<TempDir>, String) {
fn copy_to_tmp_dir(test_path: &str) -> (Rc<TempDir>, PathBuf) {
let tmp_dir = Rc::new(TempDir::new("mcshader").unwrap());
fs::create_dir(tmp_dir.path().join("shaders")).unwrap();
copy_files(test_path, &tmp_dir);
let tmp_clone = tmp_dir.clone();
let tmp_path = tmp_clone.path().as_os_str().to_str().unwrap();
let tmp_path = tmp_clone.path().to_str().unwrap();
(tmp_dir, tmp_path.into())
}
@ -86,13 +84,12 @@ fn test_empty_initialize() {
let mut server = new_temp_server();
let tmp_dir = TempDir::new("mcshader").unwrap();
let tmp_path = tmp_dir.path().as_os_str().to_str().unwrap();
let tmp_uri = format!("{}{}", "file://", tmp_path);
let tmp_path = tmp_dir.path();
let initialize_params = InitializeParams {
process_id: None,
root_path: None,
root_uri: Some(Url::parse(tmp_uri.as_str()).unwrap()),
root_uri: Some(Url::from_directory_path(tmp_path.clone()).unwrap()),
client_info: None,
initialization_options: None,
capabilities: ClientCapabilities {
@ -124,7 +121,7 @@ fn test_empty_initialize() {
));
server.initialize(initialize_params, completable);
assert_eq!(server.root, String::from(tmp_path));
assert_eq!(server.root, tmp_path);
assert_eq!(server.graph.borrow().graph.edge_count(), 0);
assert_eq!(server.graph.borrow().graph.node_count(), 0);
@ -144,7 +141,7 @@ fn test_01_initialize() {
let initialize_params = InitializeParams {
process_id: None,
root_path: None,
root_uri: Some(Url::parse(format!("{}{}", "file://", tmp_path).as_str()).unwrap()),
root_uri: Some(Url::from_directory_path(tmp_path.clone()).unwrap()),
client_info: None,
initialization_options: None,
capabilities: ClientCapabilities {
@ -175,6 +172,7 @@ fn test_01_initialize() {
Box::new(on_response),
));
server.initialize(initialize_params, completable);
server.endpoint.request_shutdown();
// Assert there is one edge between two nodes
assert_eq!(server.graph.borrow().graph.edge_count(), 1);
@ -185,27 +183,27 @@ fn test_01_initialize() {
// Assert the values of the two nodes in the tree
assert_eq!(
server.graph.borrow().graph[node1],
format!("{}/{}/{}", tmp_path, "shaders", "final.fsh")
//format!("{:?}/{}/{}", tmp_path, "shaders", "final.fsh")
tmp_path.join("shaders").join("final.fsh").to_str().unwrap().to_string()
);
assert_eq!(
server.graph.borrow().graph[node2],
format!("{}/{}/{}", tmp_path, "shaders", "common.glsl")
//format!("{:?}/{}/{}", tmp_path, "shaders", "common.glsl")
tmp_path.join("shaders").join("common.glsl").to_str().unwrap().to_string()
);
assert_eq!(
server.graph.borrow().graph.edge_weight(edge).unwrap().line,
2
);
server.endpoint.request_shutdown();
}
#[test]
fn test_graph_two_connected_nodes() {
let mut graph = graph::CachedStableGraph::new();
let idx1 = graph.add_node("sample");
let idx2 = graph.add_node("banana");
let idx1 = graph.add_node(&("sample".to_string().into()));
let idx2 = graph.add_node(&("banana".to_string().into()));
graph.add_edge(
idx1,
idx2,
@ -218,7 +216,7 @@ fn test_graph_two_connected_nodes() {
let children = graph.child_node_names(idx1);
assert_eq!(children.len(), 1);
assert_eq!(children[0], "banana");
assert_eq!(children[0], Into::<PathBuf>::into("banana".to_string()));
let children = graph.child_node_indexes(idx1);
assert_eq!(children.len(), 1);
@ -229,7 +227,7 @@ fn test_graph_two_connected_nodes() {
let parents = graph.parent_node_names(idx2);
assert_eq!(parents.len(), 1);
assert_eq!(parents[0], "sample");
assert_eq!(parents[0], Into::<PathBuf>::into("sample".to_string()));
let parents = graph.parent_node_indexes(idx2);
assert_eq!(parents.len(), 1);
@ -242,9 +240,9 @@ fn test_graph_two_connected_nodes() {
let ancestors = graph.collect_root_ancestors(idx1);
assert_eq!(ancestors.len(), 0);
graph.remove_node("sample");
graph.remove_node(&("sample".to_string().into()));
assert_eq!(graph.graph.node_count(), 1);
assert!(graph.find_node("sample").is_none());
assert!(graph.find_node(&("sample".to_string().into())).is_none());
let neighbors = graph.child_node_names(idx2);
assert_eq!(neighbors.len(), 0);
}
@ -254,10 +252,10 @@ fn test_collect_root_ancestors() {
{
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");
let idx0 = graph.add_node(&("0".to_string().into()));
let idx1 = graph.add_node(&("1".to_string().into()));
let idx2 = graph.add_node(&("2".to_string().into()));
let idx3 = graph.add_node(&("3".to_string().into()));
graph.add_edge(
idx0,
@ -308,10 +306,10 @@ fn test_collect_root_ancestors() {
{
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");
let idx0 = graph.add_node(&("0".to_string().into()));
let idx1 = graph.add_node(&("1".to_string().into()));
let idx2 = graph.add_node(&("2".to_string().into()));
let idx3 = graph.add_node(&("3".to_string().into()));
graph.add_edge(
idx0,
@ -362,10 +360,10 @@ fn test_collect_root_ancestors() {
{
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");
let idx0 = graph.add_node(&("0".to_string().into()));
let idx1 = graph.add_node(&("1".to_string().into()));
let idx2 = graph.add_node(&("2".to_string().into()));
let idx3 = graph.add_node(&("3".to_string().into()));
graph.add_edge(
idx0,
@ -418,10 +416,10 @@ fn test_collect_root_ancestors() {
{
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");
let idx0 = graph.add_node(&("0".to_string().into()));
let idx1 = graph.add_node(&("1".to_string().into()));
let idx2 = graph.add_node(&("2".to_string().into()));
let idx3 = graph.add_node(&("3".to_string().into()));
graph.add_edge(
idx0,
@ -476,10 +474,10 @@ fn test_graph_dfs() {
{
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");
let idx0 = graph.add_node(&("0".to_string().into()));
let idx1 = graph.add_node(&("1".to_string().into()));
let idx2 = graph.add_node(&("2".to_string().into()));
let idx3 = graph.add_node(&("3".to_string().into()));
graph.add_edge(
idx0,
@ -538,14 +536,14 @@ fn test_graph_dfs() {
{
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");
let idx4 = graph.add_node("4");
let idx5 = graph.add_node("5");
let idx6 = graph.add_node("6");
let idx7 = graph.add_node("7");
let idx0 = graph.add_node(&("0".to_string().into()));
let idx1 = graph.add_node(&("1".to_string().into()));
let idx2 = graph.add_node(&("2".to_string().into()));
let idx3 = graph.add_node(&("3".to_string().into()));
let idx4 = graph.add_node(&("4".to_string().into()));
let idx5 = graph.add_node(&("5".to_string().into()));
let idx6 = graph.add_node(&("6".to_string().into()));
let idx7 = graph.add_node(&("7".to_string().into()));
graph.add_edge(
idx0,
@ -680,14 +678,14 @@ fn test_graph_dfs_cycle() {
{
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");
let idx4 = graph.add_node("4");
let idx5 = graph.add_node("5");
let idx6 = graph.add_node("6");
let idx7 = graph.add_node("7");
let idx0 = graph.add_node(&("0".to_string().into()));
let idx1 = graph.add_node(&("1".to_string().into()));
let idx2 = graph.add_node(&("2".to_string().into()));
let idx3 = graph.add_node(&("3".to_string().into()));
let idx4 = graph.add_node(&("4".to_string().into()));
let idx5 = graph.add_node(&("5".to_string().into()));
let idx6 = graph.add_node(&("6".to_string().into()));
let idx7 = graph.add_node(&("7".to_string().into()));
graph.add_edge(
idx0,
@ -804,8 +802,8 @@ fn test_graph_dfs_cycle() {
{
let mut graph = graph::CachedStableGraph::new();
let idx0 = graph.add_node("0");
let idx1 = graph.add_node("1");
let idx0 = graph.add_node(&("0".to_string().into()));
let idx1 = graph.add_node(&("1".to_string().into()));
graph.add_edge(
idx0,
@ -839,11 +837,14 @@ fn test_generate_merge_list_01() {
let mut server = new_temp_server();
let (_tmp_dir, tmp_path) = copy_to_and_set_root("./testdata/01", &mut server);
server.endpoint.request_shutdown();
let final_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/{}", tmp_path, "final.fsh"));
//.add_node(&format!("{:?}/shaders/final.fsh", tmp_path).try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("final.fsh"));
let common_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/{}", tmp_path, "common.glsl"));
//.add_node(&format!("{:?}/shaders/common.glsl", tmp_path).try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("common.glsl"));
server.graph.borrow_mut().add_edge(
final_idx,
@ -861,15 +862,13 @@ fn test_generate_merge_list_01() {
let graph_borrow = server.graph.borrow();
let result = merge_views::generate_merge_list(&nodes, &sources, &graph_borrow);
let merge_file = tmp_path.clone() + "/shaders/final.fsh.merge";
let merge_file = tmp_path.clone().join( "shaders").join("final.fsh.merge");
let mut truth = fs::read_to_string::<String>(merge_file).unwrap();
truth = truth.replacen("!!", &(tmp_path.clone() + "/shaders/" + "common.glsl"), 1);
truth = truth.replace("!!", &(tmp_path + "/shaders/" + "final.fsh"));
let mut truth = fs::read_to_string(merge_file).unwrap();
truth = truth.replacen("!!", &tmp_path.clone().join("shaders").join("common.glsl").to_str().unwrap().replace("\\", "\\\\"), 1);
truth = truth.replace("!!", &tmp_path.join("shaders").join("final.fsh").to_str().unwrap().replace("\\", "\\\\"));
server.endpoint.request_shutdown();
assert_that!(result, eq(truth));
assert_eq!(result, truth);
}
#[test]
@ -877,15 +876,20 @@ fn test_generate_merge_list_02() {
let mut server = new_temp_server();
let (_tmp_dir, tmp_path) = copy_to_and_set_root("./testdata/02", &mut server);
server.endpoint.request_shutdown();
let final_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/{}", tmp_path, "final.fsh"));
//.add_node(&format!("{}/shaders/{}", tmp_path, "final.fsh").try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("final.fsh"));
let test_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/utils/{}", tmp_path, "test.glsl"));
//.add_node(&format!("{}/shaders/utils/{}", tmp_path, "test.glsl").try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("utils").join("test.glsl"));
let burger_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/utils/{}", tmp_path, "burger.glsl"));
//.add_node(&format!("{}/shaders/utils/{}", tmp_path, "burger.glsl").try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("utils").join("burger.glsl"));
let sample_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/utils/{}", tmp_path, "sample.glsl"));
//.add_node(&format!("{}/shaders/utils/{}", tmp_path, "sample.glsl").try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("utils").join("sample.glsl"));
server.graph.borrow_mut().add_edge(
final_idx,
@ -921,9 +925,9 @@ fn test_generate_merge_list_02() {
let graph_borrow = server.graph.borrow();
let result = merge_views::generate_merge_list(&nodes, &sources, &graph_borrow);
let merge_file = tmp_path.clone() + "/shaders/final.fsh.merge";
let merge_file = tmp_path.clone().join("shaders").join("final.fsh.merge");
let mut truth = fs::read_to_string::<String>(merge_file).unwrap();
let mut truth = fs::read_to_string(merge_file).unwrap();
for file in &[
"sample.glsl",
@ -933,13 +937,11 @@ fn test_generate_merge_list_02() {
"sample.glsl",
] {
let path = tmp_path.clone();
truth = truth.replacen("!!", &format!("{}/shaders/utils/{}", path, file), 1);
truth = truth.replacen("!!", &&path.join("shaders").join("utils").join(file).to_str().unwrap().replace("\\", "\\\\"), 1);
}
truth = truth.replacen("!!", &(tmp_path + "/shaders/final.fsh"), 1);
truth = truth.replacen("!!", &&tmp_path.join("shaders").join("final.fsh").to_str().unwrap().replace("\\", "\\\\"), 1);
assert_that!(result, eq(truth));
server.endpoint.request_shutdown();
assert_eq!(result, truth);
}
#[test]
@ -947,15 +949,20 @@ fn test_generate_merge_list_03() {
let mut server = new_temp_server();
let (_tmp_dir, tmp_path) = copy_to_and_set_root("./testdata/03", &mut server);
server.endpoint.request_shutdown();
let final_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/{}", tmp_path, "final.fsh"));
//.add_node(&format!("{}/shaders/{}", tmp_path, "final.fsh").try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("final.fsh"));
let test_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/utils/{}", tmp_path, "test.glsl"));
//.add_node(&format!("{}/shaders/utils/{}", tmp_path, "test.glsl").try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("utils").join("test.glsl"));
let burger_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/utils/{}", tmp_path, "burger.glsl"));
//.add_node(&format!("{}/shaders/utils/{}", tmp_path, "burger.glsl").try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("utils").join("burger.glsl"));
let sample_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/utils/{}", tmp_path, "sample.glsl"));
//.add_node(&format!("{}/shaders/utils/{}", tmp_path, "sample.glsl").try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("utils").join("sample.glsl"));
server.graph.borrow_mut().add_edge(
final_idx,
@ -991,9 +998,9 @@ fn test_generate_merge_list_03() {
let graph_borrow = server.graph.borrow();
let result = merge_views::generate_merge_list(&nodes, &sources, &graph_borrow);
let merge_file = tmp_path.clone() + "/shaders/final.fsh.merge";
let merge_file = tmp_path.clone().join("shaders").join("final.fsh.merge");
let mut truth = fs::read_to_string::<String>(merge_file).unwrap();
let mut truth = fs::read_to_string(merge_file).unwrap();
for file in &[
"sample.glsl",
@ -1003,13 +1010,11 @@ fn test_generate_merge_list_03() {
"sample.glsl",
] {
let path = tmp_path.clone();
truth = truth.replacen("!!", &format!("{}/shaders/utils/{}", path, file), 1);
truth = truth.replacen("!!", &&&path.join("shaders").join("utils").join(file).to_str().unwrap().replace("\\", "\\\\"), 1);
}
truth = truth.replacen("!!", &(tmp_path + "/shaders/final.fsh"), 1);
truth = truth.replacen("!!", &&&tmp_path.join("shaders").join("final.fsh").to_str().unwrap().replace("\\", "\\\\"), 1);
assert_that!(result, eq(truth));
server.endpoint.request_shutdown();
assert_eq!(result, truth);
}
#[test]
@ -1017,17 +1022,23 @@ fn test_generate_merge_list_04() {
let mut server = new_temp_server();
let (_tmp_dir, tmp_path) = copy_to_and_set_root("./testdata/04", &mut server);
server.endpoint.request_shutdown();
let final_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/{}", tmp_path, "final.fsh"));
//.add_node(&format!("{}/shaders/{}", tmp_path, "final.fsh").try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("final.fsh"));
let utilities_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/utils/{}", tmp_path, "utilities.glsl"));
//.add_node(&format!("{}/shaders/utils/{}", tmp_path, "utilities.glsl").try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("utils").join("utilities.glsl"));
let stuff1_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/utils/{}", tmp_path, "stuff1.glsl"));
//.add_node(&format!("{}/shaders/utils/{}", tmp_path, "stuff1.glsl").try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("utils").join("stuff1.glsl"));
let stuff2_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/utils/{}", tmp_path, "stuff2.glsl"));
//.add_node(&format!("{}/shaders/utils/{}", tmp_path, "stuff2.glsl").try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("utils").join("stuff2.glsl"));
let matrices_idx = server.graph.borrow_mut()
.add_node(&format!("{}/shaders/lib/{}", tmp_path, "matrices.glsl"));
//.add_node(&format!("{}/shaders/lib/{}", tmp_path, "matrices.glsl").try_into().unwrap());
.add_node(&tmp_path.join("shaders").join("lib").join("matrices.glsl"));
server.graph.borrow_mut().add_edge(
final_idx,
@ -1072,25 +1083,24 @@ fn test_generate_merge_list_04() {
let graph_borrow = server.graph.borrow();
let result = merge_views::generate_merge_list(&nodes, &sources, &graph_borrow);
let merge_file = tmp_path.clone() + "/shaders/final.fsh.merge";
let merge_file = tmp_path.clone().join("shaders").join("final.fsh.merge");
let mut truth = fs::read_to_string::<String>(merge_file).unwrap();
let mut truth = fs::read_to_string(merge_file).unwrap();
for file in &[
"utils/utilities.glsl",
"utils/stuff1.glsl",
"utils/utilities.glsl",
"utils/stuff2.glsl",
"utils/utilities.glsl",
"final.fsh",
"lib/matrices.glsl",
"final.fsh"
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(),
PathBuf::new().join("utils").join("stuff2.glsl").to_str().unwrap(),
PathBuf::new().join("utils").join("utilities.glsl").to_str().unwrap(),
PathBuf::new().join("final.fsh").to_str().unwrap(),
PathBuf::new().join("lib").join("matrices.glsl").to_str().unwrap(),
PathBuf::new().join("final.fsh").to_str().unwrap()
] {
let path = tmp_path.clone();
truth = truth.replacen("!!", &format!("{}/shaders/{}", path, file), 1);
//path.f
truth = truth.replacen("!!", &path.join("shaders").join(file).to_str().unwrap().replace("\\", "\\\\"), 1);
}
server.endpoint.request_shutdown();
assert_that!(result, eq(truth));
assert_eq!(result, truth);
}

22
server/src/url_norm.rs Normal file
View file

@ -0,0 +1,22 @@
use std::path::PathBuf;
use path_slash::PathBufExt;
use url::Url;
pub trait FromUrl {
fn from_url(u: Url) -> Self;
}
impl FromUrl for PathBuf {
#[cfg(target_family = "windows")]
fn from_url(u: Url) -> Self {
let path = percent_encoding::percent_decode_str(u.path().strip_prefix("/").unwrap()).decode_utf8().unwrap();
PathBuf::from_slash(path)
}
#[cfg(target_family = "unix")]
fn from_url(u: Url) -> Self {
let path = percent_encoding::percent_decode_str(u.path()).decode_utf8().unwrap();
PathBuf::from_slash(path)
}
}