test rust lsp

This commit is contained in:
2025-09-07 07:18:18 +02:00
parent a8bf55882e
commit 7a3e3ae9f7
330 changed files with 1714 additions and 70094 deletions
+12
View File
@@ -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 }
+99
View File
@@ -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()
}