on master help sign in
Try to reuse an existing layer based on layer.ranges
8a53e34Blaž Hrastnik
flake.nix+1−1
@@ -72,7 +72,7 @@
72 };
72 };
73 };
73 };
74 shell = common: prev: {
74 shell = common: prev: {
75− packages = prev.packages ++ (with common.pkgs; [ lld_13 lldb cargo-tarpaulin ]);
75+ packages = prev.packages ++ (with common.pkgs; [ lld_13 lldb cargo-tarpaulin cargo-flamegraph ]);
76 env = prev.env ++ [
76 env = prev.env ++ [
77 { name = "HELIX_RUNTIME"; eval = "$PWD/runtime"; }
77 { name = "HELIX_RUNTIME"; eval = "$PWD/runtime"; }
78 { name = "RUST_BACKTRACE"; value = "1"; }
78 { name = "RUST_BACKTRACE"; value = "1"; }
helix-core/src/syntax.rs+74−33
@@ -459,9 +459,10 @@ impl Syntax {
459 source: &Rope,
459 source: &Rope,
460 changeset: &ChangeSet,
460 changeset: &ChangeSet,
461 ) -> Result<(), Error> {
461 ) -> Result<(), Error> {
462− use std::collections::VecDeque;
462+ use std::collections::{HashSet, VecDeque};
463 let mut queue = VecDeque::new();
463 let mut queue = VecDeque::new();
464− // let source = source.slice(..);
464+ queue.push_back(self.root);
465+
465 let injection_callback = |language: &str| {
466 let injection_callback = |language: &str| {
466 self.loader
467 self.loader
467 .language_configuration_for_injection_string(language)
468 .language_configuration_for_injection_string(language)
@@ -470,21 +471,26 @@ impl Syntax {
470 })
471 })
471 };
472 };
472
473
473− queue.push_back(self.root);
474−
475 // HAXX: for now, clear all layers except root so they get re-parsed
474 // HAXX: for now, clear all layers except root so they get re-parsed
476 self.layers.retain(|id, _| id == self.root);
475 self.layers.retain(|id, _| id == self.root);
477
476
478− // Workaround for Syntax::new() with empty changeset
477+ // Convert the changeset into tree sitter edits.
479− if !changeset.is_empty() {
478+ let edits = generate_edits(old_source, changeset);
480− // TODO: do this in a recursive way
479+
481− // Notify the tree about all the changes
480+ // TODO: use the edits to update all layers markers
482− let edits = generate_edits(old_source.slice(..), changeset);
481+ if !edits.is_empty() {
483− let tree = self.layers[self.root].tree.as_mut().unwrap();
482+ for layer in &mut self.layers.values_mut() {
483+ for range in &mut layer.ranges {
484− for edit in edits.iter().rev() {
484+ for edit in &edits {
485− // apply the edits in reverse. If we applied them in order then edit 1 would disrupt
485+ // if edit is after range, skip
486− // the positioning of edit 2
486+ if edit.start_byte > range.end_byte {
487− tree.edit(edit);
487+ continue;
488+ }
489+
490+ // if edit is before range, shift entire range by len
491+ if edit.old_end_byte < range.start_byte {}
492+ }
493+ }
488 }
494 }
489 }
495 }
490
496
@@ -495,10 +501,26 @@ impl Syntax {
495
501
496 let source_slice = source.slice(..);
502 let source_slice = source.slice(..);
497
503
504+ let mut touched = HashSet::new();
505+
506+ // TODO: we should be able to avoid editing & parsing layers with ranges earlier in the document before the edit
507+
498 while let Some(layer_id) = queue.pop_front() {
508 while let Some(layer_id) = queue.pop_front() {
509+ let layer = &mut self.layers[layer_id];
510+
511+ // If a tree already exists, notify it of changes.
512+ if let Some(tree) = &mut layer.tree {
513+ for edit in edits.iter().rev() {
514+ // Apply the edits in reverse.
515+ // If we applied them in order then edit 1 would disrupt the positioning of edit 2.
516+ tree.edit(edit);
517+ }
518+ }
519+
499 // Re-parse the tree.
520 // Re-parse the tree.
500− self.layers[layer_id].parse(ts_parser, source)?;
521+ layer.parse(ts_parser, source)?;
501
522
523+ // Switch to an immutable borrow.
502 let layer = &self.layers[layer_id];
524 let layer = &self.layers[layer_id];
503
525
504 // Process injections.
526 // Process injections.
@@ -529,7 +551,6 @@ impl Syntax {
529 intersect_ranges(&layer.ranges, &[content_node], include_children);
551 intersect_ranges(&layer.ranges, &[content_node], include_children);
530
552
531 if !ranges.is_empty() {
553 if !ranges.is_empty() {
532− log::info!("{} {:?}", language_name, ranges);
533 injections.push((config, ranges));
554 injections.push((config, ranges));
534 }
555 }
535 }
556 }
@@ -581,28 +602,46 @@ impl Syntax {
581 let depth = layer.depth + 1;
602 let depth = layer.depth + 1;
582 // TODO: can't inline this since matches borrows self.layers
603 // TODO: can't inline this since matches borrows self.layers
583 for (config, ranges) in injections {
604 for (config, ranges) in injections {
605+ // Find an existing layer
606+ let layer = self
607+ .layers
608+ .iter_mut()
609+ .find(|(_, layer)| {
610+ layer.depth == depth && // TODO: track parent id instead
611+ layer.config.language == config.language && layer.ranges == ranges
612+ })
613+ .map(|(id, _layer)| id);
614+
615+ // ...or insert a new one.
616+ let layer_id = layer.unwrap_or_else(|| {
584− let layer_id = self.layers.insert(LanguageLayer {
617+ self.layers.insert(LanguageLayer {
585− tree: None,
618+ tree: None,
586− config,
619+ config,
587− depth,
620+ depth,
588− ranges,
621+ ranges,
622+ })
589 });
623 });
624+
590 queue.push_back(layer_id);
625 queue.push_back(layer_id);
591 }
626 }
627+
628+ // Mark the layer as touched
629+ touched.insert(layer_id);
630+
631+ // TODO: pre-process local scopes at this time, rather than highlight?
632+ // would solve problems with locals not working across boundaries
592 }
633 }
593
634
594 // Return the cursor back in the pool.
635 // Return the cursor back in the pool.
595 ts_parser.cursors.push(cursor);
636 ts_parser.cursors.push(cursor);
596
637
597− Ok(()) // so we can use the try operator
638+ // Remove all untouched layers
598− })?;
639+ self.layers.retain(|id, _| touched.contains(&id));
599
640
600− Ok(())
641+ Ok(())
642+ })
601 }
643 }
602
644
603− // fn buffer_changed -> call layer.update(range, new_text) on root layer and then all marker layers
604− // call this on transaction.apply() -> buffer_changed(changes)
605−
606 pub fn tree(&self) -> &Tree {
645 pub fn tree(&self) -> &Tree {
607 self.layers[self.root].tree()
646 self.layers[self.root].tree()
608 }
647 }
@@ -619,8 +658,6 @@ impl Syntax {
619 //
658 //
620 // layer update:
659 // layer update:
621 // if range.len = 0 then remove the layer
660 // if range.len = 0 then remove the layer
622− // for change in changes { tree.edit(change) }
623− // tree = parser.parse(.., tree, ..)
624 // calculate affected range and update injections
661 // calculate affected range and update injections
625 // injection update:
662 // injection update:
626 // look for existing injections
663 // look for existing injections
@@ -776,7 +813,7 @@ impl LanguageLayer {
776}
813}
777
814
778pub(crate) fn generate_edits(
815pub(crate) fn generate_edits(
779− old_text: RopeSlice,
816+ old_text: &Rope,
780 changeset: &ChangeSet,
817 changeset: &ChangeSet,
781) -> Vec<tree_sitter::InputEdit> {
818) -> Vec<tree_sitter::InputEdit> {
782 use Operation::*;
819 use Operation::*;
@@ -784,11 +821,15 @@ pub(crate) fn generate_edits(
784
821
785 let mut edits = Vec::new();
822 let mut edits = Vec::new();
786
823
824+ if changeset.changes.is_empty() {
825+ return edits;
826+ }
827+
787 let mut iter = changeset.changes.iter().peekable();
828 let mut iter = changeset.changes.iter().peekable();
788
829
789 // TODO; this is a lot easier with Change instead of Operation.
830 // TODO; this is a lot easier with Change instead of Operation.
790
831
791− fn point_at_pos(text: RopeSlice, pos: usize) -> (usize, Point) {
832+ fn point_at_pos(text: &Rope, pos: usize) -> (usize, Point) {
792 let byte = text.char_to_byte(pos); // <- attempted to index past end
833 let byte = text.char_to_byte(pos); // <- attempted to index past end
793 let line = text.char_to_line(pos);
834 let line = text.char_to_line(pos);
794 let line_start_byte = text.line_to_byte(line);
835 let line_start_byte = text.line_to_byte(line);
@@ -1816,7 +1857,7 @@ mod test {
1816 &doc,
1857 &doc,
1817 vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
1858 vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
1818 );
1859 );
1819− let edits = generate_edits(doc.slice(..), transaction.changes());
1860+ let edits = generate_edits(&doc, transaction.changes());
1820 // transaction.apply(&mut state);
1861 // transaction.apply(&mut state);
1821
1862
1822 assert_eq!(
1863 assert_eq!(
@@ -1845,7 +1886,7 @@ mod test {
1845 let mut doc = Rope::from("fn test() {}");
1886 let mut doc = Rope::from("fn test() {}");
1846 let transaction =
1887 let transaction =
1847 Transaction::change(&doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
1888 Transaction::change(&doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
1848− let edits = generate_edits(doc.slice(..), transaction.changes());
1889+ let edits = generate_edits(&doc, transaction.changes());
1849 transaction.apply(&mut doc);
1890 transaction.apply(&mut doc);
1850
1891
1851 assert_eq!(doc, "fn test(a: u32) {}");
1892 assert_eq!(doc, "fn test(a: u32) {}");