@@ -7,16 +7,19 @@ use crate::{
7
7
Rope , RopeSlice , Tendril ,
8
8
} ;
9
9
10
+ use ahash:: RandomState ;
10
11
use arc_swap:: { ArcSwap , Guard } ;
11
12
use bitflags:: bitflags;
13
+ use hashbrown:: raw:: RawTable ;
12
14
use slotmap:: { DefaultKey as LayerId , HopSlotMap } ;
13
15
14
16
use std:: {
15
17
borrow:: Cow ,
16
18
cell:: RefCell ,
17
19
collections:: { HashMap , VecDeque } ,
18
20
fmt,
19
- mem:: replace,
21
+ hash:: { Hash , Hasher } ,
22
+ mem:: { replace, transmute} ,
20
23
path:: Path ,
21
24
str:: FromStr ,
22
25
sync:: Arc ,
@@ -770,30 +773,38 @@ impl Syntax {
770
773
// Convert the changeset into tree sitter edits.
771
774
let edits = generate_edits ( old_source, changeset) ;
772
775
776
+ // This table allows inverse indexing of `layers`.
777
+ // That is by hashing a `Layer` you can find
778
+ // the `LayerId` of an existing equivalent `Layer` in `layers`.
779
+ //
780
+ // It is used to determine if a new layer exists for an injection
781
+ // or if an existing layer needs to be updated.
782
+ let mut layers_table = RawTable :: with_capacity ( self . layers . len ( ) ) ;
783
+ let layers_hasher = RandomState :: new ( ) ;
773
784
// Use the edits to update all layers markers
774
- if !edits. is_empty ( ) {
775
- fn point_add ( a : Point , b : Point ) -> Point {
776
- if b. row > 0 {
777
- Point :: new ( a. row . saturating_add ( b. row ) , b. column )
778
- } else {
779
- Point :: new ( 0 , a. column . saturating_add ( b. column ) )
780
- }
785
+ fn point_add ( a : Point , b : Point ) -> Point {
786
+ if b. row > 0 {
787
+ Point :: new ( a. row . saturating_add ( b. row ) , b. column )
788
+ } else {
789
+ Point :: new ( 0 , a. column . saturating_add ( b. column ) )
781
790
}
782
- fn point_sub ( a : Point , b : Point ) -> Point {
783
- if a . row > b . row {
784
- Point :: new ( a. row . saturating_sub ( b. row ) , a . column )
785
- } else {
786
- Point :: new ( 0 , a . column . saturating_sub ( b . column ) )
787
- }
791
+ }
792
+ fn point_sub ( a : Point , b : Point ) -> Point {
793
+ if a. row > b. row {
794
+ Point :: new ( a . row . saturating_sub ( b . row ) , a . column )
795
+ } else {
796
+ Point :: new ( 0 , a . column . saturating_sub ( b . column ) )
788
797
}
798
+ }
789
799
790
- for layer in self . layers . values_mut ( ) {
791
- // The root layer always covers the whole range (0..usize::MAX)
792
- if layer. depth == 0 {
793
- layer. flags = LayerUpdateFlags :: MODIFIED ;
794
- continue ;
795
- }
800
+ for ( layer_id , layer) in self . layers . iter_mut ( ) {
801
+ // The root layer always covers the whole range (0..usize::MAX)
802
+ if layer. depth == 0 {
803
+ layer. flags = LayerUpdateFlags :: MODIFIED ;
804
+ continue ;
805
+ }
796
806
807
+ if !edits. is_empty ( ) {
797
808
for range in & mut layer. ranges {
798
809
// Roughly based on https://github.com/tree-sitter/tree-sitter/blob/ddeaa0c7f534268b35b4f6cb39b52df082754413/lib/src/subtree.c#L691-L720
799
810
for edit in edits. iter ( ) . rev ( ) {
@@ -858,6 +869,12 @@ impl Syntax {
858
869
}
859
870
}
860
871
}
872
+
873
+ let hash = layers_hasher. hash_one ( layer) ;
874
+ // Safety: insert_no_grow is unsafe because it assumes that the table
875
+ // has enough capacity to hold additional elements.
876
+ // This is always the case as we reserved enough capacity above.
877
+ unsafe { layers_table. insert_no_grow ( hash, layer_id) } ;
861
878
}
862
879
863
880
PARSER . with ( |ts_parser| {
@@ -982,27 +999,23 @@ impl Syntax {
982
999
let depth = layer. depth + 1 ;
983
1000
// TODO: can't inline this since matches borrows self.layers
984
1001
for ( config, ranges) in injections {
985
- // Find an existing layer
986
- let layer = self
987
- . layers
988
- . iter_mut ( )
989
- . find ( |( _, layer) | {
990
- layer. depth == depth && // TODO: track parent id instead
991
- layer. config . language == config. language && layer. ranges == ranges
1002
+ let new_layer = LanguageLayer {
1003
+ tree : None ,
1004
+ config,
1005
+ depth,
1006
+ ranges,
1007
+ flags : LayerUpdateFlags :: empty ( ) ,
1008
+ } ;
1009
+
1010
+ // Find an identical existing layer
1011
+ let layer = layers_table
1012
+ . get ( layers_hasher. hash_one ( & new_layer) , |& it| {
1013
+ self . layers [ it] == new_layer
992
1014
} )
993
- . map ( | ( id , _layer ) | id ) ;
1015
+ . copied ( ) ;
994
1016
995
1017
// ...or insert a new one.
996
- let layer_id = layer. unwrap_or_else ( || {
997
- self . layers . insert ( LanguageLayer {
998
- tree : None ,
999
- config,
1000
- depth,
1001
- ranges,
1002
- // set the modified flag to ensure the layer is parsed
1003
- flags : LayerUpdateFlags :: empty ( ) ,
1004
- } )
1005
- } ) ;
1018
+ let layer_id = layer. unwrap_or_else ( || self . layers . insert ( new_layer) ) ;
1006
1019
1007
1020
queue. push_back ( layer_id) ;
1008
1021
}
@@ -1139,6 +1152,34 @@ pub struct LanguageLayer {
1139
1152
flags : LayerUpdateFlags ,
1140
1153
}
1141
1154
1155
+ /// This PartialEq implementation only checks if that
1156
+ /// two layers are theoretically identical (meaning they highlight the same text range with the same language).
1157
+ /// It does not check whether the layers have the same internal treesitter
1158
+ /// state.
1159
+ impl PartialEq for LanguageLayer {
1160
+ fn eq ( & self , other : & Self ) -> bool {
1161
+ self . depth == other. depth
1162
+ && self . config . language == other. config . language
1163
+ && self . ranges == other. ranges
1164
+ }
1165
+ }
1166
+
1167
+ /// Hash implementation belongs to PartialEq implementation above.
1168
+ /// See its documentation for details.
1169
+ impl Hash for LanguageLayer {
1170
+ fn hash < H : Hasher > ( & self , state : & mut H ) {
1171
+ self . depth . hash ( state) ;
1172
+ // The transmute is necessary here because tree_sitter::Language does not derive Hash at the moment.
1173
+ // However it does use #[repr] transparent so the transmute here is safe
1174
+ // as `Language` (which `Grammar` is an alias for) is just a newtype wrapper around a (thin) pointer.
1175
+ // This is also compatible with the PartialEq implementation of language
1176
+ // as that is just a pointer comparison.
1177
+ let language: * const ( ) = unsafe { transmute ( self . config . language ) } ;
1178
+ language. hash ( state) ;
1179
+ self . ranges . hash ( state) ;
1180
+ }
1181
+ }
1182
+
1142
1183
impl LanguageLayer {
1143
1184
pub fn tree ( & self ) -> & Tree {
1144
1185
// TODO: no unwrap
0 commit comments