001 #![recursion_limit = "512"]
002 use stag::StagBuilder;
003
004 use std::iter::Iterator;
005 use tree_sitter::{Node, Parser, TreeCursor};
006
007 fn main() {
008 let src = include_str!("html.rs");
009
010 let sg = StagBuilder::default()
011 .with_source(src)
012 .with_stag_file(stag::RUST)
013 .with_language(tree_sitter_rust::language())
014 .execute()
015 .unwrap();
016
017 let mut parser = Parser::new();
018 let _ = parser.set_language(tree_sitter_rust::language());
019
020 let tree = parser.parse(&src, None).unwrap();
021 let root = tree.root_node();
022
023 let preorder = PreOrder {
024 cursor: root.walk(),
025 done: false,
026 };
027
028 let mut document = html::root::Html::builder();
029 let mut code = html::inline_text::Code::builder();
030
031 let mut prev_range = 0..0;
032 let mut line_number = 1;
033 code.span(|s| {
034 s.text(format!("{line_number:03} "))
035 .id(format!("L{line_number}"))
036 .class("line-number")
037 });
038 line_number += 1;
039
040 for item in preorder {
041 let item_range = item.byte_range();
042 if prev_range.end < item_range.start {
043 let text = &src[prev_range.end..item_range.start];
044 for line in text.split_inclusive('\n') {
045 code.span(|s| s.text(format!("{line}")));
046 if line.contains('\n') {
047 code.span(|s| {
048 s.text(format!("{line_number:03} "))
049 .id(format!("L{line_number}"))
050 .class("line-number")
051 });
052 line_number += 1;
053 }
054 }
055 }
056 if item.child_count() == 0 {
057 code.span(|mut s| {
058 if let Some(idx) = sg.node_by_range(item_range.start, item_range.end) {
059 if sg.is_reference(idx) {
060 let definitions = sg.definitions(idx).collect::<Vec<_>>();
061 if let [only_def] = definitions.as_slice() {
062 let def_range = sg.graph[*only_def].range();
063 s = s.anchor(|l| {
064 l.href(format!("#L{}", def_range.start.line + 1))
065 .text(item.utf8_text(src.as_bytes()).unwrap())
066 });
067 return s;
068 }
069 }
070 }
071 s.text(item.utf8_text(src.as_bytes()).unwrap())
072 });
073 }
074 prev_range = item_range;
075 }
076
077 println!(
078 "{}",
079 document
080 .body(|b| {
081 b.title("static goto def")
082 .preformatted_text(|pre| pre.push(code.build()))
083 })
084 .head(|h| h.style(|s| s.text(".line-number:target { background-color: lightBlue; }")))
085 .build()
086 );
087 }
088
089 // root left right
090 struct PreOrder<'a> {
091 cursor: TreeCursor<'a>,
092 done: bool,
093 }
094
095 impl<'a> Iterator for PreOrder<'a> {
096 type Item = Node<'a>;
097 fn next(&mut self) -> Option<Self::Item> {
098 if self.done {
099 return None;
100 }
101
102 let node = self.cursor.node();
103
104 if self.cursor.goto_first_child() {
105 return Some(node);
106 } else if self.cursor.goto_next_sibling() {
107 return Some(node);
108 }
109
110 loop {
111 if !self.cursor.goto_parent() {
112 self.done = true;
113 break;
114 }
115
116 if self.cursor.goto_next_sibling() {
117 break;
118 }
119 }
120
121 Some(node)
122 }
123 }