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