@@ -25,13 +25,22 @@ const enum Constants {
2525 MaxResolvedLinkLength = 1024 ,
2626}
2727
28- const candidateMatchers = [
28+ const lineNumberPrefixMatchers = [
2929 // Ripgrep:
30+ // /some/file
3031 // 16:searchresult
3132 // 16: searchresult
3233 // Eslint:
33- // 16:5 error ...
34- / \s * (?< link > (?< line > \d + ) : (?< col > \d + ) ? ) /
34+ // /some/file
35+ // 16:5 error ...
36+ / * (?< link > (?< line > \d + ) : (?< col > \d + ) ? ) /
37+ ] ;
38+
39+ const gitDiffMatchers = [
40+ // --- a/some/file
41+ // +++ b/some/file
42+ // @@ -8,11 +8,11 @@ file content...
43+ / ^ (?< link > @ @ .+ \+ (?< toFileLine > \d + ) , (?< toFileCount > \d + ) @ @ ) /
3544] ;
3645
3746export class TerminalMultiLineLinkDetector implements ITerminalLinkDetector {
@@ -66,7 +75,7 @@ export class TerminalMultiLineLinkDetector implements ITerminalLinkDetector {
6675
6776 // Match against the fallback matchers which are mainly designed to catch paths with spaces
6877 // that aren't possible using the regular mechanism.
69- for ( const matcher of candidateMatchers ) {
78+ for ( const matcher of lineNumberPrefixMatchers ) {
7079 const match = text . match ( matcher ) ;
7180 const group = match ?. groups ;
7281 if ( ! group ) {
@@ -130,7 +139,7 @@ export class TerminalMultiLineLinkDetector implements ITerminalLinkDetector {
130139 uri : linkStat . uri ,
131140 selection : {
132141 startLineNumber : parseInt ( line ) ,
133- startColumn : col ? parseInt ( col ) : 0
142+ startColumn : col ? parseInt ( col ) : 1
134143 } ,
135144 disableTrimColon : true ,
136145 bufferRange : bufferRange ,
@@ -144,6 +153,88 @@ export class TerminalMultiLineLinkDetector implements ITerminalLinkDetector {
144153 }
145154 }
146155
156+ if ( links . length === 0 ) {
157+ for ( const matcher of gitDiffMatchers ) {
158+ const match = text . match ( matcher ) ;
159+ const group = match ?. groups ;
160+ if ( ! group ) {
161+ continue ;
162+ }
163+ const link = group ?. link ;
164+ const toFileLine = group ?. toFileLine ;
165+ const toFileCount = group ?. toFileCount ;
166+ if ( ! link || toFileLine === undefined ) {
167+ continue ;
168+ }
169+
170+ // Don't try resolve any links of excessive length
171+ if ( link . length > Constants . MaxResolvedLinkLength ) {
172+ continue ;
173+ }
174+
175+ this . _logService . trace ( 'terminalMultiLineLinkDetector#detect candidate' , link ) ;
176+
177+
178+ // Scan up looking for the first line that could be a path
179+ let possiblePath : string | undefined ;
180+ for ( let index = startLine - 1 ; index >= 0 ; index -- ) {
181+ // Ignore lines that aren't at the beginning of a wrapped line
182+ if ( this . xterm . buffer . active . getLine ( index ) ! . isWrapped ) {
183+ continue ;
184+ }
185+ const text = getXtermLineContent ( this . xterm . buffer . active , index , index , this . xterm . cols ) ;
186+ const match = text . match ( / \+ \+ \+ b \/ (?< path > .+ ) / ) ;
187+ if ( match ) {
188+ possiblePath = match . groups ?. path ;
189+ break ;
190+ }
191+ }
192+ if ( ! possiblePath ) {
193+ continue ;
194+ }
195+
196+ // Check if the first non-matching line is an absolute or relative link
197+ const linkStat = await this . _linkResolver . resolveLink ( this . _processManager , possiblePath ) ;
198+ if ( linkStat ) {
199+ let type : TerminalBuiltinLinkType ;
200+ if ( linkStat . isDirectory ) {
201+ if ( this . _isDirectoryInsideWorkspace ( linkStat . uri ) ) {
202+ type = TerminalBuiltinLinkType . LocalFolderInWorkspace ;
203+ } else {
204+ type = TerminalBuiltinLinkType . LocalFolderOutsideWorkspace ;
205+ }
206+ } else {
207+ type = TerminalBuiltinLinkType . LocalFile ;
208+ }
209+
210+ // Convert the link to the buffer range
211+ const bufferRange = convertLinkRangeToBuffer ( lines , this . xterm . cols , {
212+ startColumn : 1 ,
213+ startLineNumber : 1 ,
214+ endColumn : 1 + link . length ,
215+ endLineNumber : 1
216+ } , startLine ) ;
217+
218+ const simpleLink : ITerminalSimpleLink = {
219+ text : link ,
220+ uri : linkStat . uri ,
221+ selection : {
222+ startLineNumber : parseInt ( toFileLine ) ,
223+ startColumn : 1 ,
224+ endLineNumber : parseInt ( toFileLine ) + parseInt ( toFileCount )
225+ } ,
226+ bufferRange : bufferRange ,
227+ type
228+ } ;
229+ this . _logService . trace ( 'terminalMultiLineLinkDetector#detect verified link' , simpleLink ) ;
230+ links . push ( simpleLink ) ;
231+
232+ // Break on the first match
233+ break ;
234+ }
235+ }
236+ }
237+
147238 return links ;
148239 }
149240
0 commit comments