tinymist_query/analysis/
doc_highlight.rsuse crate::{prelude::*, syntax::node_ancestors};
pub struct DocumentHighlightWorker<'a> {
ctx: &'a mut LocalContext,
source: &'a Source,
pub annotated: Vec<DocumentHighlight>,
worklist: Vec<LinkedNode<'a>>,
}
impl<'a> DocumentHighlightWorker<'a> {
pub fn new(ctx: &'a mut LocalContext, source: &'a Source) -> Self {
Self {
ctx,
source,
annotated: Vec::new(),
worklist: Vec::new(),
}
}
pub fn work(&mut self, mut node: &'a LinkedNode<'a>) -> Option<()> {
loop {
match node.kind() {
SyntaxKind::For
| SyntaxKind::While
| SyntaxKind::Break
| SyntaxKind::Continue
| SyntaxKind::LoopBreak
| SyntaxKind::LoopContinue => return self.work_loop(node),
SyntaxKind::Arrow
| SyntaxKind::Params
| SyntaxKind::Return
| SyntaxKind::FuncReturn
| SyntaxKind::Contextual => return self.work_func(node),
_ => {}
}
node = node.parent()?;
}
}
fn work_loop(&mut self, node: &'a LinkedNode<'a>) -> Option<()> {
let _ = self.ctx;
let loop_node = 'find_loop: {
for anc in node_ancestors(node) {
if matches!(anc.kind(), SyntaxKind::Contextual | SyntaxKind::Closure) {
return None;
}
if matches!(anc.kind(), SyntaxKind::ForLoop | SyntaxKind::WhileLoop) {
break 'find_loop anc;
}
}
return None;
};
let keyword = loop_node.children().find(|node| node.kind().is_keyword());
if let Some(keyword) = keyword {
self.annotate(&keyword);
}
self.check_children(loop_node);
self.check(Self::check_loop);
crate::log_debug_ct!("highlights: {:?}", self.annotated);
Some(())
}
fn work_func(&mut self, _node: &'a LinkedNode<'a>) -> Option<()> {
None
}
fn annotate(&mut self, node: &LinkedNode) {
let mut rng = node.range();
if rng.start > 0 && self.source.text().as_bytes()[rng.start - 1] == b'#' {
rng.start -= 1;
}
self.annotated.push(DocumentHighlight {
range: self.ctx.to_lsp_range(rng, self.source),
kind: None,
});
}
fn check<F>(&mut self, check: F)
where
F: Fn(&mut Self, LinkedNode<'a>),
{
while let Some(node) = self.worklist.pop() {
check(self, node);
}
}
fn check_children(&mut self, node: &LinkedNode<'a>) {
if node.get().children().len() == 0 {
return;
}
for child in node.children() {
self.worklist.push(child.clone());
}
}
fn check_loop(&mut self, node: LinkedNode<'a>) {
match node.kind() {
SyntaxKind::ForLoop
| SyntaxKind::WhileLoop
| SyntaxKind::Closure
| SyntaxKind::Contextual => {
return;
}
SyntaxKind::LoopBreak | SyntaxKind::LoopContinue => {
self.annotate(&node);
return;
}
_ => {}
}
self.check_children(&node);
}
}