This commit is contained in:
Pascal Kuthe 2024-04-22 02:25:18 +02:00
parent c4b7b08809
commit 37397ecc6d
No known key found for this signature in database
GPG Key ID: D715E8655AE166A6
2 changed files with 97 additions and 1 deletions

View File

@ -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>>,
}

View File

@ -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::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 @@
mod config;
pub mod highlighter;
mod injections_tree;
mod merge;
mod parse;
mod pretty_print;