@@ -25,13 +25,22 @@ const enum Constants {
25
25
MaxResolvedLinkLength = 1024 ,
26
26
}
27
27
28
- const candidateMatchers = [
28
+ const lineNumberPrefixMatchers = [
29
29
// Ripgrep:
30
+ // /some/file
30
31
// 16:searchresult
31
32
// 16: searchresult
32
33
// 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 + ) @ @ ) /
35
44
] ;
36
45
37
46
export class TerminalMultiLineLinkDetector implements ITerminalLinkDetector {
@@ -66,7 +75,7 @@ export class TerminalMultiLineLinkDetector implements ITerminalLinkDetector {
66
75
67
76
// Match against the fallback matchers which are mainly designed to catch paths with spaces
68
77
// that aren't possible using the regular mechanism.
69
- for ( const matcher of candidateMatchers ) {
78
+ for ( const matcher of lineNumberPrefixMatchers ) {
70
79
const match = text . match ( matcher ) ;
71
80
const group = match ?. groups ;
72
81
if ( ! group ) {
@@ -130,7 +139,7 @@ export class TerminalMultiLineLinkDetector implements ITerminalLinkDetector {
130
139
uri : linkStat . uri ,
131
140
selection : {
132
141
startLineNumber : parseInt ( line ) ,
133
- startColumn : col ? parseInt ( col ) : 0
142
+ startColumn : col ? parseInt ( col ) : 1
134
143
} ,
135
144
disableTrimColon : true ,
136
145
bufferRange : bufferRange ,
@@ -144,6 +153,88 @@ export class TerminalMultiLineLinkDetector implements ITerminalLinkDetector {
144
153
}
145
154
}
146
155
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
+
147
238
return links ;
148
239
}
149
240
0 commit comments