@@ -9,28 +9,25 @@ import { Event } from '../../../../../../base/common/event.js';
9
9
import { Disposable , IDisposable } from '../../../../../../base/common/lifecycle.js' ;
10
10
import { ResourceMap } from '../../../../../../base/common/map.js' ;
11
11
import { isEqual } from '../../../../../../base/common/resources.js' ;
12
- import { format , noBreakWhitespace } from '../../../../../../base/common/strings.js' ;
13
- import { Constants } from '../../../../../../base/common/uint.js' ;
12
+ import { format } from '../../../../../../base/common/strings.js' ;
14
13
import { Position } from '../../../../../../editor/common/core/position.js' ;
15
14
import { Range } from '../../../../../../editor/common/core/range.js' ;
16
15
import { InlineValueContext , InlineValueText , InlineValueVariableLookup } from '../../../../../../editor/common/languages.js' ;
17
- import { IModelDeltaDecoration , InjectedTextCursorStops , ITextModel } from '../../../../../../editor/common/model.js' ;
16
+ import { IModelDeltaDecoration , ITextModel } from '../../../../../../editor/common/model.js' ;
18
17
import { ILanguageFeaturesService } from '../../../../../../editor/common/services/languageFeatures.js' ;
19
18
import { localize } from '../../../../../../nls.js' ;
20
19
import { registerAction2 } from '../../../../../../platform/actions/common/actions.js' ;
21
20
import { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js' ;
22
21
import { ServicesAccessor } from '../../../../../../platform/instantiation/common/instantiation.js' ;
22
+ import { createInlineValueDecoration } from '../../../../debug/browser/debugEditorContribution.js' ;
23
23
import { IDebugService , State } from '../../../../debug/common/debug.js' ;
24
24
import { NotebookSetting } from '../../../common/notebookCommon.js' ;
25
25
import { ICellExecutionStateChangedEvent , INotebookExecutionStateService , NotebookExecutionType } from '../../../common/notebookExecutionStateService.js' ;
26
- import { INotebookKernelMatchResult , INotebookKernelService , VariablesResult } from '../../../common/notebookKernelService.js' ;
26
+ import { INotebookKernelService , VariablesResult } from '../../../common/notebookKernelService.js' ;
27
27
import { INotebookActionContext , NotebookAction } from '../../controller/coreActions.js' ;
28
28
import { ICellViewModel , INotebookEditor , INotebookEditorContribution } from '../../notebookBrowser.js' ;
29
29
import { registerNotebookContribution } from '../../notebookEditorExtensions.js' ;
30
30
31
- // value from debug, may need to keep an eye on and shorter to account for cells having a narrower viewport width
32
- const MAX_INLINE_DECORATOR_LENGTH = 150 ; // Max string length of each inline decorator. If exceeded ... is added
33
-
34
31
class InlineSegment {
35
32
constructor ( public column : number , public text : string ) {
36
33
}
@@ -136,57 +133,61 @@ export class NotebookInlineVariablesController extends Disposable implements INo
136
133
const fullCellRange = new Range ( 1 , 1 , lastLine , lastColumn ) ;
137
134
138
135
const promises = providers . flatMap ( provider => Promise . resolve ( provider . provideInlineValues ( model , fullCellRange , ctx , token ) ) . then ( async ( result ) => {
139
- if ( result ) {
136
+ if ( ! result ) {
137
+ return ;
138
+ }
140
139
141
- let kernel : INotebookKernelMatchResult ;
142
- const kernelVars : VariablesResult [ ] = [ ] ;
143
- if ( result . some ( iv => iv . type === 'variable' ) ) { // if anyone will need a lookup, get vars now to avoid needing to do it multiple times
144
- if ( ! this . notebookEditor . hasModel ( ) ) {
145
- return ; // should not happen, a cell will be executed
146
- }
147
- kernel = this . notebookKernelService . getMatchingKernel ( this . notebookEditor . textModel ) ;
148
- const variables = kernel . selected ?. provideVariables ( event . notebook , undefined , 'named' , 0 , token ) ;
149
- if ( ! variables ) {
150
- return ;
151
- }
140
+ const notebook = this . notebookEditor . textModel ;
141
+ if ( ! notebook ) {
142
+ return ;
143
+ }
144
+
145
+ const kernel = this . notebookKernelService . getMatchingKernel ( notebook ) ;
146
+ const kernelVars : VariablesResult [ ] = [ ] ;
147
+ if ( result . some ( iv => iv . type === 'variable' ) ) { // if anyone will need a lookup, get vars now to avoid needing to do it multiple times
148
+ if ( ! this . notebookEditor . hasModel ( ) ) {
149
+ return ; // should not happen, a cell will be executed
150
+ }
151
+ const variables = kernel . selected ?. provideVariables ( event . notebook , undefined , 'named' , 0 , token ) ;
152
+ if ( variables ) {
152
153
for await ( const v of variables ) {
153
154
kernelVars . push ( v ) ;
154
155
}
155
156
}
157
+ }
156
158
157
- for ( const iv of result ) {
158
- let text : string | undefined = undefined ;
159
- switch ( iv . type ) {
160
- case 'text' :
161
- text = ( iv as InlineValueText ) . text ;
162
- break ;
163
- case 'variable' : {
164
- const name = ( iv as InlineValueVariableLookup ) . variableName ;
165
- if ( ! name ) {
166
- continue ; // skip to next var, no valid name to lookup with
167
- }
168
- const value = kernelVars . find ( v => v . name === name ) ?. value ;
169
- if ( ! value ) {
170
- continue ;
171
- }
172
- text = format ( '{0} = {1}' , name , value ) ;
173
- break ;
159
+ for ( const iv of result ) {
160
+ let text : string | undefined = undefined ;
161
+ switch ( iv . type ) {
162
+ case 'text' :
163
+ text = ( iv as InlineValueText ) . text ;
164
+ break ;
165
+ case 'variable' : {
166
+ const name = ( iv as InlineValueVariableLookup ) . variableName ;
167
+ if ( ! name ) {
168
+ continue ; // skip to next var, no valid name to lookup with
174
169
}
175
- case 'expression' : {
176
- continue ; // no active debug session, so evaluate would break
170
+ const value = kernelVars . find ( v => v . name === name ) ?. value ;
171
+ if ( ! value ) {
172
+ continue ;
177
173
}
174
+ text = format ( '{0} = {1}' , name , value ) ;
175
+ break ;
178
176
}
177
+ case 'expression' : {
178
+ continue ; // no active debug session, so evaluate would break
179
+ }
180
+ }
179
181
180
- if ( text ) {
181
- const line = iv . range . startLineNumber ;
182
- let lineSegments = lineDecorations . get ( line ) ;
183
- if ( ! lineSegments ) {
184
- lineSegments = [ ] ;
185
- lineDecorations . set ( line , lineSegments ) ;
186
- }
187
- if ( ! lineSegments . some ( iv => iv . text === text ) ) { // de-dupe
188
- lineSegments . push ( new InlineSegment ( iv . range . startColumn , text ) ) ;
189
- }
182
+ if ( text ) {
183
+ const line = iv . range . startLineNumber ;
184
+ let lineSegments = lineDecorations . get ( line ) ;
185
+ if ( ! lineSegments ) {
186
+ lineSegments = [ ] ;
187
+ lineDecorations . set ( line , lineSegments ) ;
188
+ }
189
+ if ( ! lineSegments . some ( iv => iv . text === text ) ) { // de-dupe
190
+ lineSegments . push ( new InlineSegment ( iv . range . startColumn , text ) ) ;
190
191
}
191
192
}
192
193
}
@@ -199,10 +200,18 @@ export class NotebookInlineVariablesController extends Disposable implements INo
199
200
// sort line segments and concatenate them into a decoration
200
201
lineDecorations . forEach ( ( segments , line ) => {
201
202
if ( segments . length > 0 ) {
202
- segments = segments . sort ( ( a , b ) => a . column - b . column ) ;
203
+ segments . sort ( ( a , b ) => a . column - b . column ) ;
203
204
const text = segments . map ( s => s . text ) . join ( ', ' ) ;
204
- inlineDecorations . push ( ...this . createNotebookInlineValueDecoration ( line , text ) ) ;
205
-
205
+ const editorWidth = cell . layoutInfo . editorWidth ;
206
+ const fontInfo = cell . layoutInfo . fontInfo ;
207
+ if ( fontInfo && cell . textModel ) {
208
+ const base = Math . floor ( ( editorWidth - 50 ) / fontInfo . typicalHalfwidthCharacterWidth ) ;
209
+ const lineLength = cell . textModel . getLineLength ( line ) ;
210
+ const available = Math . max ( 0 , base - lineLength ) ;
211
+ inlineDecorations . push ( ...createInlineValueDecoration ( line , text , 'nb' , undefined , available ) ) ;
212
+ } else {
213
+ inlineDecorations . push ( ...createInlineValueDecoration ( line , text , 'nb' ) ) ;
214
+ }
206
215
}
207
216
} ) ;
208
217
@@ -231,6 +240,7 @@ export class NotebookInlineVariablesController extends Disposable implements INo
231
240
const processedVars = new Set < string > ( ) ;
232
241
233
242
const functionRanges = this . getFunctionRanges ( document ) ;
243
+ const lineDecorations = new Map < number , InlineSegment [ ] > ( ) ;
234
244
235
245
// For each variable name found in the kernel results
236
246
for ( const varName of varNames ) {
@@ -270,12 +280,38 @@ export class NotebookInlineVariablesController extends Disposable implements INo
270
280
271
281
if ( lastMatchOutsideFunction ) {
272
282
const inlineVal = varName + ' = ' + vars . find ( v => v . name === varName ) ?. value ;
273
- inlineDecorations . push ( ...this . createNotebookInlineValueDecoration ( lastMatchOutsideFunction . line , inlineVal ) ) ;
283
+
284
+ let lineSegments = lineDecorations . get ( lastMatchOutsideFunction . line ) ;
285
+ if ( ! lineSegments ) {
286
+ lineSegments = [ ] ;
287
+ lineDecorations . set ( lastMatchOutsideFunction . line , lineSegments ) ;
288
+ }
289
+ if ( ! lineSegments . some ( iv => iv . text === inlineVal ) ) { // de-dupe
290
+ lineSegments . push ( new InlineSegment ( lastMatchOutsideFunction . column , inlineVal ) ) ;
291
+ }
274
292
}
275
293
276
294
processedVars . add ( varName ) ;
277
295
}
278
296
297
+ // sort line segments and concatenate them into a decoration
298
+ lineDecorations . forEach ( ( segments , line ) => {
299
+ if ( segments . length > 0 ) {
300
+ segments . sort ( ( a , b ) => a . column - b . column ) ;
301
+ const text = segments . map ( s => s . text ) . join ( ', ' ) ;
302
+ const editorWidth = cell . layoutInfo . editorWidth ;
303
+ const fontInfo = cell . layoutInfo . fontInfo ;
304
+ if ( fontInfo && cell . textModel ) {
305
+ const base = Math . floor ( ( editorWidth - 50 ) / fontInfo . typicalHalfwidthCharacterWidth ) ;
306
+ const lineLength = cell . textModel . getLineLength ( line ) ;
307
+ const available = Math . max ( 0 , base - lineLength ) ;
308
+ inlineDecorations . push ( ...createInlineValueDecoration ( line , text , 'nb' , undefined , available ) ) ;
309
+ } else {
310
+ inlineDecorations . push ( ...createInlineValueDecoration ( line , text , 'nb' ) ) ;
311
+ }
312
+ }
313
+ } ) ;
314
+
279
315
if ( inlineDecorations . length > 0 ) {
280
316
this . updateCellInlineDecorations ( cell , inlineDecorations ) ;
281
317
this . initCellContentListener ( cell ) ;
@@ -421,55 +457,6 @@ export class NotebookInlineVariablesController extends Disposable implements INo
421
457
this . _clearNotebookInlineDecorations ( ) ;
422
458
}
423
459
424
- // taken from /src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts
425
- private createNotebookInlineValueDecoration ( lineNumber : number , contentText : string , column = Constants . MAX_SAFE_SMALL_INTEGER ) : IModelDeltaDecoration [ ] {
426
- // If decoratorText is too long, trim and add ellipses. This could happen for minified files with everything on a single line
427
- if ( contentText . length > MAX_INLINE_DECORATOR_LENGTH ) {
428
- contentText = contentText . substring ( 0 , MAX_INLINE_DECORATOR_LENGTH ) + '...' ;
429
- }
430
-
431
- return [
432
- {
433
- range : {
434
- startLineNumber : lineNumber ,
435
- endLineNumber : lineNumber ,
436
- startColumn : column ,
437
- endColumn : column
438
- } ,
439
- options : {
440
- description : 'nb-inline-value-decoration-spacer' ,
441
- after : {
442
- content : noBreakWhitespace ,
443
- cursorStops : InjectedTextCursorStops . None
444
- } ,
445
- showIfCollapsed : true ,
446
- }
447
- } ,
448
- {
449
- range : {
450
- startLineNumber : lineNumber ,
451
- endLineNumber : lineNumber ,
452
- startColumn : column ,
453
- endColumn : column
454
- } ,
455
- options : {
456
- description : 'nb-inline-value-decoration' ,
457
- after : {
458
- content : this . replaceWsWithNoBreakWs ( contentText ) ,
459
- inlineClassName : 'nb-inline-value' ,
460
- inlineClassNameAffectsLetterSpacing : true ,
461
- cursorStops : InjectedTextCursorStops . None
462
- } ,
463
- showIfCollapsed : true ,
464
- }
465
- } ,
466
- ] ;
467
- }
468
-
469
- private replaceWsWithNoBreakWs ( str : string ) : string {
470
- return str . replace ( / [ \t ] / g, noBreakWhitespace ) ;
471
- }
472
-
473
460
override dispose ( ) : void {
474
461
super . dispose ( ) ;
475
462
this . _clearNotebookInlineDecorations ( ) ;
@@ -478,7 +465,6 @@ export class NotebookInlineVariablesController extends Disposable implements INo
478
465
}
479
466
}
480
467
481
-
482
468
registerNotebookContribution ( NotebookInlineVariablesController . id , NotebookInlineVariablesController ) ;
483
469
484
470
registerAction2 ( class ClearNotebookInlineValues extends NotebookAction {
0 commit comments