Skip to content

Commit

Permalink
* show a diff zone per "change region"
Browse files Browse the repository at this point in the history
* don't show whole range highlights anymore
  • Loading branch information
jrieken committed Oct 18, 2023
1 parent 712a1b5 commit 6db4184
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 103 deletions.
49 changes: 24 additions & 25 deletions src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import { Barrier, raceCancellationError } from 'vs/base/common/async';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { Emitter, Event } from 'vs/base/common/event';
import { DisposableStore, IDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { StopWatch } from 'vs/base/common/stopwatch';
import { assertType } from 'vs/base/common/types';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IPosition, Position } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon';
import { ModelDecorationOptions, createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
import { IModelService } from 'vs/editor/common/services/model';
import { InlineCompletionsController } from 'vs/editor/contrib/inlineCompletions/browser/inlineCompletionsController';
Expand All @@ -39,7 +39,6 @@ import { generateUuid } from 'vs/base/common/uuid';
import { TextEdit } from 'vs/editor/common/languages';
import { ISelection, Selection } from 'vs/editor/common/core/selection';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IModelDeltaDecoration } from 'vs/editor/common/model';

export const enum State {
CREATE_SESSION = 'CREATE_SESSION',
Expand Down Expand Up @@ -93,12 +92,12 @@ export class InlineChatController implements IEditorContribution {
return editor.getContribution<InlineChatController>(INLINE_CHAT_ID);
}

private static _decoBlock = ModelDecorationOptions.register({
description: 'inline-chat',
showIfCollapsed: false,
isWholeLine: true,
className: 'inline-chat-block-selection',
});
// private static _decoBlock = ModelDecorationOptions.register({
// description: 'inline-chat',
// showIfCollapsed: false,
// isWholeLine: true,
// className: 'inline-chat-block-selection',
// });

private static _promptHistory: string[] = [];
private _historyOffset: number = -1;
Expand Down Expand Up @@ -335,22 +334,22 @@ export class InlineChatController implements IEditorContribution {

this._sessionStore.clear();

const wholeRangeDecoration = this._editor.createDecorationsCollection();
const updateWholeRangeDecoration = () => {

const range = this._activeSession!.wholeRange.value;
const decorations: IModelDeltaDecoration[] = [];
if (!range.isEmpty()) {
decorations.push({
range,
options: InlineChatController._decoBlock
});
}
wholeRangeDecoration.set(decorations);
};
this._sessionStore.add(toDisposable(() => wholeRangeDecoration.clear()));
this._sessionStore.add(this._activeSession.wholeRange.onDidChange(updateWholeRangeDecoration));
updateWholeRangeDecoration();
// const wholeRangeDecoration = this._editor.createDecorationsCollection();
// const updateWholeRangeDecoration = () => {

// const range = this._activeSession!.wholeRange.value;
// const decorations: IModelDeltaDecoration[] = [];
// if (!range.isEmpty()) {
// decorations.push({
// range,
// options: InlineChatController._decoBlock
// });
// }
// wholeRangeDecoration.set(decorations);
// };
// this._sessionStore.add(toDisposable(() => wholeRangeDecoration.clear()));
// this._sessionStore.add(this._activeSession.wholeRange.onDidChange(updateWholeRangeDecoration));
// updateWholeRangeDecoration();

this._zone.value.widget.updateSlashCommands(this._activeSession.session.slashCommands ?? []);
this._updatePlaceholder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { Dimension, h } from 'vs/base/browser/dom';
import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
import { MutableDisposable } from 'vs/base/common/lifecycle';
import { assertType } from 'vs/base/common/types';
import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
Expand Down Expand Up @@ -35,21 +35,22 @@ import { ILanguageService } from 'vs/editor/common/languages/language';
import { FoldingController } from 'vs/editor/contrib/folding/browser/folding';
import { WordHighlighterContribution } from 'vs/editor/contrib/wordHighlighter/browser/wordHighlighter';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { generateUuid } from 'vs/base/common/uuid';

export class InlineChatLivePreviewWidget extends ZoneWidget {

private static readonly _hideId = 'overlayDiff';
private readonly _hideId = `overlayDiff:${generateUuid()}`;

private readonly _elements = h('div.inline-chat-diff-widget@domNode');

private readonly _sessionStore = this._disposables.add(new DisposableStore());
private readonly _diffEditor: IDiffEditor;
private _dim: Dimension | undefined;
private _isVisible: boolean = false;

constructor(
editor: ICodeEditor,
private readonly _session: Session,
onDidChangeDiff: (() => void) | undefined,
@IInstantiationService instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@ILogService private readonly _logService: ILogService,
Expand Down Expand Up @@ -92,6 +93,10 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
lineDecorationsWidth: editor.getLayoutInfo().decorationsWidth
});

if (onDidChangeDiff) {
this._disposables.add(this._diffEditor.onDidUpdateDiff(() => { onDidChangeDiff(); }));
}

const highlighter = WordHighlighterContribution.get(editor);
if (highlighter) {
this._disposables.add(highlighter.linkWordHighlighters(this._diffEditor.getModifiedEditor()));
Expand Down Expand Up @@ -132,33 +137,17 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {

override hide(): void {
this._cleanupFullDiff();
this._sessionStore.clear();
super.hide();
this._isVisible = false;
}

override show(): void {
assertType(this.editor.hasModel());
this._sessionStore.clear();
this._isVisible = true;

this._sessionStore.add(this._diffEditor.onDidUpdateDiff(() => {
const result = this._diffEditor.getDiffComputationResult();
const hasFocus = this._diffEditor.hasTextFocus();
this._updateFromChanges(this._session.wholeRange.value, result?.changes2 ?? []);
// TODO@jrieken find a better fix for this. this is the challenge:
// the _doShowForChanges method invokes show of the zone widget which removes and adds the
// zone and overlay parts. this dettaches and reattaches the dom nodes which means they lose
// focus
if (hasFocus) {
this._diffEditor.focus();
}
}));
this._updateFromChanges(this._session.wholeRange.value, this._session.lastTextModelChanges);
throw new Error('use showForChanges');
}

private _updateFromChanges(range: Range, changes: readonly DetailedLineRangeMapping[]): void {
assertType(this.editor.hasModel());
showForChanges(changes: readonly DetailedLineRangeMapping[]): void {
const hasFocus = this._diffEditor.hasTextFocus();
this._isVisible = true;

if (changes.length === 0 || this._session.textModel0.getValueLength() === 0) {
// no change or changes to an empty file
Expand All @@ -167,16 +156,26 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
} else {
// complex changes
this._logService.debug('[IE] livePreview-mode: full diff');
this._renderChangesWithFullDiff(changes, range);
this._renderChangesWithFullDiff(changes);
}

// TODO@jrieken find a better fix for this. this is the challenge:
// the `_updateFromChanges` method invokes show of the zone widget which removes and adds the
// zone and overlay parts. this dettaches and reattaches the dom nodes which means they lose
// focus
if (hasFocus) {
this._diffEditor.focus();
}
}


// --- full diff

private _renderChangesWithFullDiff(changes: readonly DetailedLineRangeMapping[], range: Range) {
private _renderChangesWithFullDiff(changes: readonly DetailedLineRangeMapping[]) {
assertType(this.editor.hasModel());

const modified = this.editor.getModel()!;
const ranges = this._computeHiddenRanges(modified, range, changes);
const modified = this.editor.getModel();
const ranges = this._computeHiddenRanges(modified, changes);

this._hideEditorRanges(this.editor, [ranges.modifiedHidden]);
this._hideEditorRanges(this._diffEditor.getOriginalEditor(), ranges.originalDiffHidden);
Expand All @@ -187,25 +186,20 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
const lineCountModified = ranges.modifiedHidden.length;
const lineCountOriginal = ranges.originalHidden.length;

const lineHeightDiff = Math.max(lineCountModified, lineCountOriginal);
const lineHeightPadding = (this.editor.getOption(EditorOption.lineHeight) / 12) /* padding-top/bottom*/;
const heightInLines = lineHeightDiff + lineHeightPadding;
const heightInLines = Math.max(lineCountModified, lineCountOriginal);

super.show(ranges.anchor, heightInLines);
this._logService.debug(`[IE] diff SHOWING at ${ranges.anchor} with ${heightInLines} lines height`);
}

private _cleanupFullDiff() {
this.editor.setHiddenAreas([], InlineChatLivePreviewWidget._hideId);
this._diffEditor.getOriginalEditor().setHiddenAreas([], InlineChatLivePreviewWidget._hideId);
this._diffEditor.getModifiedEditor().setHiddenAreas([], InlineChatLivePreviewWidget._hideId);
this.editor.setHiddenAreas([], this._hideId);
this._diffEditor.getOriginalEditor().setHiddenAreas([], this._hideId);
this._diffEditor.getModifiedEditor().setHiddenAreas([], this._hideId);
super.hide();
}

private _computeHiddenRanges(model: ITextModel, range: Range, changes: readonly DetailedLineRangeMapping[]) {
if (changes.length === 0) {
changes = [new DetailedLineRangeMapping(LineRange.fromRange(range), LineRange.fromRange(range), undefined)];
}
private _computeHiddenRanges(model: ITextModel, changes: readonly DetailedLineRangeMapping[]) {

let originalLineRange = changes[0].original;
let modifiedLineRange = changes[0].modified;
Expand All @@ -214,16 +208,8 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
modifiedLineRange = modifiedLineRange.join(changes[i].modified);
}

const startDelta = modifiedLineRange.startLineNumber - range.startLineNumber;
if (startDelta > 0) {
modifiedLineRange = new LineRange(modifiedLineRange.startLineNumber - startDelta, modifiedLineRange.endLineNumberExclusive);
originalLineRange = new LineRange(originalLineRange.startLineNumber - startDelta, originalLineRange.endLineNumberExclusive);
}

const endDelta = range.endLineNumber - (modifiedLineRange.endLineNumberExclusive - 1);
if (endDelta > 0) {
modifiedLineRange = new LineRange(modifiedLineRange.startLineNumber, modifiedLineRange.endLineNumberExclusive + endDelta);
originalLineRange = new LineRange(originalLineRange.startLineNumber, originalLineRange.endLineNumberExclusive + endDelta);
if (originalLineRange.isEmpty) {
originalLineRange = new LineRange(originalLineRange.startLineNumber, originalLineRange.endLineNumberExclusive + 1);
}

const originalDiffHidden = invertLineRange(originalLineRange, this._session.textModel0);
Expand Down Expand Up @@ -256,7 +242,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
} else {
hiddenRanges = lineRanges.map(lineRangeAsRange);
}
editor.setHiddenAreas(hiddenRanges, InlineChatLivePreviewWidget._hideId);
editor.setHiddenAreas(hiddenRanges, this._hideId);
this._logService.debug(`[IE] diff HIDING ${hiddenRanges} for ${editor.getId()} with ${String(editor.getModel()?.uri)}`);
}

Expand All @@ -276,7 +262,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
const newDim = new Dimension(widthInPixel, heightInPixel);
if (!Dimension.equals(this._dim, newDim)) {
this._dim = newDim;
this._diffEditor.layout(this._dim.with(undefined, this._dim.height - 12 /* padding */));
this._diffEditor.layout(this._dim.with(undefined, this._dim.height));
this._logService.debug('[IE] diff LAYOUT', this._dim);
}
}
Expand Down
Loading

0 comments on commit 6db4184

Please sign in to comment.