aboutsummaryrefslogtreecommitdiff
path: root/helix-core
diff options
context:
space:
mode:
authorBlaž Hrastnik2022-01-07 00:19:20 +0000
committerBlaž Hrastnik2022-01-23 07:04:12 +0000
commit7315f6f3e419d8f433a5cc99d929289ce710f442 (patch)
treeda41ba87de0af01c2722ddafd84f276511a512dc /helix-core
parent8a53e34e668f4816e051173ff079af5a6ac72e03 (diff)
Update range markers so we can determine which layers can be reused
Diffstat (limited to 'helix-core')
-rw-r--r--helix-core/src/syntax.rs84
1 files changed, 73 insertions, 11 deletions
diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs
index f787f92e..75f8536b 100644
--- a/helix-core/src/syntax.rs
+++ b/helix-core/src/syntax.rs
@@ -14,7 +14,7 @@ use slotmap::{DefaultKey as LayerId, HopSlotMap};
use std::{
borrow::Cow,
cell::RefCell,
- collections::{HashMap, HashSet},
+ collections::{HashMap, HashSet, VecDeque},
fmt,
path::Path,
sync::Arc,
@@ -459,7 +459,6 @@ impl Syntax {
source: &Rope,
changeset: &ChangeSet,
) -> Result<(), Error> {
- use std::collections::{HashSet, VecDeque};
let mut queue = VecDeque::new();
queue.push_back(self.root);
@@ -472,23 +471,84 @@ impl Syntax {
};
// HAXX: for now, clear all layers except root so they get re-parsed
- self.layers.retain(|id, _| id == self.root);
+ // self.layers.retain(|id, _| id == self.root);
// Convert the changeset into tree sitter edits.
let edits = generate_edits(old_source, changeset);
// TODO: use the edits to update all layers markers
if !edits.is_empty() {
+ fn point_add(a: Point, b: Point) -> Point {
+ if b.row > 0 {
+ Point::new(a.row.saturating_add(b.row), b.column)
+ } else {
+ Point::new(0, a.column.saturating_add(b.column))
+ }
+ }
+ fn point_sub(a: Point, b: Point) -> Point {
+ if a.row > b.row {
+ Point::new(a.row.saturating_sub(b.row), a.column)
+ } else {
+ Point::new(0, a.column.saturating_sub(b.column))
+ }
+ }
+
for layer in &mut self.layers.values_mut() {
for range in &mut layer.ranges {
- for edit in &edits {
+ for edit in edits.iter().rev() {
+ let is_pure_insertion = edit.old_end_byte == edit.start_byte;
+
// if edit is after range, skip
if edit.start_byte > range.end_byte {
+ // TODO: || (is_noop && edit.start_byte == range.end_byte)
continue;
}
// if edit is before range, shift entire range by len
- if edit.old_end_byte < range.start_byte {}
+ if edit.old_end_byte < range.start_byte {
+ range.start_byte =
+ edit.new_end_byte + (range.start_byte - edit.old_end_byte);
+ range.start_point = point_add(
+ edit.new_end_position,
+ point_sub(range.start_point, edit.old_end_position),
+ );
+
+ range.end_byte = edit
+ .new_end_byte
+ .saturating_add(range.end_byte - edit.old_end_byte);
+ range.end_point = point_add(
+ edit.new_end_position,
+ point_sub(range.end_point, edit.old_end_position),
+ );
+ }
+ // if the edit starts in the space before and extends into the range
+ else if edit.start_byte < range.start_byte {
+ range.start_byte = edit.new_end_byte;
+ range.start_point = edit.new_end_position;
+
+ range.end_byte = range
+ .end_byte
+ .saturating_sub(edit.old_end_byte)
+ .saturating_add(edit.new_end_byte);
+ range.end_point = point_add(
+ edit.new_end_position,
+ point_sub(range.end_point, edit.old_end_position),
+ );
+ }
+ // If the edit is an insertion at the start of the tree, shift
+ else if edit.start_byte == range.start_byte && is_pure_insertion {
+ range.start_byte = edit.new_end_byte;
+ range.start_point = edit.new_end_position;
+ } else {
+ range.end_byte = range
+ .end_byte
+ .saturating_sub(edit.old_end_byte)
+ .saturating_add(edit.new_end_byte);
+ range.end_point = point_add(
+ edit.new_end_position,
+ point_sub(range.end_point, edit.old_end_position),
+ );
+ }
}
}
}
@@ -506,6 +566,9 @@ impl Syntax {
// TODO: we should be able to avoid editing & parsing layers with ranges earlier in the document before the edit
while let Some(layer_id) = queue.pop_front() {
+ // Mark the layer as touched
+ touched.insert(layer_id);
+
let layer = &mut self.layers[layer_id];
// If a tree already exists, notify it of changes.
@@ -610,10 +673,14 @@ impl Syntax {
layer.depth == depth && // TODO: track parent id instead
layer.config.language == config.language && layer.ranges == ranges
})
- .map(|(id, _layer)| id);
+ .map(|(id, _layer)| {
+ log::info!("match! {:?}", id);
+ id
+ });
// ...or insert a new one.
let layer_id = layer.unwrap_or_else(|| {
+ log::info!("miss! {:?}", ranges);
self.layers.insert(LanguageLayer {
tree: None,
config,
@@ -625,9 +692,6 @@ impl Syntax {
queue.push_back(layer_id);
}
- // Mark the layer as touched
- touched.insert(layer_id);
-
// TODO: pre-process local scopes at this time, rather than highlight?
// would solve problems with locals not working across boundaries
}
@@ -723,8 +787,6 @@ impl Syntax {
})
.collect::<Vec<_>>();
- log::info!("--");
-
// HAXX: arrange layers by byte range, with deeper layers positioned first
layers.sort_by_key(|layer| {
(