test rust lsp
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "analysis"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
lsp-types = { workspace = true }
|
||||
tree-sitter = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
use serde::{ Deserialize, Serialize };
|
||||
use std::collections::HashMap;
|
||||
use tree_sitter::{ Node, Tree };
|
||||
use lsp_types as lsp;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ProcDef {
|
||||
pub name: String,
|
||||
pub params: Vec<String>,
|
||||
pub byte_start: usize,
|
||||
pub byte_end: usize,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ProcIndex {
|
||||
by_uri: HashMap<lsp::Uri, Vec<ProcDef>>,
|
||||
}
|
||||
|
||||
impl ProcIndex {
|
||||
pub fn insert(&mut self, uri: lsp::Uri, procs: Vec<ProcDef>) {
|
||||
self.by_uri.insert(uri, procs);
|
||||
}
|
||||
pub fn get(&self, uri: &lsp::Uri) -> Option<&[ProcDef]> {
|
||||
self.by_uri.get(uri).map(|v| v.as_slice())
|
||||
}
|
||||
pub fn remove(&mut self, uri: &lsp::Uri) {
|
||||
self.by_uri.remove(uri);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collect_procs(tree: &Tree, source: &str) -> Vec<ProcDef> {
|
||||
let root = tree.root_node();
|
||||
let mut out = Vec::new();
|
||||
collect_from_node(root, source.as_bytes(), &mut out);
|
||||
out
|
||||
}
|
||||
|
||||
fn collect_from_node(node: Node, src: &[u8], out: &mut Vec<ProcDef>) {
|
||||
let mut stack = vec![node];
|
||||
let mut cursor = node.walk();
|
||||
|
||||
while let Some(n) = stack.pop() {
|
||||
if n.kind() == "command" {
|
||||
if let Some(p) = try_extract_proc(n, src) {
|
||||
out.push(p);
|
||||
}
|
||||
}
|
||||
let mut it = n.children(&mut cursor);
|
||||
while let Some(c) = it.next() {
|
||||
stack.push(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_extract_proc(cmd: Node, src: &[u8]) -> Option<ProcDef> {
|
||||
// Gather word-like named children
|
||||
let mut cursor = cmd.walk();
|
||||
let mut words: Vec<(Node, String)> = Vec::new();
|
||||
for ch in cmd.named_children(&mut cursor) {
|
||||
match ch.kind() {
|
||||
"word" | "braced_word" | "quoted_word" => {
|
||||
if let Ok(t) = ch.utf8_text(src) {
|
||||
words.push((ch, t.to_string()));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if words.len() < 2 {
|
||||
return None;
|
||||
}
|
||||
if words[0].1 != "proc" {
|
||||
return None;
|
||||
}
|
||||
|
||||
let name = words[1].1.trim().to_string();
|
||||
let params = if words.len() >= 3 { parse_params(&words[2].0, &words[2].1) } else { vec![] };
|
||||
|
||||
Some(ProcDef {
|
||||
name,
|
||||
params,
|
||||
byte_start: cmd.start_byte(),
|
||||
byte_end: cmd.end_byte(),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_params(node: &Node, text: &str) -> Vec<String> {
|
||||
// naive split; good enough for a starter
|
||||
let is_braced =
|
||||
node.kind() == "braced_word" &&
|
||||
text.starts_with('{') &&
|
||||
text.ends_with('}') &&
|
||||
text.len() >= 2;
|
||||
let inner = if is_braced { &text[1..text.len() - 1] } else { text };
|
||||
inner
|
||||
.split_whitespace()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
}
|
||||
Reference in New Issue
Block a user