|
|
@ -459,9 +459,10 @@ impl Syntax {
|
|
|
|
source: &Rope,
|
|
|
|
source: &Rope,
|
|
|
|
changeset: &ChangeSet,
|
|
|
|
changeset: &ChangeSet,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
use std::collections::VecDeque;
|
|
|
|
use std::collections::{HashSet, VecDeque};
|
|
|
|
let mut queue = VecDeque::new();
|
|
|
|
let mut queue = VecDeque::new();
|
|
|
|
// let source = source.slice(..);
|
|
|
|
queue.push_back(self.root);
|
|
|
|
|
|
|
|
|
|
|
|
let injection_callback = |language: &str| {
|
|
|
|
let injection_callback = |language: &str| {
|
|
|
|
self.loader
|
|
|
|
self.loader
|
|
|
|
.language_configuration_for_injection_string(language)
|
|
|
|
.language_configuration_for_injection_string(language)
|
|
|
@ -470,21 +471,26 @@ impl Syntax {
|
|
|
|
})
|
|
|
|
})
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
queue.push_back(self.root);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// HAXX: for now, clear all layers except root so they get re-parsed
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
|
|
|
|
// Workaround for Syntax::new() with empty changeset
|
|
|
|
// Convert the changeset into tree sitter edits.
|
|
|
|
if !changeset.is_empty() {
|
|
|
|
let edits = generate_edits(old_source, changeset);
|
|
|
|
// TODO: do this in a recursive way
|
|
|
|
|
|
|
|
// Notify the tree about all the changes
|
|
|
|
// TODO: use the edits to update all layers markers
|
|
|
|
let edits = generate_edits(old_source.slice(..), changeset);
|
|
|
|
if !edits.is_empty() {
|
|
|
|
let tree = self.layers[self.root].tree.as_mut().unwrap();
|
|
|
|
for layer in &mut self.layers.values_mut() {
|
|
|
|
for edit in edits.iter().rev() {
|
|
|
|
for range in &mut layer.ranges {
|
|
|
|
// apply the edits in reverse. If we applied them in order then edit 1 would disrupt
|
|
|
|
for edit in &edits {
|
|
|
|
// the positioning of edit 2
|
|
|
|
// if edit is after range, skip
|
|
|
|
tree.edit(edit);
|
|
|
|
if 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 {}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -495,10 +501,26 @@ impl Syntax {
|
|
|
|
|
|
|
|
|
|
|
|
let source_slice = source.slice(..);
|
|
|
|
let source_slice = source.slice(..);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut touched = HashSet::new();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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() {
|
|
|
|
while let Some(layer_id) = queue.pop_front() {
|
|
|
|
|
|
|
|
let layer = &mut self.layers[layer_id];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If a tree already exists, notify it of changes.
|
|
|
|
|
|
|
|
if let Some(tree) = &mut layer.tree {
|
|
|
|
|
|
|
|
for edit in edits.iter().rev() {
|
|
|
|
|
|
|
|
// Apply the edits in reverse.
|
|
|
|
|
|
|
|
// If we applied them in order then edit 1 would disrupt the positioning of edit 2.
|
|
|
|
|
|
|
|
tree.edit(edit);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Re-parse the tree.
|
|
|
|
// Re-parse the tree.
|
|
|
|
self.layers[layer_id].parse(ts_parser, source)?;
|
|
|
|
layer.parse(ts_parser, source)?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Switch to an immutable borrow.
|
|
|
|
let layer = &self.layers[layer_id];
|
|
|
|
let layer = &self.layers[layer_id];
|
|
|
|
|
|
|
|
|
|
|
|
// Process injections.
|
|
|
|
// Process injections.
|
|
|
@ -529,7 +551,6 @@ impl Syntax {
|
|
|
|
intersect_ranges(&layer.ranges, &[content_node], include_children);
|
|
|
|
intersect_ranges(&layer.ranges, &[content_node], include_children);
|
|
|
|
|
|
|
|
|
|
|
|
if !ranges.is_empty() {
|
|
|
|
if !ranges.is_empty() {
|
|
|
|
log::info!("{} {:?}", language_name, ranges);
|
|
|
|
|
|
|
|
injections.push((config, ranges));
|
|
|
|
injections.push((config, ranges));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -581,28 +602,46 @@ impl Syntax {
|
|
|
|
let depth = layer.depth + 1;
|
|
|
|
let depth = layer.depth + 1;
|
|
|
|
// TODO: can't inline this since matches borrows self.layers
|
|
|
|
// TODO: can't inline this since matches borrows self.layers
|
|
|
|
for (config, ranges) in injections {
|
|
|
|
for (config, ranges) in injections {
|
|
|
|
let layer_id = self.layers.insert(LanguageLayer {
|
|
|
|
// Find an existing layer
|
|
|
|
tree: None,
|
|
|
|
let layer = self
|
|
|
|
config,
|
|
|
|
.layers
|
|
|
|
depth,
|
|
|
|
.iter_mut()
|
|
|
|
ranges,
|
|
|
|
.find(|(_, layer)| {
|
|
|
|
|
|
|
|
layer.depth == depth && // TODO: track parent id instead
|
|
|
|
|
|
|
|
layer.config.language == config.language && layer.ranges == ranges
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.map(|(id, _layer)| id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ...or insert a new one.
|
|
|
|
|
|
|
|
let layer_id = layer.unwrap_or_else(|| {
|
|
|
|
|
|
|
|
self.layers.insert(LanguageLayer {
|
|
|
|
|
|
|
|
tree: None,
|
|
|
|
|
|
|
|
config,
|
|
|
|
|
|
|
|
depth,
|
|
|
|
|
|
|
|
ranges,
|
|
|
|
|
|
|
|
})
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
queue.push_back(layer_id);
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return the cursor back in the pool.
|
|
|
|
// Return the cursor back in the pool.
|
|
|
|
ts_parser.cursors.push(cursor);
|
|
|
|
ts_parser.cursors.push(cursor);
|
|
|
|
|
|
|
|
|
|
|
|
Ok(()) // so we can use the try operator
|
|
|
|
// Remove all untouched layers
|
|
|
|
})?;
|
|
|
|
self.layers.retain(|id, _| touched.contains(&id));
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// fn buffer_changed -> call layer.update(range, new_text) on root layer and then all marker layers
|
|
|
|
|
|
|
|
// call this on transaction.apply() -> buffer_changed(changes)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn tree(&self) -> &Tree {
|
|
|
|
pub fn tree(&self) -> &Tree {
|
|
|
|
self.layers[self.root].tree()
|
|
|
|
self.layers[self.root].tree()
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -619,8 +658,6 @@ impl Syntax {
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// layer update:
|
|
|
|
// layer update:
|
|
|
|
// if range.len = 0 then remove the layer
|
|
|
|
// if range.len = 0 then remove the layer
|
|
|
|
// for change in changes { tree.edit(change) }
|
|
|
|
|
|
|
|
// tree = parser.parse(.., tree, ..)
|
|
|
|
|
|
|
|
// calculate affected range and update injections
|
|
|
|
// calculate affected range and update injections
|
|
|
|
// injection update:
|
|
|
|
// injection update:
|
|
|
|
// look for existing injections
|
|
|
|
// look for existing injections
|
|
|
@ -776,7 +813,7 @@ impl LanguageLayer {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub(crate) fn generate_edits(
|
|
|
|
pub(crate) fn generate_edits(
|
|
|
|
old_text: RopeSlice,
|
|
|
|
old_text: &Rope,
|
|
|
|
changeset: &ChangeSet,
|
|
|
|
changeset: &ChangeSet,
|
|
|
|
) -> Vec<tree_sitter::InputEdit> {
|
|
|
|
) -> Vec<tree_sitter::InputEdit> {
|
|
|
|
use Operation::*;
|
|
|
|
use Operation::*;
|
|
|
@ -784,11 +821,15 @@ pub(crate) fn generate_edits(
|
|
|
|
|
|
|
|
|
|
|
|
let mut edits = Vec::new();
|
|
|
|
let mut edits = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if changeset.changes.is_empty() {
|
|
|
|
|
|
|
|
return edits;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let mut iter = changeset.changes.iter().peekable();
|
|
|
|
let mut iter = changeset.changes.iter().peekable();
|
|
|
|
|
|
|
|
|
|
|
|
// TODO; this is a lot easier with Change instead of Operation.
|
|
|
|
// TODO; this is a lot easier with Change instead of Operation.
|
|
|
|
|
|
|
|
|
|
|
|
fn point_at_pos(text: RopeSlice, pos: usize) -> (usize, Point) {
|
|
|
|
fn point_at_pos(text: &Rope, pos: usize) -> (usize, Point) {
|
|
|
|
let byte = text.char_to_byte(pos); // <- attempted to index past end
|
|
|
|
let byte = text.char_to_byte(pos); // <- attempted to index past end
|
|
|
|
let line = text.char_to_line(pos);
|
|
|
|
let line = text.char_to_line(pos);
|
|
|
|
let line_start_byte = text.line_to_byte(line);
|
|
|
|
let line_start_byte = text.line_to_byte(line);
|
|
|
@ -1816,7 +1857,7 @@ mod test {
|
|
|
|
&doc,
|
|
|
|
&doc,
|
|
|
|
vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
|
|
|
|
vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
let edits = generate_edits(doc.slice(..), transaction.changes());
|
|
|
|
let edits = generate_edits(&doc, transaction.changes());
|
|
|
|
// transaction.apply(&mut state);
|
|
|
|
// transaction.apply(&mut state);
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
assert_eq!(
|
|
|
@ -1845,7 +1886,7 @@ mod test {
|
|
|
|
let mut doc = Rope::from("fn test() {}");
|
|
|
|
let mut doc = Rope::from("fn test() {}");
|
|
|
|
let transaction =
|
|
|
|
let transaction =
|
|
|
|
Transaction::change(&doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
|
|
|
|
Transaction::change(&doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
|
|
|
|
let edits = generate_edits(doc.slice(..), transaction.changes());
|
|
|
|
let edits = generate_edits(&doc, transaction.changes());
|
|
|
|
transaction.apply(&mut doc);
|
|
|
|
transaction.apply(&mut doc);
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(doc, "fn test(a: u32) {}");
|
|
|
|
assert_eq!(doc, "fn test(a: u32) {}");
|
|
|
|