mirror of
https://github.com/Strum355/mcshader-lsp.git
synced 2025-08-03 16:39:16 +00:00
tree-sitter fun 👀
This commit is contained in:
parent
86100aa008
commit
d3c0869288
9 changed files with 198 additions and 5 deletions
22
server/Cargo.lock
generated
22
server/Cargo.lock
generated
|
@ -765,6 +765,8 @@ dependencies = [
|
|||
"slog-term",
|
||||
"tempdir",
|
||||
"thiserror",
|
||||
"tree-sitter",
|
||||
"tree-sitter-glsl",
|
||||
"url",
|
||||
"walkdir",
|
||||
]
|
||||
|
@ -1631,6 +1633,26 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter"
|
||||
version = "0.20.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09b3b781640108d29892e8b9684642d2cda5ea05951fd58f0fea1db9edeb9b71"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-glsl"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d20c93432c782c4f66618ffb06669870ac6231a86b1777813a6c97148f1f0fb"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"tree-sitter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "treeline"
|
||||
version = "0.1.0"
|
||||
|
|
|
@ -30,6 +30,8 @@ slog-atomic = "3.1"
|
|||
once_cell = "1.7"
|
||||
rand = "0.8"
|
||||
arc-swap = "1.5.0"
|
||||
tree-sitter = "0.20.6"
|
||||
tree-sitter-glsl = "0.1.2"
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3"
|
||||
|
|
|
@ -3,9 +3,11 @@ use std::{collections::HashMap, path::Path};
|
|||
use serde_json::Value;
|
||||
|
||||
use anyhow::{format_err, Result};
|
||||
use slog_scope::info;
|
||||
|
||||
pub mod graph_dot;
|
||||
pub mod merged_includes;
|
||||
pub mod parse_tree;
|
||||
|
||||
pub struct CustomCommandProvider {
|
||||
commands: HashMap<String, Box<dyn Invokeable>>,
|
||||
|
@ -20,6 +22,9 @@ impl CustomCommandProvider {
|
|||
|
||||
pub fn execute(&self, command: &str, args: &[Value], root_path: &Path) -> Result<Value> {
|
||||
if self.commands.contains_key(command) {
|
||||
info!("running command";
|
||||
"command" => command,
|
||||
"args" => format!("[{}]", args.iter().map(|v| serde_json::to_string(v).unwrap()).collect::<Vec<String>>().join(", ")));
|
||||
return self.commands.get(command).unwrap().run_command(root_path, args);
|
||||
}
|
||||
Err(format_err!("command doesn't exist"))
|
||||
|
|
94
server/src/commands/parse_tree.rs
Normal file
94
server/src/commands/parse_tree.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
use std::{
|
||||
cell::RefCell,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use anyhow::{format_err, Result};
|
||||
use serde_json::Value;
|
||||
use slog_scope::warn;
|
||||
use tree_sitter::{Parser, TreeCursor};
|
||||
|
||||
use crate::url_norm::FromJson;
|
||||
|
||||
use super::Invokeable;
|
||||
|
||||
pub struct TreeSitterSExpr {
|
||||
pub tree_sitter: Rc<RefCell<Parser>>,
|
||||
}
|
||||
|
||||
impl Invokeable for TreeSitterSExpr {
|
||||
fn run_command(&self, _: &Path, arguments: &[Value]) -> Result<Value> {
|
||||
let path = PathBuf::from_json(arguments.get(0).unwrap())?;
|
||||
|
||||
warn!("parsing"; "path" => path.to_str().unwrap().to_string());
|
||||
|
||||
let source = fs::read_to_string(path)?;
|
||||
|
||||
let tree = match self.tree_sitter.borrow_mut().parse(source, None) {
|
||||
Some(tree) => tree,
|
||||
None => return Err(format_err!("tree-sitter parsing resulted in no parse tree")),
|
||||
};
|
||||
|
||||
let mut cursor = tree.walk();
|
||||
|
||||
let rendered = render_parse_tree(&mut cursor);
|
||||
|
||||
Ok(serde_json::value::Value::String(rendered))
|
||||
}
|
||||
}
|
||||
|
||||
fn render_parse_tree(cursor: &mut TreeCursor) -> String {
|
||||
let mut string = String::new();
|
||||
|
||||
let mut indent = 0;
|
||||
let mut visited_children = false;
|
||||
|
||||
loop {
|
||||
let node = cursor.node();
|
||||
|
||||
let display_name = if node.is_missing() {
|
||||
format!("MISSING {}", node.kind())
|
||||
} else if node.is_named() {
|
||||
node.kind().to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
if visited_children {
|
||||
if cursor.goto_next_sibling() {
|
||||
visited_children = false;
|
||||
} else if cursor.goto_parent() {
|
||||
visited_children = true;
|
||||
indent -= 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if !display_name.is_empty() {
|
||||
let start = node.start_position();
|
||||
let end = node.end_position();
|
||||
|
||||
let field_name = match cursor.field_name() {
|
||||
Some(name) => name.to_string() + ": ",
|
||||
None => "".to_string(),
|
||||
};
|
||||
|
||||
string += (" ".repeat(indent)
|
||||
+ format!("{}{} [{}, {}] - [{}, {}]\n", field_name, display_name, start.row, start.column, end.row, end.column)
|
||||
.trim_start())
|
||||
.as_str();
|
||||
}
|
||||
|
||||
if cursor.goto_first_child() {
|
||||
visited_children = false;
|
||||
indent += 1;
|
||||
} else {
|
||||
visited_children = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string
|
||||
}
|
|
@ -7,6 +7,7 @@ use petgraph::stable_graph::NodeIndex;
|
|||
use serde::Deserialize;
|
||||
use serde_json::{from_value, Value};
|
||||
|
||||
use tree_sitter::Parser;
|
||||
use url_norm::FromUrl;
|
||||
|
||||
use walkdir::WalkDir;
|
||||
|
@ -65,12 +66,16 @@ fn main() {
|
|||
|
||||
let cache_graph = graph::CachedStableGraph::new();
|
||||
|
||||
let mut parser = Parser::new();
|
||||
parser.set_language(tree_sitter_glsl::language()).unwrap();
|
||||
|
||||
let mut langserver = MinecraftShaderLanguageServer {
|
||||
endpoint: endpoint_output.clone(),
|
||||
graph: Rc::new(RefCell::new(cache_graph)),
|
||||
root: "".into(),
|
||||
command_provider: None,
|
||||
opengl_context: Rc::new(opengl::OpenGlContext::new()),
|
||||
tree_sitter: Rc::new(RefCell::new(parser)),
|
||||
log_guard: Some(guard),
|
||||
};
|
||||
|
||||
|
@ -87,6 +92,12 @@ fn main() {
|
|||
graph: langserver.graph.clone(),
|
||||
}),
|
||||
),
|
||||
(
|
||||
"parseTree",
|
||||
Box::new(commands::parse_tree::TreeSitterSExpr {
|
||||
tree_sitter: langserver.tree_sitter.clone(),
|
||||
}),
|
||||
),
|
||||
]));
|
||||
|
||||
LSPEndpoint::run_server_from_input(&mut stdin().lock(), endpoint_output, langserver);
|
||||
|
@ -98,6 +109,7 @@ struct MinecraftShaderLanguageServer {
|
|||
root: PathBuf,
|
||||
command_provider: Option<commands::CustomCommandProvider>,
|
||||
opengl_context: Rc<dyn opengl::ShaderValidator>,
|
||||
tree_sitter: Rc<RefCell<Parser>>,
|
||||
log_guard: Option<slog_scope::GlobalLoggerGuard>,
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ fn new_temp_server(opengl_context: Option<Box<dyn opengl::ShaderValidator>>) ->
|
|||
command_provider: None,
|
||||
opengl_context: context.into(),
|
||||
log_guard: Some(guard),
|
||||
tree_sitter: Rc::new(RefCell::new(Parser::new())),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue