intelligent ctags powered by tree-sitter and lexical scope-graphs

move binary

Changed files
+128 -33
src
+124
src/bin/html.rs
··· 1 + #![recursion_limit = "512"] 2 + use stag::StagBuilder; 3 + 4 + use std::iter::Iterator; 5 + use tree_sitter::{Node, Parser, TreeCursor}; 6 + 7 + fn main() { 8 + let scopes = std::fs::read_to_string("src/stag.tsg").unwrap(); 9 + let src = include_str!("html.rs"); 10 + 11 + let sg = StagBuilder::default() 12 + .with_source(src) 13 + .with_stag_file(&scopes) 14 + .with_language(tree_sitter_rust::language()) 15 + .execute() 16 + .unwrap(); 17 + 18 + let mut parser = Parser::new(); 19 + let _ = parser.set_language(tree_sitter_rust::language()); 20 + 21 + let tree = parser.parse(&src, None).unwrap(); 22 + let root = tree.root_node(); 23 + 24 + let preorder = PreOrder { 25 + cursor: root.walk(), 26 + done: false, 27 + }; 28 + 29 + let mut document = html::root::Html::builder(); 30 + let mut code = html::inline_text::Code::builder(); 31 + 32 + let mut prev_range = 0..0; 33 + let mut line_number = 1; 34 + code.span(|s| { 35 + s.text(format!("{line_number:03} ")) 36 + .id(format!("L{line_number}")) 37 + .class("line-number") 38 + }); 39 + line_number += 1; 40 + 41 + for item in preorder { 42 + let item_range = item.byte_range(); 43 + if prev_range.end < item_range.start { 44 + let text = &src[prev_range.end..item_range.start]; 45 + for line in text.split_inclusive('\n') { 46 + code.span(|s| s.text(format!("{line}"))); 47 + if line.contains('\n') { 48 + code.span(|s| { 49 + s.text(format!("{line_number:03} ")) 50 + .id(format!("L{line_number}")) 51 + .class("line-number") 52 + }); 53 + line_number += 1; 54 + } 55 + } 56 + } 57 + if item.child_count() == 0 { 58 + code.span(|mut s| { 59 + if let Some(idx) = sg.node_by_range(item_range.start, item_range.end) { 60 + if sg.is_reference(idx) { 61 + let definitions = sg.definitions(idx).collect::<Vec<_>>(); 62 + if let [only_def] = definitions.as_slice() { 63 + let def_range = sg.graph[*only_def].range(); 64 + s = s.anchor(|l| { 65 + l.href(format!("#L{}", def_range.start.line + 1)) 66 + .text(item.utf8_text(src.as_bytes()).unwrap()) 67 + }); 68 + return s; 69 + } 70 + } 71 + } 72 + s.text(item.utf8_text(src.as_bytes()).unwrap()) 73 + }); 74 + } 75 + prev_range = item_range; 76 + } 77 + 78 + println!( 79 + "{}", 80 + document 81 + .body(|b| { 82 + b.title("static goto def") 83 + .preformatted_text(|pre| pre.push(code.build())) 84 + }) 85 + .head(|h| h.style(|s| s.text(".line-number:target { background-color: lightBlue; }"))) 86 + .build() 87 + ); 88 + } 89 + 90 + // root left right 91 + struct PreOrder<'a> { 92 + cursor: TreeCursor<'a>, 93 + done: bool, 94 + } 95 + 96 + impl<'a> Iterator for PreOrder<'a> { 97 + type Item = Node<'a>; 98 + fn next(&mut self) -> Option<Self::Item> { 99 + if self.done { 100 + return None; 101 + } 102 + 103 + let node = self.cursor.node(); 104 + 105 + if self.cursor.goto_first_child() { 106 + return Some(node); 107 + } else if self.cursor.goto_next_sibling() { 108 + return Some(node); 109 + } 110 + 111 + loop { 112 + if !self.cursor.goto_parent() { 113 + self.done = true; 114 + break; 115 + } 116 + 117 + if self.cursor.goto_next_sibling() { 118 + break; 119 + } 120 + } 121 + 122 + Some(node) 123 + } 124 + }
+1 -1
src/debug.rs
··· 1 1 use std::fmt; 2 2 3 3 use crate::text_range::TextRange; 4 - use crate::{EdgeKind, LocalDef, NodeKind}; 4 + use crate::{EdgeKind, NodeKind}; 5 5 6 6 use petgraph::{ 7 7 graph::{Graph, NodeIndex},
+1 -1
src/lib.rs
··· 6 6 ast::File, functions::Functions, ExecutionConfig, Identifier, NoCancellation, Variables, 7 7 }; 8 8 9 - mod debug; 9 + pub mod debug; 10 10 mod error; 11 11 mod stdlib; 12 12
-30
src/main.rs
··· 1 - use stag::StagBuilder; 2 - 3 - fn main() { 4 - let scopes = std::fs::read_to_string("src/stag.tsg").unwrap(); 5 - let src = r#" 6 - fn main() { 7 - let x = 2; 8 - let a = 5; 9 - if let _ = z { 10 - a[x]; 11 - } 12 - } 13 - "#; 14 - 15 - let sg = StagBuilder::default() 16 - .with_source(src) 17 - .with_stag_file(&scopes) 18 - .with_language(tree_sitter_rust::language()) 19 - .execute() 20 - .unwrap(); 21 - 22 - for edge in sg.graph.raw_edges() { 23 - let s = edge.source(); 24 - let t = edge.target(); 25 - let sn = &sg.graph[s]; 26 - let st = &sg.graph[t]; 27 - println!("{:?} -> {:?}", edge.source(), edge.target()); 28 - println!("{:#?} -> {:#?}", sn, st); 29 - } 30 - }
+2 -1
src/stag.tsg
··· 114 114 ;; let S { field: a } = ..; 115 115 (struct_pattern 116 116 (field_pattern 117 - (identifier) @cap)) 117 + [(identifier) 118 + (shorthand_field_identifier)] @cap)) 118 119 { 119 120 (def @cap "variable") 120 121 }