@@ -75,10 +75,9 @@ export class InlayHintsProvider implements vscode.InlayHintsProvider {
75
75
return undefined ;
76
76
}
77
77
78
- // Locates the inlay hints, and provides the inlay hints within the requested range
79
- return this . locateInlayHintCandidates ( document )
80
- . filter ( candidate => range . intersection ( candidate . range ) )
81
- . map ( candidate => candidate . provide ( ) ) ;
78
+ // Locates the inlay hints candidates within the requested range and provides the inlay hints
79
+ return this . locateInlayHintCandidates ( document , range )
80
+ . map ( candidate => candidate . provide ( ) ) ;
82
81
}
83
82
84
83
resolveInlayHint ( hint : vscode . InlayHint , _token : vscode . CancellationToken ) : vscode . ProviderResult < vscode . InlayHint > {
@@ -89,81 +88,83 @@ export class InlayHintsProvider implements vscode.InlayHintsProvider {
89
88
: undefined ;
90
89
}
91
90
92
- private locateInlayHintCandidates ( document : vscode . TextDocument ) : InlayHintCandidate [ ] {
91
+ private locateInlayHintCandidates ( document : vscode . TextDocument , range : vscode . Range ) : InlayHintCandidate [ ] {
93
92
93
+ // (for performance reasons)
94
94
const lineSeparatorCharacter = config . syntax . lineSeparatorCharacter ;
95
+ const unlabelledSubroutines = config . inlayHints . unlabelledSubroutines ;
96
+ const fallthroughSubroutines = config . inlayHints . fallthroughSubroutines ;
95
97
96
98
const candidates : InlayHintCandidate [ ] = [ ] ;
97
99
98
100
let ongoingCandidates : OngoingInlayHintCandidate [ ] = [ ] ;
99
- let containsCode : boolean = false ;
101
+ let didContainCode : boolean = false ;
100
102
for ( let i = 0 , n = document . lineCount ; i < n ; i ++ ) {
101
103
const line = document . lineAt ( i ) ;
104
+
105
+ // Stops looking for candidates after the range
106
+ const isAfterRange = line . range . start . isAfter ( range . end ) ;
107
+ if ( isAfterRange && ! ongoingCandidates . length ) {
108
+ break ;
109
+ }
110
+
102
111
const sourceCodes = lineToSourceCode ( line . text , lineSeparatorCharacter ) ;
103
112
if ( ! sourceCodes . length || ! sourceCodes [ 0 ] ) {
104
- continue ; // (ignore empty lines )
113
+ continue ; // (ignore empty line )
105
114
}
115
+ const sourceCode = sourceCodes [ 0 ] ;
106
116
107
117
// (saves source code on each previously found candidate)
108
118
ongoingCandidates . forEach ( candidateBuilder => {
109
119
candidateBuilder . sourceCode . push ( ...sourceCodes ) ;
110
120
} ) ;
111
121
112
- // Checks labels (for subroutine starts)
113
- const sourceCode = sourceCodes [ 0 ] ;
114
- if ( this . isValidLabel ( sourceCode , ongoingCandidates ) ) {
115
- if ( ! containsCode ) {
122
+ // Checks labels for subroutine starts (if not after the range)
123
+ if ( ! isAfterRange && this . isValidLabel ( sourceCode , ongoingCandidates ) ) {
124
+ if ( ! didContainCode ) {
116
125
// Discards any previous candidates (labels) because they did not contain code
117
126
ongoingCandidates = [ new OngoingInlayHintCandidate ( line , sourceCodes ) ] ;
118
127
119
- } else if ( config . inlayHints . fallthroughSubroutines ) {
128
+ } else if ( fallthroughSubroutines ) {
120
129
// Creates a new candidate on "falls through" labels
121
130
ongoingCandidates . push ( new OngoingInlayHintCandidate ( line , sourceCodes ) ) ;
122
131
}
123
132
}
124
133
125
134
// Checks source code
126
135
const metered = mainParser . parseInstruction ( sourceCode ) ;
127
- if ( ! metered ) {
128
- // (nothing else to do on unparseable source code)
129
- continue ;
130
- }
131
-
132
- // Checks code
133
- if ( ! this . isCode ( metered ) ) {
134
- // Checks data
135
- if ( ! containsCode && metered . size ) {
136
- // Discards previous candidate (label) because it contains data
137
- ongoingCandidates . pop ( ) ;
138
- }
139
- // (nothing else to do on no-code lines)
140
- continue ;
136
+ if ( ! metered || ! this . isCode ( metered ) ) {
137
+ continue ; // (ignore unparseable source code or no-code (data?) lines)
141
138
}
142
139
143
140
// Creates a new candidate on unlabelled code
144
- if ( ! containsCode && ! ongoingCandidates . length && config . inlayHints . unlabelledSubroutines ) {
141
+ if ( ! didContainCode && ! ongoingCandidates . length && unlabelledSubroutines ) {
145
142
ongoingCandidates = [ new OngoingInlayHintCandidate ( line , sourceCodes ) ] ;
146
143
}
147
- containsCode = true ;
148
144
149
- // Checks subroutine end
145
+ didContainCode = true ;
146
+
147
+ const isBeforeRange = line . range . start . isBefore ( range . start ) ;
148
+
149
+ // Checks subroutine ends
150
150
if ( isUnconditionalJumpOrRetInstruction ( metered . instruction ) ) {
151
- // Ends all incomplete subroutines
152
- candidates . push ( ...this . withUnconditionalJumpOrRetInstruction ( ongoingCandidates , line ) ) ;
151
+ // Ends all incomplete subroutines (if not before the range)
152
+ if ( ! isBeforeRange ) {
153
+ candidates . push ( ...this . withUnconditionalJumpOrRetInstruction ( ongoingCandidates , line ) ) ;
154
+ }
153
155
154
- // (restarts sections )
156
+ // (restarts subroutine lookup )
155
157
ongoingCandidates = [ ] ;
156
- containsCode = false ;
158
+ didContainCode = false ;
157
159
158
- // Checks subroutine conditional exit point
159
- } else if ( this . isValidConditionalExitPoint ( metered . instruction ) ) {
160
- // Subroutine conditional exit point
160
+ // Checks subroutine conditional exit point (if not before the range)
161
+ } else if ( ! isBeforeRange && this . isValidConditionalExitPoint ( metered . instruction ) ) {
161
162
candidates . push ( ...this . withConditionalExitPoint ( ongoingCandidates , line ) ) ;
162
163
}
163
164
}
164
165
165
166
// Completes trailing code as subroutine
166
- if ( ongoingCandidates . length && containsCode ) {
167
+ if ( ongoingCandidates . length && didContainCode ) {
167
168
const line = document . lineAt ( document . lineCount - 1 ) ;
168
169
candidates . push ( ...this . withUnconditionalJumpOrRetInstruction ( ongoingCandidates , line ) ) ;
169
170
}
@@ -229,23 +230,37 @@ export class InlayHintsProvider implements vscode.InlayHintsProvider {
229
230
}
230
231
}
231
232
232
- private withUnconditionalJumpOrRetInstruction ( ongoingCandidates : OngoingInlayHintCandidate [ ] , endLine : vscode . TextLine ) : InlayHintCandidate [ ] {
233
+ /**
234
+ * Materializes the possible InlayHint candidates
235
+ * @returns the InlayHint candidates, before the comment of the first line
236
+ */
237
+ private withUnconditionalJumpOrRetInstruction (
238
+ ongoingCandidates : OngoingInlayHintCandidate [ ] , endLine : vscode . TextLine ) : InlayHintCandidate [ ] {
233
239
234
- return ongoingCandidates . map ( ongingCandidate =>
235
- ongingCandidate . withUnconditionalJumpOrRetInstruction ( endLine ) ) ;
240
+ // (sanity check)
241
+ if ( ! ongoingCandidates . length ) {
242
+ return [ ] ;
243
+ }
244
+
245
+ return ongoingCandidates . map ( ongoingCandidate => ongoingCandidate . withUnconditionalJumpOrRetInstruction ( endLine ) ) ;
236
246
}
237
247
238
- private withConditionalExitPoint ( ongoingCandidates : OngoingInlayHintCandidate [ ] , endLine : vscode . TextLine ) : InlayHintCandidate [ ] {
248
+ /**
249
+ * Materializes the possible InlayHint candidate
250
+ * @returns the InlayHint candidate, before the comment of the last line
251
+ */
252
+ private withConditionalExitPoint (
253
+ ongoingCandidates : OngoingInlayHintCandidate [ ] , endLine : vscode . TextLine ) : InlayHintCandidate [ ] {
239
254
240
- // (sanity check )
255
+ // (sanity checks )
241
256
if ( ! ongoingCandidates . length ) {
242
257
return [ ] ;
243
258
}
244
259
245
- const ongoingCandidate = config . inlayHints . exitPointLabel === "first"
246
- ? ongoingCandidates [ 0 ]
247
- : ongoingCandidates [ ongoingCandidates . length - 1 ] ;
248
- return [ ongoingCandidate . withConditionalExitPoint ( endLine ) ] ;
260
+ return [
261
+ ongoingCandidates [ config . inlayHints . exitPointLabel === "first" ? 0 : ongoingCandidates . length - 1 ]
262
+ . withConditionalExitPoint ( endLine )
263
+ ] ;
249
264
}
250
265
}
251
266
@@ -264,7 +279,7 @@ function documentSelector(): readonly vscode.DocumentFilter[] {
264
279
*/
265
280
class OngoingInlayHintCandidate {
266
281
267
- private readonly startLine : vscode . TextLine ;
282
+ readonly startLine : vscode . TextLine ;
268
283
269
284
readonly sourceCode : SourceCode [ ] ;
270
285
@@ -274,39 +289,49 @@ class OngoingInlayHintCandidate {
274
289
}
275
290
276
291
/**
277
- * Materializes the possible InlayHint candidate
278
- * @returns the InlayHint candidate, before the comment of the first line
292
+ * Materializes the InlayHint candidate
293
+ * @returns the InlayHint candidate
279
294
*/
280
295
withUnconditionalJumpOrRetInstruction ( endLine : vscode . TextLine ) : InlayHintCandidate {
281
296
282
297
// Computes the InlayHint position before the comment of the first line
283
- const lineCommentPosition = this . sourceCode [ 0 ] . beforeLineCommentPosition ;
284
- const hasLineComment = lineCommentPosition >= 0 ;
285
- const positionCharacter = hasLineComment
286
- ? this . startLine . text . substring ( 0 , lineCommentPosition ) . trimEnd ( ) . length
287
- : this . startLine . text . trimEnd ( ) . length ;
288
- const inlayHintPosition = this . startLine . range . end . with ( undefined , positionCharacter ) ;
289
-
290
- return new InlayHintCandidate ( inlayHintPosition ,
291
- this . startLine , endLine , [ ...this . sourceCode ] , hasLineComment ) ;
298
+ const [ position , paddingRight ] = this . positionBeforeLineComment (
299
+ this . startLine , this . sourceCode [ 0 ] ) ;
300
+
301
+ return new InlayHintCandidate (
302
+ position ,
303
+ paddingRight ,
304
+ new vscode . Range ( this . startLine . range . start , endLine . range . end ) ,
305
+ [ ...this . sourceCode ] ) ;
292
306
}
293
307
294
308
/**
295
- * Materializes the possible InlayHint candidate
296
- * @returns the InlayHint candidate, before the comment of the last line
309
+ * Materializes the InlayHint candidate
310
+ * @returns the InlayHint candidate
297
311
*/
298
312
withConditionalExitPoint ( endLine : vscode . TextLine ) : InlayHintCandidate {
299
313
300
314
// Computes the InlayHint position before the comment of the last line
301
- const lineCommentPosition = this . sourceCode [ this . sourceCode . length - 1 ] . beforeLineCommentPosition ;
315
+ const [ position , paddingRight ] = this . positionBeforeLineComment (
316
+ endLine , this . sourceCode [ this . sourceCode . length - 1 ] ) ;
317
+
318
+ return new InlayHintCandidate (
319
+ position ,
320
+ paddingRight ,
321
+ new vscode . Range ( this . startLine . range . start , endLine . range . end ) ,
322
+ [ ...this . sourceCode ] ) ;
323
+ }
324
+
325
+ private positionBeforeLineComment ( line : vscode . TextLine , sourceCode : SourceCode ) : [ vscode . Position , boolean ] {
326
+
327
+ const lineCommentPosition = sourceCode . beforeLineCommentPosition ;
302
328
const hasLineComment = lineCommentPosition >= 0 ;
329
+
303
330
const positionCharacter = hasLineComment
304
- ? endLine . text . substring ( 0 , lineCommentPosition ) . trimEnd ( ) . length
305
- : endLine . text . trimEnd ( ) . length ;
306
- const inlayHintPosition = endLine . range . end . with ( undefined , positionCharacter ) ;
331
+ ? line . text . substring ( 0 , lineCommentPosition ) . trimEnd ( ) . length
332
+ : line . text . trimEnd ( ) . length ;
307
333
308
- return new InlayHintCandidate ( inlayHintPosition ,
309
- this . startLine , endLine , [ ...this . sourceCode ] , hasLineComment ) ;
334
+ return [ line . range . end . with ( undefined , positionCharacter ) , hasLineComment ] ;
310
335
}
311
336
}
312
337
@@ -316,17 +341,16 @@ class OngoingInlayHintCandidate {
316
341
class InlayHintCandidate {
317
342
318
343
private readonly position : vscode . Position ;
344
+ private readonly paddingRight : boolean ;
345
+ private readonly range : vscode . Range ;
319
346
private readonly sourceCode : SourceCode [ ] ;
320
- readonly range : vscode . Range ;
321
- private readonly hasLineComment : boolean ;
322
347
323
- constructor ( position : vscode . Position ,
324
- startLine : vscode . TextLine , endLine : vscode . TextLine , sourceCode : SourceCode [ ] , hasLineComment : boolean ) {
348
+ constructor ( position : vscode . Position , paddingRight : boolean , range : vscode . Range , sourceCode : SourceCode [ ] ) {
325
349
326
350
this . position = position ;
351
+ this . paddingRight = paddingRight ;
352
+ this . range = range ;
327
353
this . sourceCode = sourceCode ;
328
- this . range = new vscode . Range ( startLine . range . start , endLine . range . end ) ;
329
- this . hasLineComment = hasLineComment ;
330
354
}
331
355
332
356
/**
@@ -342,11 +366,10 @@ class InlayHintCandidate {
342
366
343
367
// Computes the InlayHint label
344
368
const label = `${ timing } ${ timingSuffix } ` ;
345
- const paddingRight = this . hasLineComment ; // (only if there are line comments);
346
369
347
- return new InlayHint ( this . position , label , paddingRight ,
370
+ return new InlayHint ( this . position , this . range , label , this . paddingRight ,
348
371
totalTimings , totalTiming , timing , timingSuffix ,
349
- this . sourceCode [ 0 ] , this . range ) ;
372
+ this . sourceCode [ 0 ] ) ;
350
373
}
351
374
}
352
375
@@ -355,27 +378,30 @@ class InlayHintCandidate {
355
378
*/
356
379
class InlayHint extends vscode . InlayHint {
357
380
381
+ private readonly range : vscode . Range ;
382
+
358
383
private readonly timing : string ;
359
384
private readonly timingSuffix : string ;
360
385
private readonly totalTimings : TotalTimings ;
361
386
private readonly totalTiming : TotalTimingMeterable ;
362
- private readonly sourceCodeForLabel : SourceCode ;
363
- private readonly range : vscode . Range ;
364
387
365
- constructor ( position : vscode . Position , label : string , paddingRight : boolean ,
388
+ private readonly sourceCodeWithLabel : SourceCode ;
389
+
390
+ constructor ( position : vscode . Position , range : vscode . Range , label : string , paddingRight : boolean ,
366
391
totalTimings : TotalTimings , totalTiming : TotalTimingMeterable , timing : string , timingSuffix : string ,
367
- sourceCodeForLabel : SourceCode , range : vscode . Range ) {
392
+ sourceCodeWithLabel : SourceCode ) {
368
393
369
394
super ( position , label ) ;
370
395
this . paddingLeft = true ;
371
396
this . paddingRight = paddingRight ;
372
397
398
+ this . range = range ;
399
+
373
400
this . totalTimings = totalTimings ;
374
401
this . totalTiming = totalTiming ;
375
402
this . timing = timing ;
376
403
this . timingSuffix = timingSuffix ;
377
- this . sourceCodeForLabel = sourceCodeForLabel ;
378
- this . range = range ;
404
+ this . sourceCodeWithLabel = sourceCodeWithLabel ;
379
405
}
380
406
381
407
resolve ( ) : vscode . InlayHint {
@@ -385,13 +411,13 @@ class InlayHint extends vscode.InlayHint {
385
411
return this ;
386
412
}
387
413
388
- const label = removeEnd ( this . sourceCodeForLabel . label , ":" ) ;
414
+ const title = removeEnd ( this . sourceCodeWithLabel . label , ":" ) ;
389
415
390
416
// Computes the InlayHint tooltip
391
417
const timingText = `**${ this . timing } **${ this . timingSuffix } ` ;
392
418
const rangeText = printRange ( this . range ) ;
393
419
this . tooltip = new vscode . MarkdownString ( "" , true )
394
- . appendMarkdown ( label ? `### ${ label } \n\n` : "" )
420
+ . appendMarkdown ( title ? `### ${ title } \n\n` : "" )
395
421
. appendMarkdown ( `_${ rangeText } _\n\n` )
396
422
. appendMarkdown ( `${ this . totalTiming . statusBarIcon } ${ this . totalTiming . name } : ${ timingText } \n` )
397
423
. appendMarkdown ( hrMarkdown )
0 commit comments