Unnamed repository; edit this file 'description' to name the repository.
Pascal Kuthe 2024-07-15
parent c4b7b08 · commit 37397ec
-rw-r--r--helix-syntax/src/injections_tree.rs94
-rw-r--r--helix-syntax/src/lib.rs4
2 files changed, 97 insertions, 1 deletions
diff --git a/helix-syntax/src/injections_tree.rs b/helix-syntax/src/injections_tree.rs
new file mode 100644
index 00000000..e181a775
--- /dev/null
+++ b/helix-syntax/src/injections_tree.rs
@@ -0,0 +1,94 @@
+use core::slice;
+use std::iter::Peekable;
+use std::sync::Arc;
+
+use hashbrown::HashMap;
+use slotmap::{new_key_type, HopSlotMap, SlotMap};
+use tree_sitter::Tree;
+
+use crate::parse::LayerUpdateFlags;
+use crate::{HighlightConfiguration, RopeProvider};
+
+// TODO(perf): replace std::ops::Range with helix_core::Range once added
+type Range = std::ops::Range<usize>;
+
+new_key_type! {
+ /// The default slot map key type.
+ pub struct LayerId;
+}
+
+#[derive(Debug)]
+pub struct LanguageLayer {
+ pub config: Arc<HighlightConfiguration>,
+ pub(crate) parse_tree: Option<Tree>,
+ /// internal flags used during parsing to track incremental invalidation
+ pub(crate) flags: LayerUpdateFlags,
+ pub(crate) parent: Option<LayerId>,
+ /// a list of **sorted** non-overlapping injection ranges note that
+ /// injection ranges are not relative to the start of this layer but the
+ /// start of the root layer
+ pub(crate) injection_ranges: Box<[InjectionRange]>,
+}
+
+#[derive(Debug)]
+pub(crate) struct InjectionRange {
+ pub byte_range: Range,
+ pub layer: LayerId,
+}
+
+impl LanguageLayer {
+ /// Returns the injection range **within this layers** that contains `idx`.
+ /// This function will not descend into nested injections
+ pub(crate) fn injection_at_byte_idx(&self, idx: usize) -> Option<&InjectionRange> {
+ let i = self
+ .injection_ranges
+ .partition_point(|range| range.byte_range.start <= idx);
+ self.injection_ranges
+ .get(i)
+ .filter(|injection| injection.byte_range.end > idx)
+ }
+}
+
+struct InjectionTree {
+ layers: SlotMap<LayerId, LanguageLayer>,
+ root: LayerId,
+}
+
+impl InjectionTree {
+ pub fn layer_for_byte_range(&self, start: usize, end: usize) -> LayerId {
+ let mut cursor = self.root;
+ loop {
+ let layer = &self.layers[cursor];
+ let Some(start_injection) = layer.injection_at_byte_idx(start) else {
+ break;
+ };
+ let Some(end_injection) = layer.injection_at_byte_idx(end) else {
+ break;
+ };
+ if start_injection.layer == end_injection.layer {
+ cursor = start_injection.layer;
+ } else {
+ break;
+ }
+ }
+ cursor
+ }
+}
+
+struct ActiveInjection<'a> {
+ injections: Peekable<slice::Iter<'a, InjectionTree>>,
+ range: InjectionRange,
+}
+
+struct ActiveLayer<'a, State> {
+ state: State,
+ /// the query captures just for this layer
+ layer_captures: Peekable<LayerQueryCaptures<'a>>,
+}
+
+type LayerQueryCaptures<'a> = tree_sitter::QueryCaptures<'a, 'a, RopeProvider<'a>, &'a [u8]>;
+
+pub struct QueryCaptures<'a> {
+ active_layers: HashMap<LayerId, ActiveLayer<'a, ()>>,
+ active_injections: Vec<ActiveInjection<'a>>,
+}
diff --git a/helix-syntax/src/lib.rs b/helix-syntax/src/lib.rs
index 04a2d27d..915d8df5 100644
--- a/helix-syntax/src/lib.rs
+++ b/helix-syntax/src/lib.rs
@@ -1,5 +1,5 @@
use ::ropey::RopeSlice;
-use slotmap::{DefaultKey as LayerId, HopSlotMap};
+use slotmap::{new_key_type, HopSlotMap};
use tree_sitter::{Node, Parser, Point, Query, QueryCursor, Range, Tree};
use std::borrow::Cow;
@@ -9,6 +9,7 @@ use std::path::Path;
use std::str;
use std::sync::Arc;
+use crate::injections_tree::LayerId;
use crate::parse::LayerUpdateFlags;
pub use crate::config::{read_query, HighlightConfiguration};
@@ -19,6 +20,7 @@ pub use tree_cursor::TreeCursor;
mod config;
pub mod highlighter;
+mod injections_tree;
mod merge;
mod parse;
mod pretty_print;