From dbcb321f4cc80e9694c26b3d078751e27abd670d Mon Sep 17 00:00:00 2001 From: BeniBenj Date: Thu, 9 Jan 2025 23:44:07 +0100 Subject: [PATCH] inline edits UI changes --- .../view/inlineEdits/sideBySideDiff.ts | 111 ++++++++++-------- .../browser/view/inlineEdits/utils.ts | 2 + .../view/inlineEdits/wordReplacementView.ts | 2 +- 3 files changed, 62 insertions(+), 53 deletions(-) diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/sideBySideDiff.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/sideBySideDiff.ts index e1feaa2eb8b78..38bf37a2698f8 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/sideBySideDiff.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/sideBySideDiff.ts @@ -147,9 +147,11 @@ export class InlineEditsSideBySideDiff extends Disposable { return; } - this.previewEditor.layout({ height: layoutInfo.editHeight, width: layoutInfo.previewEditorWidth }); - const topEdit = layoutInfo.edit1; + const bottomEdit = layoutInfo.edit2; + + this.previewEditor.layout({ height: bottomEdit.y - topEdit.y, width: layoutInfo.previewEditorWidth }); + this.previewEditor.updateOptions({ padding: { top: layoutInfo.padding, bottom: layoutInfo.padding } }); this._editorContainer.element.style.top = `${topEdit.y}px`; this._editorContainer.element.style.left = `${topEdit.x}px`; })); @@ -261,6 +263,7 @@ export class InlineEditsSideBySideDiff extends Disposable { overviewRulerLanes: 0, lineDecorationsWidth: 0, lineNumbersMinChars: 0, + revealHorizontalRightPadding: 0, bracketPairColorization: { enabled: true, independentColorPoolPerBracketType: false }, scrollBeyondLastLine: false, scrollbar: { @@ -440,8 +443,10 @@ export class InlineEditsSideBySideDiff extends Disposable { const previewEditorWidth = Math.min(previewContentWidth, remainingWidthRightOfEditor + editorLayout.width - editorLayout.contentLeft - codeEditDist); + const PADDING = 4; + const edit1 = new Point(left + codeEditDist, selectionTop); - const edit2 = new Point(left + codeEditDist, selectionTop + editHeight); + const edit2 = new Point(left + codeEditDist, selectionTop + editHeight + PADDING * 2); return { code1, @@ -456,7 +461,9 @@ export class InlineEditsSideBySideDiff extends Disposable { maxContentWidth, shouldShowShadow: clipped, desiredPreviewEditorScrollLeft, - previewEditorWidth + previewEditorWidth, + padding: PADDING, + borderRadius: PADDING }; }); @@ -484,13 +491,28 @@ export class InlineEditsSideBySideDiff extends Disposable { private readonly _extendedModifiedPath = derived(reader => { const layoutInfo = this._previewEditorLayoutInfo.read(reader); if (!layoutInfo) { return undefined; } - const width = layoutInfo.previewEditorWidth; + const width = layoutInfo.previewEditorWidth + layoutInfo.padding; + + + const topLeft = layoutInfo.edit1; + const topRight = layoutInfo.edit1.deltaX(width); + const topRightBefore = topRight.deltaX(-layoutInfo.borderRadius); + const topRightAfter = topRight.deltaY(layoutInfo.borderRadius); + + const bottomLeft = layoutInfo.edit2; + const bottomRight = bottomLeft.deltaX(width); + const bottomRightBefore = bottomRight.deltaY(-layoutInfo.borderRadius); + const bottomRightAfter = bottomRight.deltaX(-layoutInfo.borderRadius); + const extendedModifiedPathBuilder = new PathBuilder() .moveTo(layoutInfo.code1) - .lineTo(layoutInfo.edit1) - .lineTo(layoutInfo.edit1.deltaX(width)) - .lineTo(layoutInfo.edit2.deltaX(width)) - .lineTo(layoutInfo.edit2); + .lineTo(topLeft) + .lineTo(topRightBefore) + .curveTo(topRight, topRightAfter) + .lineTo(bottomRightBefore) + .curveTo(bottomRight, bottomRightAfter) + .lineTo(bottomLeft); + if (layoutInfo.edit2.y !== layoutInfo.code2.y) { extendedModifiedPathBuilder.curveTo2(layoutInfo.edit2.deltaX(-20), layoutInfo.code2.deltaX(20), layoutInfo.code2.deltaX(0)); } @@ -545,6 +567,19 @@ export class InlineEditsSideBySideDiff extends Disposable { }), ]).keepUpdated(this._store); + private readonly _middleBorderWithShadow = n.div({ + class: ['middleBorderWithShadow'], + style: { + position: 'absolute', + display: this._previewEditorLayoutInfo.map(i => i?.shouldShowShadow ? 'block' : 'none'), + width: '6px', + boxShadow: 'var(--vscode-scrollbar-shadow) -6px 0 6px -6px inset', + left: this._previewEditorLayoutInfo.map(i => i ? i.code1.x - 6 : 0), + top: this._previewEditorLayoutInfo.map(i => i ? i.code1.y : 0), + height: this._previewEditorLayoutInfo.map(i => i ? i.code2.y - i.code1.y : 0), + }, + }, []).keepUpdated(this._store); + private readonly _foregroundSvg = n.svg({ transform: 'translate(-0.5 -0.5)', style: { overflow: 'visible', pointerEvents: 'none', position: 'absolute' }, @@ -552,7 +587,6 @@ export class InlineEditsSideBySideDiff extends Disposable { const layoutInfoObs = mapOutFalsy(this._previewEditorLayoutInfo).read(reader); if (!layoutInfoObs) { return undefined; } - const shadowWidth = 6; return [ n.svgElem('path', { class: 'originalOverlay', @@ -579,46 +613,19 @@ export class InlineEditsSideBySideDiff extends Disposable { strokeWidth: '1px', } }), - - ...(!layoutInfoObs.map(i => i.shouldShowShadow).read(reader) - ? [ - n.svgElem('path', { - class: 'middleBorder', - d: layoutInfoObs.map(layoutInfo => new PathBuilder() - .moveTo(layoutInfo.code1) - .lineTo(layoutInfo.code2) - .build() - ), - style: { - stroke: 'var(--vscode-inlineEdit-modifiedBorder)', - strokeWidth: '1px' - } - }) - ] - : [ - n.svgElem('defs', {}, [ - n.svgElem('linearGradient', { id: 'gradient', x1: '0%', x2: '100%', }, [ - n.svgElem('stop', { - offset: '0%', - style: { stopColor: 'var(--vscode-inlineEdit-modifiedBorder)', stopOpacity: '0', } - }), - n.svgElem('stop', { - offset: '100%', - style: { stopColor: 'var(--vscode-inlineEdit-modifiedBorder)', stopOpacity: '1', } - }) - ]) - ]), - n.svgElem('rect', { - class: 'middleBorderWithShadow', - x: layoutInfoObs.map(layoutInfo => layoutInfo.code1.x - shadowWidth), - y: layoutInfoObs.map(layoutInfo => layoutInfo.code1.y), - width: shadowWidth, - height: layoutInfoObs.map(layoutInfo => layoutInfo.code2.y - layoutInfo.code1.y), - fill: 'url(#gradient)', - style: { strokeWidth: '0', stroke: 'transparent', } - }) - ] - ) + n.svgElem('path', { + class: 'middleBorder', + d: layoutInfoObs.map(layoutInfo => new PathBuilder() + .moveTo(layoutInfo.code1) + .lineTo(layoutInfo.code2) + .build() + ), + style: { + display: layoutInfoObs.map(i => i.shouldShowShadow ? 'none' : 'block'), + stroke: 'var(--vscode-inlineEdit-modifiedBorder)', + strokeWidth: '1px' + } + }) ]; })).keepUpdated(this._store); @@ -634,7 +641,7 @@ export class InlineEditsSideBySideDiff extends Disposable { }, }, [ this._backgroundSvg, - derived(this, reader => this._shouldOverflow.read(reader) ? [] : [this._foregroundBackgroundSvg, this._editorContainer, this._foregroundSvg]), + derived(this, reader => this._shouldOverflow.read(reader) ? [] : [this._foregroundBackgroundSvg, this._editorContainer, this._foregroundSvg, this._middleBorderWithShadow]), ]).keepUpdated(this._store); private readonly _overflowView = n.div({ @@ -645,6 +652,6 @@ export class InlineEditsSideBySideDiff extends Disposable { display: this._display, }, }, [ - derived(this, reader => this._shouldOverflow.read(reader) ? [this._foregroundBackgroundSvg, this._editorContainer, this._foregroundSvg] : []), + derived(this, reader => this._shouldOverflow.read(reader) ? [this._foregroundBackgroundSvg, this._editorContainer, this._foregroundSvg, this._middleBorderWithShadow] : []), ]).keepUpdated(this._store); } diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/utils.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/utils.ts index 57e0eb3393e01..a3b822d875d85 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/utils.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/utils.ts @@ -392,11 +392,13 @@ function setClassName(domNode: Element, className: string) { function resolve(value: ValueOrList, reader: IReader | undefined, cb: (val: T) => void): void { if (isObservable(value)) { cb(value.read(reader)); + return; } if (Array.isArray(value)) { for (const v of value) { resolve(v, reader, cb); } + return; } cb(value as any); } diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/wordReplacementView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/wordReplacementView.ts index 19f28075c3365..9797502d7b031 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/wordReplacementView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/wordReplacementView.ts @@ -24,7 +24,7 @@ export const transparentHoverBackground = registerColor( 'inlineEdit.wordReplacementView.background', { light: transparent(editorHoverStatusBarBackground, 0.1), - dark: transparent(editorHoverStatusBarBackground, 0.5), + dark: transparent(editorHoverStatusBarBackground, 0.1), hcLight: transparent(editorHoverStatusBarBackground, 0.1), hcDark: transparent(editorHoverStatusBarBackground, 0.1), },