@@ -58,6 +58,11 @@ interface IHighlight extends IDisposable {
58
58
match : ISearchResult ;
59
59
}
60
60
61
+ interface IMultiHighlight extends IDisposable {
62
+ decorations : IDecoration [ ] ;
63
+ match : ISearchResult ;
64
+ }
65
+
61
66
const NON_WORD_CHARACTERS = ' ~!@#$%^&*()+`-=[]{}|\\;:"\',./<>?' ;
62
67
const LINES_CACHE_TIME_TO_LIVE = 15 * 1000 ; // 15 secs
63
68
const DEFAULT_HIGHLIGHT_LIMIT = 1000 ;
@@ -67,7 +72,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA
67
72
private _cachedSearchTerm : string | undefined ;
68
73
private _highlightedLines : Set < number > = new Set ( ) ;
69
74
private _highlightDecorations : IHighlight [ ] = [ ] ;
70
- private _selectedDecoration : MutableDisposable < IHighlight > = this . _register ( new MutableDisposable ( ) ) ;
75
+ private _selectedDecoration : MutableDisposable < IMultiHighlight > = this . _register ( new MutableDisposable ( ) ) ;
71
76
private _highlightLimit : number ;
72
77
private _lastSearchOptions : ISearchOptions | undefined ;
73
78
private _highlightTimeout : number | undefined ;
@@ -179,14 +184,20 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA
179
184
) ;
180
185
}
181
186
for ( const match of searchResultsWithHighlight ) {
182
- const decoration = this . _createResultDecoration ( match , searchOptions . decorations ! ) ;
183
- if ( decoration ) {
184
- this . _highlightedLines . add ( decoration . marker . line ) ;
185
- this . _highlightDecorations . push ( { decoration, match, dispose ( ) { decoration . dispose ( ) ; } } ) ;
187
+ const decorations = this . _createResultDecorations ( match , searchOptions . decorations ! , false ) ;
188
+ if ( decorations ) {
189
+ for ( const decoration of decorations ) {
190
+ this . _storeDecoration ( decoration , match ) ;
191
+ }
186
192
}
187
193
}
188
194
}
189
195
196
+ private _storeDecoration ( decoration : IDecoration , match : ISearchResult ) : void {
197
+ this . _highlightedLines . add ( decoration . marker . line ) ;
198
+ this . _highlightDecorations . push ( { decoration, match, dispose ( ) { decoration . dispose ( ) ; } } ) ;
199
+ }
200
+
190
201
private _find ( term : string , startRow : number , startCol : number , searchOptions ?: ISearchOptions ) : ISearchResult | undefined {
191
202
if ( ! this . _terminal || ! term || term . length === 0 ) {
192
203
this . _terminal ?. clearSelection ( ) ;
@@ -666,25 +677,9 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA
666
677
}
667
678
terminal . select ( result . col , result . row , result . size ) ;
668
679
if ( options ) {
669
- const marker = terminal . registerMarker ( - terminal . buffer . active . baseY - terminal . buffer . active . cursorY + result . row ) ;
670
- if ( marker ) {
671
- const decoration = terminal . registerDecoration ( {
672
- marker,
673
- x : result . col ,
674
- width : result . size ,
675
- backgroundColor : options . activeMatchBackground ,
676
- layer : 'top' ,
677
- overviewRulerOptions : {
678
- color : options . activeMatchColorOverviewRuler
679
- }
680
- } ) ;
681
- if ( decoration ) {
682
- const disposables : IDisposable [ ] = [ ] ;
683
- disposables . push ( marker ) ;
684
- disposables . push ( decoration . onRender ( ( e ) => this . _applyStyles ( e , options . activeMatchBorder , true ) ) ) ;
685
- disposables . push ( decoration . onDispose ( ( ) => dispose ( disposables ) ) ) ;
686
- this . _selectedDecoration . value = { decoration, match : result , dispose ( ) { decoration . dispose ( ) ; } } ;
687
- }
680
+ const decorations = this . _createResultDecorations ( result , options , true ) ;
681
+ if ( decorations ) {
682
+ this . _selectedDecoration . value = { decorations, match : result , dispose ( ) { dispose ( decorations ) ; } } ;
688
683
}
689
684
}
690
685
@@ -724,28 +719,45 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA
724
719
* @param options the options for the decoration
725
720
* @returns the {@link IDecoration} or undefined if the marker has already been disposed of
726
721
*/
727
- private _createResultDecoration ( result : ISearchResult , options : ISearchDecorationOptions ) : IDecoration | undefined {
722
+ private _createResultDecorations ( result : ISearchResult , options : ISearchDecorationOptions , isActiveResult : boolean ) : IDecoration [ ] | undefined {
728
723
const terminal = this . _terminal ! ;
729
- const marker = terminal . registerMarker ( - terminal . buffer . active . baseY - terminal . buffer . active . cursorY + result . row ) ;
730
- if ( ! marker ) {
731
- return undefined ;
732
- }
733
- const findResultDecoration = terminal . registerDecoration ( {
734
- marker,
735
- x : result . col ,
736
- width : result . size ,
737
- backgroundColor : options . matchBackground ,
738
- overviewRulerOptions : this . _highlightedLines . has ( marker . line ) ? undefined : {
739
- color : options . matchOverviewRuler ,
740
- position : 'center'
724
+
725
+ // Gather decoration ranges for this match as it could wrap
726
+ const decorationRanges : [ number , number , number ] [ ] = [ ] ;
727
+ let currentCol = result . col ;
728
+ let remainingSize = result . size ;
729
+ let markerOffset = - terminal . buffer . active . baseY - terminal . buffer . active . cursorY + result . row ;
730
+ while ( remainingSize > 0 ) {
731
+ const amountThisRow = Math . min ( terminal . cols - currentCol , remainingSize ) ;
732
+ decorationRanges . push ( [ markerOffset , currentCol , amountThisRow ] ) ;
733
+ currentCol = 0 ;
734
+ remainingSize -= amountThisRow ;
735
+ markerOffset ++ ;
736
+ }
737
+
738
+ // Create the decorations
739
+ const decorations : IDecoration [ ] = [ ] ;
740
+ for ( const range of decorationRanges ) {
741
+ const marker = terminal . registerMarker ( range [ 0 ] ) ;
742
+ const decoration = terminal . registerDecoration ( {
743
+ marker,
744
+ x : range [ 1 ] ,
745
+ width : range [ 2 ] ,
746
+ backgroundColor : isActiveResult ? options . activeMatchBackground : options . matchBackground ,
747
+ overviewRulerOptions : this . _highlightedLines . has ( marker . line ) ? undefined : {
748
+ color : isActiveResult ? options . activeMatchColorOverviewRuler : options . matchOverviewRuler ,
749
+ position : 'center'
750
+ }
751
+ } ) ;
752
+ if ( decoration ) {
753
+ const disposables : IDisposable [ ] = [ ] ;
754
+ disposables . push ( marker ) ;
755
+ disposables . push ( decoration . onRender ( ( e ) => this . _applyStyles ( e , isActiveResult ? options . activeMatchBorder : options . matchBorder , false ) ) ) ;
756
+ disposables . push ( decoration . onDispose ( ( ) => dispose ( disposables ) ) ) ;
757
+ decorations . push ( decoration ) ;
741
758
}
742
- } ) ;
743
- if ( findResultDecoration ) {
744
- const disposables : IDisposable [ ] = [ ] ;
745
- disposables . push ( marker ) ;
746
- disposables . push ( findResultDecoration . onRender ( ( e ) => this . _applyStyles ( e , options . matchBorder , false ) ) ) ;
747
- disposables . push ( findResultDecoration . onDispose ( ( ) => dispose ( disposables ) ) ) ;
748
- }
749
- return findResultDecoration ;
759
+ }
760
+
761
+ return decorations . length === 0 ? undefined : decorations ;
750
762
}
751
763
}
0 commit comments