@@ -12,9 +12,27 @@ const SEARCH_RESULT_SELECTOR = { language: 'search-result' };
1212const DIRECTIVES = [ '# Query:' , '# Flags:' , '# Including:' , '# Excluding:' , '# ContextLines:' ] ;
1313const FLAGS = [ 'RegExp' , 'CaseSensitive' , 'IgnoreExcludeSettings' , 'WordMatch' ] ;
1414
15- let cachedLastParse : { version : number , parse : ParsedSearchResults } | undefined ;
15+ let cachedLastParse : { version : number , parse : ParsedSearchResults , uri : vscode . Uri } | undefined ;
16+ let documentChangeListener : vscode . Disposable | undefined ;
17+
1618
1719export function activate ( context : vscode . ExtensionContext ) {
20+
21+ const contextLineDecorations = vscode . window . createTextEditorDecorationType ( { opacity : '0.7' } ) ;
22+ const matchLineDecorations = vscode . window . createTextEditorDecorationType ( { fontWeight : 'bold' } ) ;
23+
24+ const decorate = ( editor : vscode . TextEditor ) => {
25+ const parsed = parseSearchResults ( editor . document ) . filter ( isResultLine ) ;
26+ const contextRanges = parsed . filter ( line => line . isContext ) . map ( line => line . prefixRange ) ;
27+ const matchRanges = parsed . filter ( line => ! line . isContext ) . map ( line => line . prefixRange ) ;
28+ editor . setDecorations ( contextLineDecorations , contextRanges ) ;
29+ editor . setDecorations ( matchLineDecorations , matchRanges ) ;
30+ } ;
31+
32+ if ( vscode . window . activeTextEditor && vscode . window . activeTextEditor . document . languageId === 'search-result' ) {
33+ decorate ( vscode . window . activeTextEditor ) ;
34+ }
35+
1836 context . subscriptions . push (
1937 vscode . commands . registerCommand ( 'searchResult.rerunSearch' , ( ) => vscode . commands . executeCommand ( 'search.action.rerunEditorSearch' ) ) ,
2038 vscode . commands . registerCommand ( 'searchResult.rerunSearchWithContext' , ( ) => vscode . commands . executeCommand ( 'search.action.rerunEditorSearchWithContext' ) ) ,
@@ -84,15 +102,24 @@ export function activate(context: vscode.ExtensionContext) {
84102 }
85103 } ) ,
86104
87- vscode . window . onDidChangeActiveTextEditor ( e => {
88- if ( e ?. document . languageId === 'search-result' ) {
105+ vscode . window . onDidChangeActiveTextEditor ( editor => {
106+ if ( editor ?. document . languageId === 'search-result' ) {
89107 // Clear the parse whenever we open a new editor.
90108 // Conservative because things like the URI might remain constant even if the contents change, and re-parsing even large files is relatively fast.
91109 cachedLastParse = undefined ;
110+
111+ documentChangeListener ?. dispose ( ) ;
112+ documentChangeListener = vscode . workspace . onDidChangeTextDocument ( doc => {
113+ if ( doc . document . uri === editor . document . uri ) {
114+ decorate ( editor ) ;
115+ }
116+ } ) ;
117+
118+ decorate ( editor ) ;
92119 }
93120 } ) ,
94121
95- { dispose ( ) { cachedLastParse = undefined ; } }
122+ { dispose ( ) { cachedLastParse = undefined ; documentChangeListener ?. dispose ( ) ; } }
96123 ) ;
97124}
98125
@@ -129,14 +156,15 @@ function relativePathToUri(path: string, resultsUri: vscode.Uri): vscode.Uri | u
129156}
130157
131158type ParsedSearchFileLine = { type : 'file' , location : vscode . LocationLink , allLocations : vscode . LocationLink [ ] , path : string } ;
132- type ParsedSearchResultLine = { type : 'result' , location : vscode . LocationLink } ;
159+ type ParsedSearchResultLine = { type : 'result' , location : vscode . LocationLink , isContext : boolean , prefixRange : vscode . Range } ;
133160type ParsedSearchResults = Array < ParsedSearchFileLine | ParsedSearchResultLine > ;
134161const isFileLine = ( line : ParsedSearchResultLine | ParsedSearchFileLine ) : line is ParsedSearchFileLine => line . type === 'file' ;
162+ const isResultLine = ( line : ParsedSearchResultLine | ParsedSearchFileLine ) : line is ParsedSearchResultLine => line . type === 'result' ;
135163
136164
137- function parseSearchResults ( document : vscode . TextDocument , token : vscode . CancellationToken ) : ParsedSearchResults {
165+ function parseSearchResults ( document : vscode . TextDocument , token ? : vscode . CancellationToken ) : ParsedSearchResults {
138166
139- if ( cachedLastParse && cachedLastParse . version === document . version ) {
167+ if ( cachedLastParse && cachedLastParse . uri === document . uri && cachedLastParse . version === document . version ) {
140168 return cachedLastParse . parse ;
141169 }
142170
@@ -147,7 +175,8 @@ function parseSearchResults(document: vscode.TextDocument, token: vscode.Cancell
147175 let currentTargetLocations : vscode . LocationLink [ ] | undefined = undefined ;
148176
149177 for ( let i = 0 ; i < lines . length ; i ++ ) {
150- if ( token . isCancellationRequested ) { return [ ] ; }
178+ // TODO: This is probably always false, given we're pegging the thread...
179+ if ( token ?. isCancellationRequested ) { return [ ] ; }
151180 const line = lines [ i ] ;
152181
153182 const fileLine = FILE_LINE_REGEX . exec ( line ) ;
@@ -186,13 +215,14 @@ function parseSearchResults(document: vscode.TextDocument, token: vscode.Cancell
186215
187216 currentTargetLocations ?. push ( location ) ;
188217
189- links [ i ] = { type : 'result' , location } ;
218+ links [ i ] = { type : 'result' , location, isContext : seperator === ' ' , prefixRange : new vscode . Range ( i , 0 , i , metadataOffset ) } ;
190219 }
191220 }
192221
193222 cachedLastParse = {
194223 version : document . version ,
195- parse : links
224+ parse : links ,
225+ uri : document . uri
196226 } ;
197227
198228 return links ;
0 commit comments