Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-core/src/syntax.rs')
| -rw-r--r-- | helix-core/src/syntax.rs | 279 |
1 files changed, 8 insertions, 271 deletions
diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 4bc177ef..8fa185c6 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -13,7 +13,6 @@ use std::{ use anyhow::{Context, Result}; use arc_swap::{ArcSwap, Guard}; use config::{Configuration, FileType, LanguageConfiguration, LanguageServerConfiguration}; -use foldhash::HashSet; use helix_loader::grammar::get_language; use helix_stdx::rope::RopeSliceExt as _; use once_cell::sync::OnceCell; @@ -21,10 +20,7 @@ use ropey::RopeSlice; use tree_house::{ highlighter, query_iter::QueryIter, - tree_sitter::{ - query::{InvalidPredicateError, UserPredicate}, - Capture, Grammar, InactiveQueryCursor, InputEdit, Node, Pattern, Query, RopeInput, Tree, - }, + tree_sitter::{Grammar, InactiveQueryCursor, InputEdit, Node, Query, RopeInput, Tree}, Error, InjectionLanguageMarker, LanguageConfig as SyntaxConfig, Layer, }; @@ -32,7 +28,6 @@ use crate::{indent::IndentQuery, tree_sitter, ChangeSet, Language}; pub use tree_house::{ highlighter::{Highlight, HighlightEvent}, - query_iter::QueryIterEvent, Error as HighlighterError, LanguageLoader, TreeCursor, TREE_SITTER_MATCH_LIMIT, }; @@ -42,8 +37,6 @@ pub struct LanguageData { syntax: OnceCell<Option<SyntaxConfig>>, indent_query: OnceCell<Option<IndentQuery>>, textobject_query: OnceCell<Option<TextObjectQuery>>, - tag_query: OnceCell<Option<TagQuery>>, - rainbow_query: OnceCell<Option<RainbowQuery>>, } impl LanguageData { @@ -53,8 +46,6 @@ impl LanguageData { syntax: OnceCell::new(), indent_query: OnceCell::new(), textobject_query: OnceCell::new(), - tag_query: OnceCell::new(), - rainbow_query: OnceCell::new(), } } @@ -90,7 +81,7 @@ impl LanguageData { Ok(Some(config)) } - pub fn syntax_config(&self, loader: &Loader) -> Option<&SyntaxConfig> { + fn syntax_config(&self, loader: &Loader) -> Option<&SyntaxConfig> { self.syntax .get_or_init(|| { Self::compile_syntax_config(&self.config, loader) @@ -163,74 +154,6 @@ impl LanguageData { .as_ref() } - /// Compiles the tags.scm query for a language. - /// This function should only be used by this module or the xtask crate. - pub fn compile_tag_query( - grammar: Grammar, - config: &LanguageConfiguration, - ) -> Result<Option<TagQuery>> { - let name = &config.language_id; - let text = read_query(name, "tags.scm"); - if text.is_empty() { - return Ok(None); - } - let query = Query::new(grammar, &text, |_pattern, predicate| match predicate { - // TODO: these predicates are allowed in tags.scm queries but not yet used. - UserPredicate::IsPropertySet { key: "local", .. } => Ok(()), - UserPredicate::Other(pred) => match pred.name() { - "strip!" | "select-adjacent!" => Ok(()), - _ => Err(InvalidPredicateError::unknown(predicate)), - }, - _ => Err(InvalidPredicateError::unknown(predicate)), - }) - .with_context(|| format!("Failed to compile tags.scm query for '{name}'"))?; - Ok(Some(TagQuery { query })) - } - - fn tag_query(&self, loader: &Loader) -> Option<&TagQuery> { - self.tag_query - .get_or_init(|| { - let grammar = self.syntax_config(loader)?.grammar; - Self::compile_tag_query(grammar, &self.config) - .map_err(|err| { - log::error!("{err}"); - }) - .ok() - .flatten() - }) - .as_ref() - } - - /// Compiles the rainbows.scm query for a language. - /// This function should only be used by this module or the xtask crate. - pub fn compile_rainbow_query( - grammar: Grammar, - config: &LanguageConfiguration, - ) -> Result<Option<RainbowQuery>> { - let name = &config.language_id; - let text = read_query(name, "rainbows.scm"); - if text.is_empty() { - return Ok(None); - } - let rainbow_query = RainbowQuery::new(grammar, &text) - .with_context(|| format!("Failed to compile rainbows.scm query for '{name}'"))?; - Ok(Some(rainbow_query)) - } - - fn rainbow_query(&self, loader: &Loader) -> Option<&RainbowQuery> { - self.rainbow_query - .get_or_init(|| { - let grammar = self.syntax_config(loader)?.grammar; - Self::compile_rainbow_query(grammar, &self.config) - .map_err(|err| { - log::error!("{err}"); - }) - .ok() - .flatten() - }) - .as_ref() - } - fn reconfigure(&self, scopes: &[String]) { if let Some(Some(config)) = self.syntax.get() { reconfigure_highlights(config, scopes); @@ -238,7 +161,7 @@ impl LanguageData { } } -pub fn reconfigure_highlights(config: &SyntaxConfig, recognized_names: &[String]) { +fn reconfigure_highlights(config: &SyntaxConfig, recognized_names: &[String]) { config.configure(move |capture_name| { let capture_parts: Vec<_> = capture_name.split('.').collect(); @@ -416,14 +339,6 @@ impl Loader { self.language(lang).textobject_query(self) } - pub fn tag_query(&self, lang: Language) -> Option<&TagQuery> { - self.language(lang).tag_query(self) - } - - fn rainbow_query(&self, lang: Language) -> Option<&RainbowQuery> { - self.language(lang).rainbow_query(self) - } - pub fn language_server_configs(&self) -> &HashMap<String, LanguageServerConfiguration> { &self.language_server_configs } @@ -512,7 +427,7 @@ impl FileTypeGlobMatcher { #[derive(Debug)] pub struct Syntax { - pub inner: tree_house::Syntax, + inner: tree_house::Syntax, } const PARSE_TIMEOUT: Duration = Duration::from_millis(500); // half a second is pretty generous @@ -562,15 +477,15 @@ impl Syntax { self.inner.tree_for_byte_range(start, end) } - pub fn named_descendant_for_byte_range(&self, start: u32, end: u32) -> Option<Node<'_>> { + pub fn named_descendant_for_byte_range(&self, start: u32, end: u32) -> Option<Node> { self.inner.named_descendant_for_byte_range(start, end) } - pub fn descendant_for_byte_range(&self, start: u32, end: u32) -> Option<Node<'_>> { + pub fn descendant_for_byte_range(&self, start: u32, end: u32) -> Option<Node> { self.inner.descendant_for_byte_range(start, end) } - pub fn walk(&self) -> TreeCursor<'_> { + pub fn walk(&self) -> TreeCursor { self.inner.walk() } @@ -596,92 +511,6 @@ impl Syntax { { QueryIter::new(&self.inner, source, loader, range) } - - pub fn tags<'a>( - &'a self, - source: RopeSlice<'a>, - loader: &'a Loader, - range: impl RangeBounds<u32>, - ) -> QueryIter<'a, 'a, impl FnMut(Language) -> Option<&'a Query> + 'a, ()> { - self.query_iter( - source, - |lang| loader.tag_query(lang).map(|q| &q.query), - range, - ) - } - - pub fn rainbow_highlights( - &self, - source: RopeSlice, - rainbow_length: usize, - loader: &Loader, - range: impl RangeBounds<u32>, - ) -> OverlayHighlights { - struct RainbowScope<'tree> { - end: u32, - node: Option<Node<'tree>>, - highlight: Highlight, - } - - let mut scope_stack = Vec::<RainbowScope>::new(); - let mut highlights = Vec::new(); - let mut query_iter = self.query_iter::<_, (), _>( - source, - |lang| loader.rainbow_query(lang).map(|q| &q.query), - range, - ); - - while let Some(event) = query_iter.next() { - let QueryIterEvent::Match(mat) = event else { - continue; - }; - - let rainbow_query = loader - .rainbow_query(query_iter.current_language()) - .expect("language must have a rainbow query to emit matches"); - - let byte_range = mat.node.byte_range(); - // Pop any scopes that end before this capture begins. - while scope_stack - .last() - .is_some_and(|scope| byte_range.start >= scope.end) - { - scope_stack.pop(); - } - - let capture = Some(mat.capture); - if capture == rainbow_query.scope_capture { - scope_stack.push(RainbowScope { - end: byte_range.end, - node: if rainbow_query - .include_children_patterns - .contains(&mat.pattern) - { - None - } else { - Some(mat.node.clone()) - }, - highlight: Highlight::new((scope_stack.len() % rainbow_length) as u32), - }); - } else if capture == rainbow_query.bracket_capture { - if let Some(scope) = scope_stack.last() { - if !scope - .node - .as_ref() - .is_some_and(|node| mat.node.parent().as_ref() != Some(node)) - { - let start = source - .byte_to_char(source.floor_char_boundary(byte_range.start as usize)); - let end = - source.byte_to_char(source.ceil_char_boundary(byte_range.end as usize)); - highlights.push((scope.highlight, start..end)); - } - } - } - } - - OverlayHighlights::Heterogenous { highlights } - } } pub type Highlighter<'a> = highlighter::Highlighter<'a, 'a, Loader>; @@ -1052,11 +881,6 @@ impl TextObjectQuery { } } -#[derive(Debug)] -pub struct TagQuery { - pub query: Query, -} - pub fn pretty_print_tree<W: fmt::Write>(fmt: &mut W, node: Node) -> fmt::Result { if node.child_count() == 0 { if node_is_visible(&node) { @@ -1073,7 +897,7 @@ fn node_is_visible(node: &Node) -> bool { node.is_missing() || (node.is_named() && node.grammar().node_kind_is_visible(node.kind_id())) } -fn format_anonymous_node_kind(kind: &str) -> Cow<'_, str> { +fn format_anonymous_node_kind(kind: &str) -> Cow<str> { if kind.contains('"') { Cow::Owned(kind.replace('"', "\\\"")) } else { @@ -1129,56 +953,6 @@ fn pretty_print_tree_impl<W: fmt::Write>( Ok(()) } -/// Finds the child of `node` which contains the given byte range. -pub fn child_for_byte_range<'a>(node: &Node<'a>, range: ops::Range<u32>) -> Option<Node<'a>> { - for child in node.children() { - let child_range = child.byte_range(); - - if range.start >= child_range.start && range.end <= child_range.end { - return Some(child); - } - } - - None -} - -#[derive(Debug)] -pub struct RainbowQuery { - query: Query, - include_children_patterns: HashSet<Pattern>, - scope_capture: Option<Capture>, - bracket_capture: Option<Capture>, -} - -impl RainbowQuery { - fn new(grammar: Grammar, source: &str) -> Result<Self, tree_sitter::query::ParseError> { - let mut include_children_patterns = HashSet::default(); - - let query = Query::new(grammar, source, |pattern, predicate| match predicate { - UserPredicate::SetProperty { - key: "rainbow.include-children", - val, - } => { - if val.is_some() { - return Err( - "property 'rainbow.include-children' does not take an argument".into(), - ); - } - include_children_patterns.insert(pattern); - Ok(()) - } - _ => Err(InvalidPredicateError::unknown(predicate)), - })?; - - Ok(Self { - include_children_patterns, - scope_capture: query.get_capture("rainbow.scope"), - bracket_capture: query.get_capture("rainbow.bracket"), - query, - }) - } -} - #[cfg(test)] mod test { use once_cell::sync::Lazy; @@ -1203,24 +977,7 @@ mod test { ); let language = LOADER.language_for_name("rust").unwrap(); - dbg!(language); let grammar = LOADER.get_config(language).unwrap().grammar; - dbg!(grammar); - let syntax = Syntax::new(source.slice(..), language, &LOADER).unwrap(); - let mut h = syntax.highlighter( - "fn main() { 4 + 2; }".into(), - &LOADER, - 0.."fn main() { 4 + 2; }".len() as u32, - ); - - for n in 0..5 { - dbg!(h.active_highlights().collect::<Vec<_>>()); - dbg!(h.next_event_offset()); - let (e, h) = h.advance(); - dbg!(h.collect::<Vec<_>>(), e); - // panic!() - } - let query = Query::new(grammar, query_str, |_, _| Ok(())).unwrap(); let textobject = TextObjectQuery::new(query); let syntax = Syntax::new(source.slice(..), language, &LOADER).unwrap(); @@ -1385,24 +1142,4 @@ mod test { source.len(), ); } - #[test] - fn highlight() { - let source = Rope::from_str(r#"assert_eq!(0, Some(0));"#); - let loader = crate::config::default_lang_loader(); - loader.set_scopes(vec!["punctuation".to_string()]); - let language = loader.language_for_name("rust").unwrap(); - - let syntax = Syntax::new(source.slice(..), language, &loader).unwrap(); - println!( - "{}", - tree_house::fixtures::highlighter_fixture( - "", - &loader, - |_| "punct".to_string(), - &syntax.inner, - source.slice(..), - .., - ) - ); - } } |