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 }