diff options
Diffstat (limited to 'src/syntax/highlight.rs')
| -rw-r--r-- | src/syntax/highlight.rs | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/src/syntax/highlight.rs b/src/syntax/highlight.rs index 9f7365a8..0f1ee89d 100644 --- a/src/syntax/highlight.rs +++ b/src/syntax/highlight.rs @@ -1,5 +1,8 @@ use std::ops::Range; +use syntect::highlighting::{Highlighter, Style}; +use syntect::parsing::Scope; + use super::{NodeKind, RedRef}; /// Provide highlighting categories for the children of a node that fall into a @@ -19,6 +22,37 @@ where } } +/// Provide syntect highlighting styles for the children of a node. +pub fn highlight_syntect<F>(node: RedRef, highlighter: &Highlighter, f: &mut F) +where + F: FnMut(Range<usize>, Style), +{ + highlight_syntect_impl(node, vec![], highlighter, f) +} + +/// Recursive implementation for returning syntect styles. +fn highlight_syntect_impl<F>( + node: RedRef, + scopes: Vec<Scope>, + highlighter: &Highlighter, + f: &mut F, +) where + F: FnMut(Range<usize>, Style), +{ + if node.children().size_hint().0 == 0 { + f(node.span().to_range(), highlighter.style_for_stack(&scopes)); + return; + } + + for child in node.children() { + let mut scopes = scopes.clone(); + if let Some(category) = Category::determine(child, node) { + scopes.push(Scope::new(category.tm_scope()).unwrap()) + } + highlight_syntect_impl(child, scopes, highlighter, f); + } +} + /// The syntax highlighting category of a node. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Category { @@ -186,6 +220,33 @@ impl Category { NodeKind::IncludeExpr => None, } } + + /// Return the TextMate grammar scope for the given highlighting category. + pub fn tm_scope(&self) -> &'static str { + match self { + Self::Bracket => "punctuation.definition.typst", + Self::Punctuation => "punctuation.typst", + Self::Comment => "comment.typst", + Self::Strong => "markup.bold.typst", + Self::Emph => "markup.italic.typst", + Self::Raw => "markup.raw.typst", + Self::Math => "string.other.math.typst", + Self::Heading => "markup.heading.typst", + Self::List => "markup.list.typst", + Self::Shortcut => "punctuation.shortcut.typst", + Self::Escape => "constant.character.escape.content.typst", + Self::Keyword => "keyword.typst", + Self::Operator => "keyword.operator.typst", + Self::None => "constant.language.none.typst", + Self::Auto => "constant.language.auto.typst", + Self::Bool => "constant.language.boolean.typst", + Self::Number => "constant.numeric.typst", + Self::String => "string.quoted.double.typst", + Self::Function => "entity.name.function.typst", + Self::Variable => "variable.parameter.typst", + Self::Invalid => "invalid.typst", + } + } } #[cfg(test)] |
