2
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
4
*--------------------------------------------------------------------------------------------*/
5
- import { getWindow } from '../../../../../../base/browser/dom.js' ;
5
+ import { $ , getWindow } from '../../../../../../base/browser/dom.js' ;
6
6
import { ActionViewItem } from '../../../../../../base/browser/ui/actionbar/actionViewItems.js' ;
7
7
import { IAction } from '../../../../../../base/common/actions.js' ;
8
8
import { Color } from '../../../../../../base/common/color.js' ;
9
9
import { structuralEquals } from '../../../../../../base/common/equals.js' ;
10
10
import { Disposable } from '../../../../../../base/common/lifecycle.js' ;
11
- import { IObservable , autorun , constObservable , derived , derivedObservableWithCache , derivedOpts , observableFromEvent , observableValue } from '../../../../../../base/common/observable.js' ;
11
+ import { IObservable , autorun , constObservable , derived , derivedObservableWithCache , derivedOpts , observableFromEvent } from '../../../../../../base/common/observable.js' ;
12
12
import { MenuId , MenuItemAction } from '../../../../../../platform/actions/common/actions.js' ;
13
13
import { ICommandService } from '../../../../../../platform/commands/common/commands.js' ;
14
14
import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js' ;
@@ -30,7 +30,7 @@ import { ITextModel } from '../../../../../common/model.js';
30
30
import { StickyScrollController } from '../../../../stickyScroll/browser/stickyScrollController.js' ;
31
31
import { InlineCompletionContextKeys } from '../../controller/inlineCompletionContextKeys.js' ;
32
32
import { CustomizedMenuWorkbenchToolBar } from '../../hintsWidget/inlineCompletionsHintsWidget.js' ;
33
- import { PathBuilder , StatusBarViewItem , getOffsetForPos , mapOutFalsy , maxContentWidthInRange , n } from './utils.js' ;
33
+ import { PathBuilder , StatusBarViewItem , createRectangle , getOffsetForPos , mapOutFalsy , maxContentWidthInRange , n } from './utils.js' ;
34
34
import { InlineEditWithChanges } from './viewAndDiffProducer.js' ;
35
35
import { localize } from '../../../../../../nls.js' ;
36
36
@@ -159,13 +159,13 @@ export class InlineEditsSideBySideDiff extends Disposable {
159
159
return ;
160
160
}
161
161
162
- const topEdit = layoutInfo . edit1 ;
163
- const bottomEdit = layoutInfo . edit2 ;
162
+ const editorTopLeft = layoutInfo . editStart1 . deltaY ( layoutInfo . padding ) ;
163
+ const editorBottomLeft = layoutInfo . editStart2 . deltaY ( - layoutInfo . padding ) ;
164
164
165
- this . previewEditor . layout ( { height : bottomEdit . y - topEdit . y , width : layoutInfo . previewEditorWidth } ) ;
166
- this . previewEditor . updateOptions ( { padding : { top : layoutInfo . padding , bottom : layoutInfo . padding } } ) ;
167
- this . _editorContainer . element . style . top = `${ topEdit . y } px` ;
168
- this . _editorContainer . element . style . left = `${ topEdit . x } px` ;
165
+ this . previewEditor . layout ( { height : editorBottomLeft . y - editorTopLeft . y , width : layoutInfo . previewEditorWidth + 15 /* Make sure editor does not scroll horizontally */ } ) ;
166
+ this . _editorContainer . element . style . top = ` ${ editorTopLeft . y } px` ;
167
+ this . _editorContainer . element . style . left = `${ editorTopLeft . x } px` ;
168
+ this . _editorContainer . element . style . width = `${ layoutInfo . previewEditorWidth } px` ; // Set width to clip view zone
169
169
} ) ) ;
170
170
171
171
/*const toolbarDropdownVisible = observableFromEvent(this, this._toolbar.onDidChangeDropdownVisibility, (e) => e ?? false);
@@ -182,20 +182,16 @@ export class InlineEditsSideBySideDiff extends Disposable {
182
182
183
183
this . _previewEditorObs . editor . setScrollLeft ( layoutInfo . desiredPreviewEditorScrollLeft ) ;
184
184
} ) ) ;
185
-
186
- this . _editorContainerTopLeft . set ( this . _previewEditorLayoutInfo . map ( i => i ?. edit1 ) , undefined ) ;
187
185
}
188
186
189
187
private readonly _display = derived ( this , reader => ! ! this . _uiState . read ( reader ) ? 'block' : 'none' ) ;
190
188
191
189
private readonly previewRef = n . ref < HTMLDivElement > ( ) ;
192
190
private readonly toolbarRef = n . ref < HTMLDivElement > ( ) ;
193
191
194
- private readonly _editorContainerTopLeft = observableValue < IObservable < Point | undefined > | undefined > ( this , undefined ) ;
195
-
196
192
private readonly _editorContainer = n . div ( {
197
193
class : [ 'editorContainer' , this . _editorObs . getOption ( EditorOption . inlineSuggest ) . map ( v => ! v . edits . experimental . useGutterIndicator && 'showHover' ) ] ,
198
- style : { position : 'absolute' } ,
194
+ style : { position : 'absolute' , overflow : 'hidden' } ,
199
195
} , [
200
196
n . div ( { class : 'preview' , style : { } , ref : this . previewRef } ) ,
201
197
n . div ( { class : 'toolbar' , style : { } , ref : this . toolbarRef } ) ,
@@ -299,6 +295,7 @@ export class InlineEditsSideBySideDiff extends Disposable {
299
295
300
296
private readonly _previewEditorObs = observableCodeEditor ( this . previewEditor ) ;
301
297
298
+ private _activeViewZones : string [ ] = [ ] ;
302
299
private readonly _updatePreviewEditor = derived ( reader => {
303
300
this . _editorContainer . readEffect ( reader ) ;
304
301
@@ -331,14 +328,32 @@ export class InlineEditsSideBySideDiff extends Disposable {
331
328
332
329
this . previewEditor . setHiddenAreas ( hiddenAreas , undefined , true ) ;
333
330
331
+ // TODO: is this the proper way to handle viewzones?
332
+ const previousViewZones = [ ...this . _activeViewZones ] ;
333
+ this . _activeViewZones = [ ] ;
334
+
335
+ const reducedLinesCount = ( range . endLineNumberExclusive - range . startLineNumber ) - uiState . newTextLineCount ;
336
+ this . previewEditor . changeViewZones ( ( changeAccessor ) => {
337
+ previousViewZones . forEach ( id => changeAccessor . removeZone ( id ) ) ;
338
+
339
+ if ( reducedLinesCount > 0 ) {
340
+ this . _activeViewZones . push ( changeAccessor . addZone ( {
341
+ afterLineNumber : range . startLineNumber + uiState . newTextLineCount - 1 ,
342
+ heightInLines : reducedLinesCount ,
343
+ showInHiddenAreas : true ,
344
+ domNode : $ ( 'div.diagonal-fill.inline-edits-view-zone' ) ,
345
+ } ) ) ;
346
+ }
347
+ } ) ;
348
+
334
349
} ) . recomputeInitiallyAndOnChange ( this . _store ) ;
335
350
336
351
private readonly _previewEditorWidth = derived ( this , reader => {
337
352
const edit = this . _edit . read ( reader ) ;
338
353
if ( ! edit ) { return 0 ; }
339
354
this . _updatePreviewEditor . read ( reader ) ;
340
355
341
- return maxContentWidthInRange ( this . _previewEditorObs , edit . modifiedLineRange , reader ) + 10 ;
356
+ return maxContentWidthInRange ( this . _previewEditorObs , edit . modifiedLineRange , reader ) ;
342
357
} ) ;
343
358
344
359
private readonly _cursorPosIfTouchesEdit = derived ( this , reader => {
@@ -409,7 +424,7 @@ export class InlineEditsSideBySideDiff extends Disposable {
409
424
const cursorPos = this . _cursorPosIfTouchesEdit . read ( reader ) ;
410
425
411
426
const maxPreviewEditorLeft = Math . max (
412
- // We're starting from the content area right and moving it left by IN_EDITOR_DISPLACEMENT and also by an ammount to ensure some mimum desired width
427
+ // We're starting from the content area right and moving it left by IN_EDITOR_DISPLACEMENT and also by an amount to ensure some minimum desired width
413
428
editorContentAreaWidth + horizontalScrollOffset - IN_EDITOR_DISPLACEMENT - Math . max ( 0 , desiredMinimumWidth - maximumAvailableWidth ) ,
414
429
// But we don't want that the moving left ends up covering the cursor, so this will push it to the right again
415
430
Math . min (
@@ -438,36 +453,62 @@ export class InlineEditsSideBySideDiff extends Disposable {
438
453
439
454
const codeLeft = editorLayout . contentLeft ;
440
455
441
- const code1 = new Point ( left , selectionTop ) ;
442
- const codeStart1 = new Point ( codeLeft , selectionTop ) ;
443
- const code2 = new Point ( left , selectionBottom ) ;
444
- const codeStart2 = new Point ( codeLeft , selectionBottom ) ;
456
+ let code1 = new Point ( left , selectionTop ) ;
457
+ let codeStart1 = new Point ( codeLeft , selectionTop ) ;
458
+ let code2 = new Point ( left , selectionBottom ) ;
459
+ let codeStart2 = new Point ( codeLeft , selectionBottom ) ;
460
+
461
+ const editHeight = this . _editor . getOption ( EditorOption . lineHeight ) * inlineEdit . modifiedLineRange . length ;
445
462
const codeHeight = selectionBottom - selectionTop ;
463
+ const previewEditorHeight = Math . max ( codeHeight , editHeight ) ;
446
464
447
- const codeEditDistRange = inlineEdit . modifiedLineRange . length === inlineEdit . originalLineRange . length
465
+ const editIsSameHeight = codeHeight === previewEditorHeight ;
466
+ const codeEditDistRange = editIsSameHeight
448
467
? new OffsetRange ( 4 , 61 )
449
468
: new OffsetRange ( 60 , 61 ) ;
450
469
451
470
const clipped = dist === 0 ;
471
+ const PADDING = 4 ;
452
472
453
- const codeEditDist = codeEditDistRange . clip ( dist ) ;
454
- const editHeight = this . _editor . getOption ( EditorOption . lineHeight ) * inlineEdit . modifiedLineRange . length ;
473
+ const codeEditDist = editIsSameHeight ? PADDING : codeEditDistRange . clip ( dist ) ; // TODO: Is there a better way to specify the distance?
455
474
456
475
const previewEditorWidth = Math . min ( previewContentWidth , remainingWidthRightOfEditor + editorLayout . width - editorLayout . contentLeft - codeEditDist ) ;
457
476
458
- const PADDING = 4 ;
459
-
460
- const edit1 = new Point ( left + codeEditDist , selectionTop ) ;
461
- const edit2 = new Point ( left + codeEditDist , selectionTop + editHeight + PADDING * 2 ) ;
477
+ let editStart1 = new Point ( left + codeEditDist , selectionTop ) ;
478
+ let edit1 = editStart1 . deltaX ( previewEditorWidth ) ;
479
+ let editStart2 = new Point ( left + codeEditDist , selectionTop + previewEditorHeight ) ;
480
+ let edit2 = editStart2 . deltaX ( previewEditorWidth ) ;
481
+
482
+ // padding
483
+ const isInsertion = codeHeight === 0 ;
484
+ if ( ! isInsertion ) {
485
+ codeStart1 = codeStart1 . deltaY ( - PADDING ) . deltaX ( - PADDING ) ;
486
+ code1 = code1 . deltaY ( - PADDING ) ;
487
+ codeStart2 = codeStart2 . deltaY ( PADDING ) . deltaX ( - PADDING ) ;
488
+ code2 = code2 . deltaY ( PADDING ) ;
489
+
490
+ editStart1 = editStart1 . deltaY ( - PADDING ) ;
491
+ edit1 = edit1 . deltaY ( - PADDING ) . deltaX ( PADDING ) ;
492
+ editStart2 = editStart2 . deltaY ( PADDING ) ;
493
+ edit2 = edit2 . deltaY ( PADDING ) . deltaX ( PADDING ) ;
494
+ } else {
495
+ // Align top of edit with insertion line
496
+ edit1 = edit1 . deltaX ( PADDING ) ;
497
+ editStart2 = editStart2 . deltaY ( 2 * PADDING ) ;
498
+ edit2 = edit2 . deltaY ( 2 * PADDING ) . deltaX ( PADDING ) ;
499
+ }
462
500
463
501
return {
464
502
code1,
465
503
codeStart1,
466
504
code2,
467
505
codeStart2,
468
506
codeHeight,
507
+ codeScrollLeft : horizontalScrollOffset ,
469
508
509
+ editStart1,
470
510
edit1,
511
+ editStart2,
471
512
edit2,
472
513
editHeight,
473
514
maxContentWidth,
@@ -503,31 +544,19 @@ export class InlineEditsSideBySideDiff extends Disposable {
503
544
private readonly _extendedModifiedPath = derived ( reader => {
504
545
const layoutInfo = this . _previewEditorLayoutInfo . read ( reader ) ;
505
546
if ( ! layoutInfo ) { return undefined ; }
506
- const width = layoutInfo . previewEditorWidth + layoutInfo . padding ;
507
-
508
- const topLeft = layoutInfo . edit1 ;
509
- const topRight = layoutInfo . edit1 . deltaX ( width ) ;
510
- const topRightBefore = topRight . deltaX ( - layoutInfo . borderRadius ) ;
511
- const topRightAfter = topRight . deltaY ( layoutInfo . borderRadius ) ;
512
-
513
- const bottomLeft = layoutInfo . edit2 ;
514
- const bottomRight = bottomLeft . deltaX ( width ) ;
515
- const bottomRightBefore = bottomRight . deltaY ( - layoutInfo . borderRadius ) ;
516
- const bottomRightAfter = bottomRight . deltaX ( - layoutInfo . borderRadius ) ;
517
-
518
- const extendedModifiedPathBuilder = new PathBuilder ( )
519
- . moveTo ( layoutInfo . code1 )
520
- . lineTo ( topLeft )
521
- . lineTo ( topRightBefore )
522
- . curveTo ( topRight , topRightAfter )
523
- . lineTo ( bottomRightBefore )
524
- . curveTo ( bottomRight , bottomRightAfter )
525
- . lineTo ( bottomLeft ) ;
526
-
527
- if ( layoutInfo . edit2 . y !== layoutInfo . code2 . y ) {
528
- extendedModifiedPathBuilder . curveTo2 ( layoutInfo . edit2 . deltaX ( - 20 ) , layoutInfo . code2 . deltaX ( 20 ) , layoutInfo . code2 . deltaX ( 0 ) ) ;
547
+
548
+ const extendedModifiedPathBuilder = createRectangle (
549
+ { topLeft : layoutInfo . editStart1 , width : layoutInfo . edit1 . x - layoutInfo . editStart1 . x , height : layoutInfo . editStart2 . y - layoutInfo . editStart1 . y } ,
550
+ 0 ,
551
+ { topLeft : 0 , bottomLeft : 0 , topRight : layoutInfo . borderRadius , bottomRight : layoutInfo . borderRadius } ,
552
+ { hideLeft : true }
553
+ ) ;
554
+
555
+ if ( layoutInfo . editStart2 . y !== layoutInfo . code2 . y ) {
556
+ extendedModifiedPathBuilder . moveTo ( layoutInfo . editStart2 ) ;
557
+ extendedModifiedPathBuilder . curveTo2 ( layoutInfo . editStart2 . deltaX ( - 20 ) , layoutInfo . code2 . deltaX ( 20 ) , layoutInfo . code2 . deltaX ( 0 ) ) ;
529
558
}
530
- extendedModifiedPathBuilder . lineTo ( layoutInfo . code2 ) ;
559
+ extendedModifiedPathBuilder . lineTo ( layoutInfo . code2 ) . moveTo ( layoutInfo . code1 ) . lineTo ( layoutInfo . editStart1 ) ;
531
560
return extendedModifiedPathBuilder . build ( ) ;
532
561
} ) ;
533
562
@@ -601,13 +630,12 @@ export class InlineEditsSideBySideDiff extends Disposable {
601
630
return [
602
631
n . svgElem ( 'path' , {
603
632
class : 'originalOverlay' ,
604
- d : layoutInfoObs . map ( layoutInfo => new PathBuilder ( )
605
- . moveTo ( layoutInfo . code2 )
606
- . lineTo ( layoutInfo . codeStart2 )
607
- . lineTo ( layoutInfo . codeStart1 )
608
- . lineTo ( layoutInfo . code1 )
609
- . build ( )
610
- ) ,
633
+ d : layoutInfoObs . map ( layoutInfo => createRectangle (
634
+ { topLeft : layoutInfo . codeStart1 , width : layoutInfo . code1 . x - layoutInfo . codeStart1 . x , height : layoutInfo . code2 . y - layoutInfo . code1 . y } ,
635
+ 0 ,
636
+ { topLeft : layoutInfo . borderRadius , bottomLeft : layoutInfo . borderRadius , topRight : 0 , bottomRight : 0 } ,
637
+ { hideRight : true , hideLeft : layoutInfo . codeScrollLeft !== 0 }
638
+ ) . build ( ) ) ,
611
639
style : {
612
640
fill : 'var(--vscode-inlineEdit-originalBackground, transparent)' ,
613
641
stroke : 'var(--vscode-inlineEdit-originalBorder)' ,
0 commit comments