1use crate::lang::{self, Grammar, Lang};
15use std::{collections::HashSet, ops::Range};
16use theme::HighlightKind;
17use tree_sitter::{InputEdit, Parser, Point, Query, QueryCursor, StreamingIterator as _, Tree};
18
19pub struct Document {
21 parser: Parser,
22 query: Query,
23 kinds: Vec<Option<HighlightKind>>,
26 tree: Tree,
27 source: String,
28}
29
30impl Document {
31 pub fn new(tag: &str, source: impl Into<String>) -> Option<Self> {
33 Self::with_lang(lang::resolve(tag)?, source)
34 }
35
36 pub fn with_lang(lang: &'static Lang, source: impl Into<String>) -> Option<Self> {
37 if !lang.injections.is_empty() {
38 return None;
39 }
40 let language = match &lang.grammar {
41 Grammar::Native(grammar) => tree_sitter::Language::from(*grammar),
42 Grammar::Wasm(_) => return None,
43 };
44 let query = Query::new(&language, lang.query).ok()?;
45 let kinds = query
46 .capture_names()
47 .iter()
48 .map(|name| recognized(name).map(lang::kind_of))
49 .collect();
50 let mut parser = Parser::new();
51 parser.set_language(&language).ok()?;
52 let source = source.into();
53 let tree = parser.parse(&source, None)?;
54 Some(Self {
55 parser,
56 query,
57 kinds,
58 tree,
59 source,
60 })
61 }
62
63 pub fn source(&self) -> &str {
65 &self.source
66 }
67
68 pub fn edit(&mut self, range: Range<usize>, new_end: usize, source: &str) -> Vec<Range<usize>> {
73 let edit = InputEdit {
74 start_byte: range.start,
75 old_end_byte: range.end,
76 new_end_byte: new_end,
77 start_position: point_at(&self.source, range.start),
78 old_end_position: point_at(&self.source, range.end),
79 new_end_position: point_at(source, new_end),
80 };
81 self.tree.edit(&edit);
82 self.source.clear();
83 self.source.push_str(source);
84 let Some(tree) = self.parser.parse(&self.source, Some(&self.tree)) else {
85 return std::iter::once(0..self.source.len()).collect();
86 };
87 let mut changed: Vec<Range<usize>> = self
88 .tree
89 .changed_ranges(&tree)
90 .map(|range| range.start_byte..range.end_byte)
91 .collect();
92 changed.push(range.start..new_end);
94 self.tree = tree;
95 merge(changed)
96 }
97
98 pub fn spans(&self) -> Vec<(Range<usize>, HighlightKind)> {
100 self.spans_in(0..self.source.len())
101 }
102
103 pub fn spans_in(&self, range: Range<usize>) -> Vec<(Range<usize>, HighlightKind)> {
105 let mut cursor = QueryCursor::new();
106 cursor.set_byte_range(range.clone());
107 let mut captures =
108 cursor.captures(&self.query, self.tree.root_node(), self.source.as_bytes());
109 let mut seen = HashSet::new();
111 let mut claimed: Vec<(Range<usize>, Option<HighlightKind>)> = Vec::new();
112 while let Some((found, index)) = captures.next() {
113 let capture = found.captures()[*index];
114 if seen.insert(capture.node.id()) {
115 claimed.push((
116 capture.node.byte_range(),
117 self.kinds[capture.index as usize],
118 ));
119 }
120 }
121 claimed.sort_by(|a, b| a.0.start.cmp(&b.0.start).then(b.0.end.cmp(&a.0.end)));
122 flatten(
123 claimed
124 .into_iter()
125 .filter_map(|(span, kind)| Some((span, kind?))),
126 range,
127 )
128 }
129}
130
131fn flatten(
134 captures: impl Iterator<Item = (Range<usize>, HighlightKind)>,
135 within: Range<usize>,
136) -> Vec<(Range<usize>, HighlightKind)> {
137 let mut spans = Vec::new();
138 let mut stack: Vec<(usize, HighlightKind)> = Vec::new();
139 let mut at = within.start;
140 let mut paint = |to: usize, stack: &[(usize, HighlightKind)], at: &mut usize| {
141 let to = to.min(within.end);
142 if to > *at {
143 if let Some((_, kind)) = stack.last() {
144 spans.push((*at..to, *kind));
145 }
146 *at = to;
147 }
148 };
149 for (span, kind) in captures {
150 while let Some(&(end, _)) = stack.last() {
151 if end > span.start {
152 break;
153 }
154 paint(end, &stack, &mut at);
155 stack.pop();
156 }
157 paint(span.start, &stack, &mut at);
158 stack.push((span.end, kind));
159 }
160 while let Some(&(end, _)) = stack.last() {
161 paint(end, &stack, &mut at);
162 stack.pop();
163 }
164 spans
165}
166
167fn point_at(text: &str, offset: usize) -> Point {
169 let before = &text.as_bytes()[..offset.min(text.len())];
170 let row = before.iter().filter(|byte| **byte == b'\n').count();
171 let column = before
172 .iter()
173 .rposition(|byte| *byte == b'\n')
174 .map_or(before.len(), |newline| before.len() - newline - 1);
175 Point { row, column }
176}
177
178fn merge(mut ranges: Vec<Range<usize>>) -> Vec<Range<usize>> {
180 ranges.sort_by_key(|range| range.start);
181 let mut merged: Vec<Range<usize>> = Vec::new();
182 for range in ranges {
183 match merged.last_mut() {
184 Some(last) if range.start <= last.end => last.end = last.end.max(range.end),
185 _ => merged.push(range),
186 }
187 }
188 merged
189}
190
191fn recognized(capture: &str) -> Option<&'static str> {
195 let parts: Vec<&str> = capture.split('.').collect();
196 let mut best: Option<(&'static str, usize)> = None;
198 for name in lang::NAMES {
199 let len = name.split('.').count();
200 if name.split('.').all(|part| parts.contains(&part))
201 && best.is_none_or(|(_, longest)| len > longest)
202 {
203 best = Some((name, len));
204 }
205 }
206 best.map(|(name, _)| name)
207}