mirror of https://github.com/helix-editor/helix
tmp
parent
c4b7b08809
commit
37397ecc6d
@ -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>>,
|
||||
}
|
Loading…
Reference in New Issue