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.rs279
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(..),
- ..,
- )
- );
- }
}