@@ -101,48 +101,47 @@ class HighlightMap:
101
101
102
102
BLOCK_SIZE = 50
103
103
104
- def __init__ (self , text_area_widget : widgets . TextArea ):
105
- self .text_area_widget : widgets . TextArea = text_area_widget
106
- self . uncovered_lines : dict [ int , range ] = {}
104
+ def __init__ (self , text_area : TextArea ):
105
+ self .text_area : TextArea = text_area
106
+ """The text area associated with this highlight map."""
107
107
108
- # A mapping from line index to a list of Highlight instances.
109
- self ._highlights : LineToHighlightsMap = defaultdict (list )
110
- self .reset ()
108
+ self ._highlighted_blocks : set [int ] = set ()
109
+ """The set of blocks that have been highlighted. Each block covers BLOCK_SIZE
110
+ lines.
111
+ """
112
+
113
+ self ._highlights : dict [int , list [Highlight ]] = defaultdict (list )
114
+ """A mapping from line index to a list of Highlight instances."""
111
115
112
116
def reset (self ) -> None :
113
117
"""Reset so that future lookups rebuild the highlight map."""
114
118
self ._highlights .clear ()
115
- line_count = self .document .line_count
116
- uncovered_lines = self .uncovered_lines
117
- uncovered_lines .clear ()
118
- i = end_range = 0
119
- for i in range (0 , line_count , self .BLOCK_SIZE ):
120
- end_range = min (i + self .BLOCK_SIZE , line_count )
121
- line_range = range (i , end_range )
122
- uncovered_lines .update ({j : line_range for j in line_range })
123
- if end_range < line_count :
124
- line_range = range (i , line_count )
125
- uncovered_lines .update ({j : line_range for j in line_range })
119
+ self ._highlighted_blocks .clear ()
126
120
127
121
@property
128
122
def document (self ) -> DocumentBase :
129
123
"""The text document being highlighted."""
130
- return self .text_area_widget .document
124
+ return self .text_area .document
125
+
126
+ def __getitem__ (self , index : int ) -> list [Highlight ]:
127
+ block_index = index // self .BLOCK_SIZE
128
+ if block_index not in self ._highlighted_blocks :
129
+ self ._highlighted_blocks .add (block_index )
130
+ self ._build_part_of_highlight_map (block_index * self .BLOCK_SIZE )
131
+ return self ._highlights [index ]
131
132
132
- def __getitem__ (self , idx : int ) -> list [text_area .Highlight ]:
133
- if idx in self .uncovered_lines :
134
- self ._build_part_of_highlight_map (self .uncovered_lines [idx ])
135
- return self ._highlights [idx ]
133
+ def _build_part_of_highlight_map (self , start_index : int ) -> None :
134
+ """Build part of the highlight map.
136
135
137
- def _build_part_of_highlight_map (self , line_range : range ) -> None :
138
- """Build part of the highlight map."""
136
+ Args:
137
+ start_index: The start of the block of line for which to build the map.
138
+ """
139
139
highlights = self ._highlights
140
- for line_index in line_range :
141
- self .uncovered_lines .pop (line_index )
142
- start_point = (line_range [0 ], 0 )
143
- end_point = (line_range [- 1 ] + 1 , 0 )
140
+ start_point = (start_index , 0 )
141
+ end_index = min (self .document .line_count , start_index + self .BLOCK_SIZE )
142
+ end_point = (end_index , 0 )
144
143
captures = self .document .query_syntax_tree (
145
- self .text_area_widget ._highlight_query ,
144
+ self .text_area ._highlight_query ,
146
145
start_point = start_point ,
147
146
end_point = end_point ,
148
147
)
@@ -160,8 +159,9 @@ def _build_part_of_highlight_map(self, line_range: range) -> None:
160
159
)
161
160
162
161
# Add the middle lines - entire row of this node is highlighted
162
+ middle_highlight = (0 , None , highlight_name )
163
163
for node_row in range (node_start_row + 1 , node_end_row ):
164
- highlights [node_row ].append (( 0 , None , highlight_name ) )
164
+ highlights [node_row ].append (middle_highlight )
165
165
166
166
# Add the last line of the node range
167
167
highlights [node_end_row ].append (
@@ -177,16 +177,16 @@ def _build_part_of_highlight_map(self, line_range: range) -> None:
177
177
# to be sorted in ascending order of ``a``. When two highlights have the same
178
178
# value of ``a`` then the one with the larger a--b range comes first, with ``None``
179
179
# being considered larger than any number.
180
- def sort_key (hl ) -> tuple [int , int , int ]:
181
- a , b , _ = hl
182
- max_range_ind = 1
180
+ def sort_key (highlight : Highlight ) -> tuple [int , int , int ]:
181
+ a , b , _ = highlight
182
+ max_range_index = 1
183
183
if b is None :
184
- max_range_ind = 0
184
+ max_range_index = 0
185
185
b = a
186
- return a , max_range_ind , a - b
186
+ return a , max_range_index , a - b
187
187
188
- for line_index in line_range :
189
- line_highlights = highlights .get (line_index , []).sort (key = sort_key )
188
+ for line_index in range ( start_index , end_index ) :
189
+ highlights .get (line_index , []).sort (key = sort_key )
190
190
191
191
192
192
@dataclass
@@ -708,7 +708,7 @@ def check_consume_key(self, key: str, character: str | None = None) -> bool:
708
708
# Otherwise we capture all printable keys
709
709
return character is not None and character .isprintable ()
710
710
711
- def _build_highlight_map (self ) -> None :
711
+ def _reset_highlights (self ) -> None :
712
712
"""Reset the lazily evaluated highlight map."""
713
713
714
714
if self ._highlight_query :
@@ -1034,7 +1034,7 @@ def _set_document(self, text: str, language: str | None) -> None:
1034
1034
self .document = document
1035
1035
self .wrapped_document = WrappedDocument (document , tab_width = self .indent_width )
1036
1036
self .navigator = DocumentNavigator (self .wrapped_document )
1037
- self ._build_highlight_map ()
1037
+ self ._reset_highlights ()
1038
1038
self .move_cursor ((0 , 0 ))
1039
1039
self ._rewrap_and_refresh_virtual_size ()
1040
1040
@@ -1447,7 +1447,7 @@ def edit(self, edit: Edit) -> EditResult:
1447
1447
1448
1448
self ._refresh_size ()
1449
1449
edit .after (self )
1450
- self ._build_highlight_map ()
1450
+ self ._reset_highlights ()
1451
1451
self .post_message (self .Changed (self ))
1452
1452
return result
1453
1453
@@ -1510,7 +1510,7 @@ def _undo_batch(self, edits: Sequence[Edit]) -> None:
1510
1510
self ._refresh_size ()
1511
1511
for edit in reversed (edits ):
1512
1512
edit .after (self )
1513
- self ._build_highlight_map ()
1513
+ self ._reset_highlights ()
1514
1514
self .post_message (self .Changed (self ))
1515
1515
1516
1516
def _redo_batch (self , edits : Sequence [Edit ]) -> None :
@@ -1558,7 +1558,7 @@ def _redo_batch(self, edits: Sequence[Edit]) -> None:
1558
1558
self ._refresh_size ()
1559
1559
for edit in edits :
1560
1560
edit .after (self )
1561
- self ._build_highlight_map ()
1561
+ self ._reset_highlights ()
1562
1562
self .post_message (self .Changed (self ))
1563
1563
1564
1564
async def _on_key (self , event : events .Key ) -> None :
0 commit comments