@@ -42,10 +42,7 @@ class Highlighter: NSObject {
4242
4343 /// The set of visible indexes in tht text view
4444 lazy private var visibleSet : IndexSet = {
45- guard let range = textView. visibleTextRange else {
46- return IndexSet ( )
47- }
48- return IndexSet ( integersIn: Range ( range) !)
45+ return IndexSet ( integersIn: textView. visibleTextRange ?? NSRange ( ) )
4946 } ( )
5047
5148 // MARK: - UI
@@ -107,7 +104,7 @@ class Highlighter: NSObject {
107104 if !( treeSitterClient? . hasSetText ?? true ) {
108105 treeSitterClient? . setText ( text: textView. string)
109106 }
110- invalidate ( range: entireTextRange)
107+ invalidate ( range: NSRange ( entireTextRange) )
111108 }
112109
113110 /// Sets the language and causes a re-highlight of the entire text.
@@ -129,12 +126,6 @@ private extension Highlighter {
129126 /// Invalidates a given range and adds it to the queue to be highlighted.
130127 /// - Parameter range: The range to invalidate.
131128 func invalidate( range: NSRange ) {
132- invalidate ( range: Range ( range) !)
133- }
134-
135- /// Invalidates a given range and adds it to the queue to be highlighted.
136- /// - Parameter range: The range to invalidate.
137- func invalidate( range: Range < Int > ) {
138129 let set = IndexSet ( integersIn: range)
139130
140131 if set. isEmpty {
@@ -161,31 +152,35 @@ private extension Highlighter {
161152
162153 /// Highlights the given range
163154 /// - Parameter range: The range to request highlights for.
164- func highlight( range nsRange: NSRange ) {
165- let range = Range ( nsRange) !
166- pendingSet. insert ( integersIn: range)
155+ func highlight( range rangeToHighlight: NSRange ) {
156+ pendingSet. insert ( integersIn: rangeToHighlight)
167157
168- treeSitterClient? . queryColorsFor ( range: nsRange ) { [ weak self] highlightRanges in
158+ treeSitterClient? . queryColorsFor ( range: rangeToHighlight ) { [ weak self] highlightRanges in
169159 guard let attributeProvider = self ? . attributeProvider,
170160 let textView = self ? . textView else { return }
171161
172162 // Mark these indices as not pending and valid
173- self ? . pendingSet. remove ( integersIn: range )
174- self ? . validSet. formUnion ( IndexSet ( integersIn: range ) )
163+ self ? . pendingSet. remove ( integersIn: rangeToHighlight )
164+ self ? . validSet. formUnion ( IndexSet ( integersIn: rangeToHighlight ) )
175165
176166 // If this range does not exist in the visible set, we can exit.
177- if !( self ? . visibleSet ?? . init( ) ) . contains ( integersIn: range ) {
167+ if !( self ? . visibleSet ?? . init( ) ) . contains ( integersIn: rangeToHighlight ) {
178168 return
179169 }
180170
181171 // Try to create a text range for invalidating. If this fails we fail silently
182172 guard let textContentManager = textView. textLayoutManager. textContentManager,
183- let textRange = NSTextRange ( nsRange , provider: textContentManager) else {
173+ let textRange = NSTextRange ( rangeToHighlight , provider: textContentManager) else {
184174 return
185175 }
186176
187177 // Loop through each highlight and modify the textStorage accordingly.
188178 textView. textContentStorage. textStorage? . beginEditing ( )
179+
180+ // Create a set of indexes that were not highlighted.
181+ var ignoredIndexes = IndexSet ( integersIn: rangeToHighlight)
182+
183+ // Apply all highlights that need color
189184 for highlight in highlightRanges {
190185 // Does not work:
191186// textView.textLayoutManager.setRenderingAttributes(attributeProvider.attributesFor(highlight.capture),
@@ -196,7 +191,21 @@ private extension Highlighter {
196191 attributeProvider. attributesFor ( highlight. capture) ,
197192 range: highlight. range
198193 )
194+
195+ // Remove highlighted indexes from the "ignored" indexes.
196+ ignoredIndexes. remove ( integersIn: highlight. range)
197+ }
198+
199+ // For any indices left over, we need to apply normal attributes to them
200+ // This fixes the case where characters are changed to have a non-text color, and then are skipped when
201+ // they need to be changed back.
202+ for ignoredRange in ignoredIndexes. rangeView {
203+ textView. textContentStorage. textStorage? . setAttributes (
204+ attributeProvider. attributesFor ( nil ) ,
205+ range: NSRange ( ignoredRange)
206+ )
199207 }
208+
200209 textView. textContentStorage. textStorage? . endEditing ( )
201210
202211 // After applying edits to the text storage we need to invalidate the layout
@@ -227,7 +236,7 @@ private extension Highlighter {
227236private extension Highlighter {
228237 /// Updates the view to highlight newly visible text when the textview is scrolled or bounds change.
229238 @objc func visibleTextChanged( _ notification: Notification ) {
230- visibleSet = IndexSet ( integersIn: Range ( textView. visibleTextRange ?? NSRange ( ) ) ! )
239+ visibleSet = IndexSet ( integersIn: textView. visibleTextRange ?? NSRange ( ) )
231240
232241 // Any indices that are both *not* valid and in the visible text range should be invalidated
233242 let newlyInvalidSet = visibleSet. subtracting ( validSet)
@@ -263,7 +272,7 @@ extension Highlighter: NSTextStorageDelegate {
263272 treeSitterClient? . applyEdit ( edit,
264273 text: textStorage. string) { [ weak self] invalidatedIndexSet in
265274 let indexSet = invalidatedIndexSet
266- . union ( IndexSet ( integersIn: Range ( editedRange) ! ) )
275+ . union ( IndexSet ( integersIn: editedRange) )
267276 // Only invalidate indices that aren't visible.
268277 . intersection ( self ? . visibleSet ?? . init( ) )
269278
0 commit comments