@@ -950,6 +950,8 @@ impl Syntax {
950
950
layers,
951
951
next_event : None ,
952
952
last_highlight_range : None ,
953
+ match_highlights : HashMap :: new ( ) ,
954
+ rainbow_nesting_level : 0 ,
953
955
} ;
954
956
result. sort_layers ( ) ;
955
957
result
@@ -1163,6 +1165,9 @@ pub struct HighlightConfiguration {
1163
1165
local_def_capture_index : Option < u32 > ,
1164
1166
local_def_value_capture_index : Option < u32 > ,
1165
1167
local_ref_capture_index : Option < u32 > ,
1168
+ rainbow_capture_index : Option < u32 > ,
1169
+ /// The number of rainbow styles in the current theme.
1170
+ rainbow_styles : AtomicUsize ,
1166
1171
}
1167
1172
1168
1173
#[ derive( Debug ) ]
@@ -1188,6 +1193,11 @@ struct HighlightIter<'a> {
1188
1193
iter_count : usize ,
1189
1194
next_event : Option < HighlightEvent > ,
1190
1195
last_highlight_range : Option < ( usize , usize , usize ) > ,
1196
+ /// A mapping between tree-sitter `QueryMatch` IDs and `Highlights`.
1197
+ /// This can be used to re-use a single highlight for an entire match
1198
+ /// like with rainbow matches.
1199
+ match_highlights : HashMap < u32 , Highlight > ,
1200
+ rainbow_nesting_level : usize ,
1191
1201
}
1192
1202
1193
1203
// Adapter to convert rope chunks to bytes
@@ -1307,13 +1317,15 @@ impl HighlightConfiguration {
1307
1317
let mut local_def_value_capture_index = None ;
1308
1318
let mut local_ref_capture_index = None ;
1309
1319
let mut local_scope_capture_index = None ;
1320
+ let mut rainbow_capture_index = None ;
1310
1321
for ( i, name) in query. capture_names ( ) . iter ( ) . enumerate ( ) {
1311
1322
let i = Some ( i as u32 ) ;
1312
1323
match name. as_str ( ) {
1313
1324
"local.definition" => local_def_capture_index = i,
1314
1325
"local.definition-value" => local_def_value_capture_index = i,
1315
1326
"local.reference" => local_ref_capture_index = i,
1316
1327
"local.scope" => local_scope_capture_index = i,
1328
+ "rainbow" => rainbow_capture_index = i,
1317
1329
_ => { }
1318
1330
}
1319
1331
}
@@ -1342,6 +1354,8 @@ impl HighlightConfiguration {
1342
1354
local_def_capture_index,
1343
1355
local_def_value_capture_index,
1344
1356
local_ref_capture_index,
1357
+ rainbow_capture_index,
1358
+ rainbow_styles : AtomicUsize :: new ( 0 ) ,
1345
1359
} )
1346
1360
}
1347
1361
@@ -1373,7 +1387,6 @@ impl HighlightConfiguration {
1373
1387
let mut best_index = None ;
1374
1388
let mut best_match_len = 0 ;
1375
1389
for ( i, recognized_name) in recognized_names. iter ( ) . enumerate ( ) {
1376
- let recognized_name = recognized_name;
1377
1390
let mut len = 0 ;
1378
1391
let mut matches = true ;
1379
1392
for part in recognized_name. split ( '.' ) {
@@ -1393,6 +1406,13 @@ impl HighlightConfiguration {
1393
1406
. collect ( ) ;
1394
1407
1395
1408
self . highlight_indices . store ( Arc :: new ( indices) ) ;
1409
+
1410
+ let rainbow_styles = recognized_names
1411
+ . iter ( )
1412
+ . filter ( |name| name. starts_with ( "rainbow." ) )
1413
+ . count ( ) ;
1414
+
1415
+ self . rainbow_styles . store ( rainbow_styles, Ordering :: Relaxed ) ;
1396
1416
}
1397
1417
}
1398
1418
@@ -1765,7 +1785,46 @@ impl<'a> Iterator for HighlightIter<'a> {
1765
1785
}
1766
1786
}
1767
1787
1768
- let current_highlight = layer. config . highlight_indices . load ( ) [ capture. index as usize ] ;
1788
+ // If the capture corresponds to the `@rainbow` scope, lookup the match
1789
+ // in the `match_highlights` map. Otherwise, use the highlight from
1790
+ // attempt to replace its default
1791
+ let rainbow_highlight = if layer. config . rainbow_capture_index == Some ( capture. index ) {
1792
+ let rainbow_styles = layer. config . rainbow_styles . load ( Ordering :: Relaxed ) ;
1793
+
1794
+ if rainbow_styles > 0 {
1795
+ if capture_index == 0 {
1796
+ // Initial capture in the match, add the entry and increment
1797
+ // nesting level, wrapping around to the first rainbow color.
1798
+ let next_highlight = Highlight ( self . rainbow_nesting_level ) ;
1799
+
1800
+ self . rainbow_nesting_level =
1801
+ ( self . rainbow_nesting_level + 1 ) % rainbow_styles;
1802
+
1803
+ self . match_highlights . insert ( match_. id ( ) , next_highlight) ;
1804
+
1805
+ Some ( next_highlight)
1806
+ } else if capture_index == match_. captures . len ( ) - 1 {
1807
+ // Final capture in the match, remove the entry and decrement
1808
+ // nesting level, wrapping around to the last rainbow color.
1809
+ self . rainbow_nesting_level = self
1810
+ . rainbow_nesting_level
1811
+ . checked_sub ( 1 )
1812
+ . unwrap_or ( rainbow_styles - 1 ) ;
1813
+
1814
+ self . match_highlights . remove ( & match_. id ( ) )
1815
+ } else {
1816
+ // Any nodes between the first and last re-use the highlight.
1817
+ self . match_highlights . get ( & match_. id ( ) ) . copied ( )
1818
+ }
1819
+ } else {
1820
+ None
1821
+ }
1822
+ } else {
1823
+ None
1824
+ } ;
1825
+
1826
+ let current_highlight = rainbow_highlight
1827
+ . or_else ( || layer. config . highlight_indices . load ( ) [ capture. index as usize ] ) ;
1769
1828
1770
1829
// If this node represents a local definition, then store the current
1771
1830
// highlight value on the local scope entry representing this node.
0 commit comments