mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 09:08:48 +01:00
Fix misalignment of arrow and suggestion box in NES Insertion View (#239104)
fix https://github.com/microsoft/vscode-copilot/issues/12461
This commit is contained in:
committed by
GitHub
parent
fa2f90b630
commit
243da33637
@@ -138,7 +138,15 @@ export class Rect {
|
||||
return new Rect(this.left - delta, this.top, this.right - delta, this.bottom);
|
||||
}
|
||||
|
||||
moveRight(delta: number): Rect {
|
||||
return new Rect(this.left + delta, this.top, this.right + delta, this.bottom);
|
||||
}
|
||||
|
||||
moveUp(delta: number): Rect {
|
||||
return new Rect(this.left, this.top - delta, this.right, this.bottom - delta);
|
||||
}
|
||||
|
||||
moveDown(delta: number): Rect {
|
||||
return new Rect(this.left, this.top + delta, this.right, this.bottom + delta);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -73,6 +73,7 @@ export class InlineEditsGutterIndicator extends Disposable {
|
||||
constructor(
|
||||
private readonly _editorObs: ObservableCodeEditor,
|
||||
private readonly _originalRange: IObservable<LineRange | undefined>,
|
||||
private readonly _verticalOffset: IObservable<number>,
|
||||
private readonly _model: IObservable<InlineCompletionsModel | undefined>,
|
||||
private readonly _isHoveringOverInlineEdit: IObservable<boolean>,
|
||||
private readonly _focusIsInMenu: ISettableObservable<boolean>,
|
||||
@@ -130,7 +131,8 @@ export class InlineEditsGutterIndicator extends Disposable {
|
||||
|
||||
|
||||
const lineHeight = this._editorObs.getOption(EditorOption.lineHeight).read(reader);
|
||||
const pillRect = targetRect.withHeight(lineHeight).withWidth(22);
|
||||
const pillOffset = this._verticalOffset.read(reader);
|
||||
const pillRect = targetRect.withHeight(lineHeight).withWidth(22).moveDown(pillOffset);
|
||||
const pillRectMoved = pillRect.moveToBeContainedIn(viewPortWithStickyScroll);
|
||||
|
||||
const rect = targetRect;
|
||||
@@ -142,7 +144,7 @@ export class InlineEditsGutterIndicator extends Disposable {
|
||||
return {
|
||||
rect,
|
||||
iconRect,
|
||||
arrowDirection: (iconRect.top === targetRect.top ? 'right' as const
|
||||
arrowDirection: (targetRect.containsRect(iconRect) ? 'right' as const
|
||||
: iconRect.top > targetRect.top ? 'top' as const : 'bottom' as const),
|
||||
docked: rect.containsRect(iconRect) && viewPortWithStickyScroll.containsRect(iconRect),
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@ import { observableCodeEditor } from '../../../../../browser/observableCodeEdito
|
||||
import { Point } from '../../../../../browser/point.js';
|
||||
import { LineSource, renderLines, RenderOptions } from '../../../../../browser/widget/diffEditor/components/diffEditorViewZones/renderLines.js';
|
||||
import { EditorOption } from '../../../../../common/config/editorOptions.js';
|
||||
import { LineRange } from '../../../../../common/core/lineRange.js';
|
||||
import { Position } from '../../../../../common/core/position.js';
|
||||
import { Range } from '../../../../../common/core/range.js';
|
||||
import { ILanguageService } from '../../../../../common/languages/language.js';
|
||||
@@ -112,6 +113,32 @@ export class InlineEditsInsertionView extends Disposable implements IInlineEdits
|
||||
return Math.max(...lineWidths);
|
||||
});
|
||||
|
||||
private readonly _trimVertically = derived(this, reader => {
|
||||
const text = this._state.read(reader)?.text;
|
||||
if (!text || text.trim() === '') {
|
||||
return { top: 0, bottom: 0 };
|
||||
}
|
||||
|
||||
// Adjust for leading/trailing newlines
|
||||
const lineHeight = this._editor.getOption(EditorOption.lineHeight);
|
||||
let topTrim = 0;
|
||||
let bottomTrim = 0;
|
||||
|
||||
let i = 0;
|
||||
for (; i < text.length && text[i] === '\n'; i++) {
|
||||
topTrim += lineHeight;
|
||||
}
|
||||
|
||||
for (let j = text.length - 1; j > i && text[j] === '\n'; j--) {
|
||||
bottomTrim += lineHeight;
|
||||
}
|
||||
|
||||
return { top: topTrim, bottom: bottomTrim };
|
||||
});
|
||||
|
||||
public readonly startLineOffset = this._trimVertically.map(v => v.top);
|
||||
public readonly originalLines = this._state.map(s => s ? new LineRange(s.lineNumber, s.lineNumber + 2) : undefined);
|
||||
|
||||
private readonly _overlayLayout = derivedWithStore(this, (reader, store) => {
|
||||
this._ghostText.read(reader);
|
||||
const state = this._state.read(reader);
|
||||
@@ -122,35 +149,22 @@ export class InlineEditsInsertionView extends Disposable implements IInlineEdits
|
||||
// Update the overlay when the position changes
|
||||
this._editorObs.observePosition(observableValue(this, new Position(state.lineNumber, state.column)), store).read(reader);
|
||||
|
||||
const lineHeight = this._editor.getOption(EditorOption.lineHeight);
|
||||
const scrollTop = this._editorObs.scrollTop.read(reader);
|
||||
const editorLayout = this._editorObs.layoutInfo.read(reader);
|
||||
const horizontalScrollOffset = this._editorObs.scrollLeft.read(reader);
|
||||
|
||||
const left = editorLayout.contentLeft + this._editorMaxContentWidthInRange.read(reader) - horizontalScrollOffset;
|
||||
|
||||
let height = this._ghostTextView.height.read(reader);
|
||||
let top = this._editor.getTopForLineNumber(state.lineNumber) - scrollTop;
|
||||
|
||||
if (state.text.trim() !== '') {
|
||||
// Adjust for leading/trailing newlines
|
||||
let i = 0;
|
||||
for (; i < state.text.length && state.text[i] === '\n'; i++) {
|
||||
height -= lineHeight;
|
||||
top += lineHeight;
|
||||
}
|
||||
for (let j = state.text.length - 1; j > i && state.text[j] === '\n'; j--) {
|
||||
height -= lineHeight;
|
||||
}
|
||||
}
|
||||
|
||||
const codeLeft = editorLayout.contentLeft;
|
||||
const bottom = top + height;
|
||||
|
||||
if (left <= codeLeft) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { top: topTrim, bottom: bottomTrim } = this._trimVertically.read(reader);
|
||||
|
||||
const scrollTop = this._editorObs.scrollTop.read(reader);
|
||||
const height = this._ghostTextView.height.read(reader) - topTrim - bottomTrim;
|
||||
const top = this._editor.getTopForLineNumber(state.lineNumber) - scrollTop + topTrim;
|
||||
const bottom = top + height;
|
||||
|
||||
const code1 = new Point(left, top);
|
||||
const codeStart1 = new Point(codeLeft, top);
|
||||
const code2 = new Point(left, bottom);
|
||||
|
||||
@@ -185,12 +185,29 @@ export class InlineEditsView extends Disposable {
|
||||
|| this._lineReplacementView.read(reader).some(v => v.isHovered.read(reader));
|
||||
});
|
||||
|
||||
private readonly _gutterIndicatorOffset = derived<number>(this, reader => {
|
||||
// TODO: have a better way to tell the gutter indicator view where the edit is inside a viewzone
|
||||
if (this._uiState.read(reader)?.state?.kind === 'insertionMultiLine') {
|
||||
return this._insertion.startLineOffset.read(reader);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
private readonly _originalDisplayRange = derived(this, reader => {
|
||||
const state = this._uiState.read(reader);
|
||||
if (state?.state?.kind === 'insertionMultiLine') {
|
||||
return this._insertion.originalLines.read(reader);
|
||||
}
|
||||
return state?.originalDisplayRange;
|
||||
});
|
||||
|
||||
protected readonly _indicator = this._register(autorunWithStore((reader, store) => {
|
||||
if (this._useGutterIndicator.read(reader)) {
|
||||
store.add(this._instantiationService.createInstance(
|
||||
InlineEditsGutterIndicator,
|
||||
this._editorObs,
|
||||
this._uiState.map(s => s && s.originalDisplayRange),
|
||||
this._originalDisplayRange,
|
||||
this._gutterIndicatorOffset,
|
||||
this._model,
|
||||
this._inlineEditsIsHovered,
|
||||
this._focusIsInMenu,
|
||||
@@ -200,9 +217,9 @@ export class InlineEditsView extends Disposable {
|
||||
this._editorObs,
|
||||
derived<IInlineEditsIndicatorState | undefined>(reader => {
|
||||
const state = this._uiState.read(reader);
|
||||
if (!state || !state.state) { return undefined; }
|
||||
const range = state.originalDisplayRange;
|
||||
const top = this._editor.getTopForLineNumber(range.startLineNumber) - this._editorObs.scrollTop.read(reader);
|
||||
const range = this._originalDisplayRange.read(reader);
|
||||
if (!state || !state.state || !range) { return undefined; }
|
||||
const top = this._editor.getTopForLineNumber(range.startLineNumber) - this._editorObs.scrollTop.read(reader) + this._gutterIndicatorOffset.read(reader);
|
||||
return { editTop: top, showAlways: state.state.kind !== 'sideBySide' };
|
||||
}),
|
||||
this._model,
|
||||
|
||||
Reference in New Issue
Block a user