Skip to content

Commit

Permalink
Merge pull request #182619 from microsoft/joh/stiff-crane
Browse files Browse the repository at this point in the history
joh/stiff crane
  • Loading branch information
jrieken authored May 16, 2023
2 parents 1236c13 + 4775bd5 commit 3e4ed47
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { EditorAction2 } from 'vs/editor/browser/editorExtensions';
import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { InteractiveEditorController, InteractiveEditorRunOptions } from 'vs/workbench/contrib/interactiveEditor/browser/interactiveEditorController';
import { CTX_INTERACTIVE_EDITOR_FOCUSED, CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST, CTX_INTERACTIVE_EDITOR_HAS_PROVIDER, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_FIRST, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST, CTX_INTERACTIVE_EDITOR_EMPTY, CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION, CTX_INTERACTIVE_EDITOR_VISIBLE, MENU_INTERACTIVE_EDITOR_WIDGET, MENU_INTERACTIVE_EDITOR_WIDGET_DISCARD, MENU_INTERACTIVE_EDITOR_WIDGET_STATUS, CTX_INTERACTIVE_EDITOR_LAST_FEEDBACK, CTX_INTERACTIVE_EDITOR_INLNE_DIFF, CTX_INTERACTIVE_EDITOR_EDIT_MODE, EditMode, CTX_INTERACTIVE_EDITOR_LAST_RESPONSE_TYPE, MENU_INTERACTIVE_EDITOR_WIDGET_MARKDOWN_MESSAGE, CTX_INTERACTIVE_EDITOR_MESSAGE_CROP_STATE, CTX_INTERACTIVE_EDITOR_DOCUMENT_CHANGED, CTX_INTERACTIVE_EDITOR_DID_EDIT } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
import { CTX_INTERACTIVE_EDITOR_FOCUSED, CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST, CTX_INTERACTIVE_EDITOR_HAS_PROVIDER, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_FIRST, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST, CTX_INTERACTIVE_EDITOR_EMPTY, CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION, CTX_INTERACTIVE_EDITOR_VISIBLE, MENU_INTERACTIVE_EDITOR_WIDGET, MENU_INTERACTIVE_EDITOR_WIDGET_DISCARD, MENU_INTERACTIVE_EDITOR_WIDGET_STATUS, CTX_INTERACTIVE_EDITOR_LAST_FEEDBACK, CTX_INTERACTIVE_EDITOR_SHOWING_DIFF, CTX_INTERACTIVE_EDITOR_EDIT_MODE, EditMode, CTX_INTERACTIVE_EDITOR_LAST_RESPONSE_TYPE, MENU_INTERACTIVE_EDITOR_WIDGET_MARKDOWN_MESSAGE, CTX_INTERACTIVE_EDITOR_MESSAGE_CROP_STATE, CTX_INTERACTIVE_EDITOR_DOCUMENT_CHANGED, CTX_INTERACTIVE_EDITOR_DID_EDIT } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
import { localize } from 'vs/nls';
import { IAction2Options } from 'vs/platform/actions/common/actions';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
Expand Down Expand Up @@ -374,22 +374,22 @@ export class ToggleInlineDiff extends AbstractInteractiveEditorAction {

constructor() {
super({
id: 'interactiveEditor.toggleInlineDiff',
title: localize('toggleInlineDiff', 'Toggle Inline Diff'),
id: 'interactiveEditor.toggleDiff',
title: localize('toggleDiff', 'Toggle Diff'),
icon: Codicon.diff,
precondition: CTX_INTERACTIVE_EDITOR_VISIBLE,
toggled: CTX_INTERACTIVE_EDITOR_INLNE_DIFF,
toggled: CTX_INTERACTIVE_EDITOR_SHOWING_DIFF,
menu: {
id: MENU_INTERACTIVE_EDITOR_WIDGET_STATUS,
when: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_EDIT_MODE.isEqualTo(EditMode.Live), CTX_INTERACTIVE_EDITOR_LAST_RESPONSE_TYPE.notEqualsTo('message')),
group: '1_main',
order: 1
when: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_EDIT_MODE.notEqualsTo(EditMode.Preview), CTX_INTERACTIVE_EDITOR_DID_EDIT),
group: '0_main',
order: 10
}
});
}

override runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController): void {
ctrl.toggleInlineDiff();
ctrl.toggleDiff();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ export class InteractiveEditorController implements IEditorContribution {
}

dispose(): void {
this._finishExistingSession();
this._store.dispose();
this.cancelSession();
}

getId(): string {
Expand All @@ -145,7 +145,6 @@ export class InteractiveEditorController implements IEditorContribution {
if (this._accessibilityService.isScreenReaderOptimized() && editModeValue === editMode.defaultValue) {
// By default, use preview mode for screen reader users
editModeValue = EditMode.Preview;
this._configurationService.updateValue('interactiveEditor.editMode', EditMode.Preview);
}
return editModeValue!;
}
Expand All @@ -156,19 +155,19 @@ export class InteractiveEditorController implements IEditorContribution {

async run(options: InteractiveEditorRunOptions | undefined): Promise<void> {
this._logService.trace('[IE] session starting');
await this._finishOrCancel();
await this._finishExistingSession();

await this._nextState(State.CREATE_SESSION, { ...options });
this._logService.trace('[IE] session done or paused');
}

private async _finishOrCancel(): Promise<void> {
private async _finishExistingSession(): Promise<void> {
if (this._activeSession) {
if (this._activeSession.editMode === EditMode.Preview) {
this._logService.trace('[IE] an EXISTING session is active, cancelling first');
this._logService.trace('[IE] finishing existing session, using CANCEL', this._activeSession.editMode);
await this.cancelSession();
} else {
this._logService.trace('[IE] an EXISTING session is active, finishing first');
this._logService.trace('[IE] finishing existing session, using APPLY', this._activeSession.editMode);
await this.applyChanges();
}
}
Expand Down Expand Up @@ -292,7 +291,7 @@ export class InteractiveEditorController implements IEditorContribution {
// cancel all sibling sessions
for (const editor of editors) {
if (editor !== this._editor) {
InteractiveEditorController.get(editor)?._finishOrCancel();
InteractiveEditorController.get(editor)?._finishExistingSession();
}
}
break;
Expand Down Expand Up @@ -507,7 +506,7 @@ export class InteractiveEditorController implements IEditorContribution {

try {
this._ignoreModelContentChanged = true;
await this._strategy.renderChanges(response, this._activeSession.lastTextModelChanges);
await this._strategy.renderChanges(response);
} finally {
this._ignoreModelContentChanged = false;
}
Expand Down Expand Up @@ -561,8 +560,8 @@ export class InteractiveEditorController implements IEditorContribution {
}
}

toggleInlineDiff(): void {
this._strategy?.toggleInlineDiff();
toggleDiff(): void {
this._strategy?.toggleDiff();
}

focus(): void {
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 All @@ -30,6 +30,7 @@ import { TextEdit } from 'vs/editor/common/languages';
import { FileKind } from 'vs/platform/files/common/files';
import { IModelService } from 'vs/editor/common/services/model';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Session } from 'vs/workbench/contrib/interactiveEditor/browser/interactiveEditorSession';

export class InteractiveEditorLivePreviewWidget extends ZoneWidget {

Expand All @@ -39,12 +40,12 @@ export class InteractiveEditorLivePreviewWidget extends ZoneWidget {

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

constructor(
editor: ICodeEditor,
private readonly _textModelv0: ITextModel,
private readonly _session: Session,
@IInstantiationService instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@ILogService private readonly _logService: ILogService,
Expand Down Expand Up @@ -80,7 +81,7 @@ export class InteractiveEditorLivePreviewWidget extends ZoneWidget {
modifiedEditor: { contributions: diffContributions }
}, editor);
this._disposables.add(this._diffEditor);
this._diffEditor.setModel({ original: this._textModelv0, modified: editor.getModel() });
this._diffEditor.setModel({ original: this._session.textModel0, modified: editor.getModel() });

const doStyle = () => {
const theme = themeService.getColorTheme();
Expand Down Expand Up @@ -115,40 +116,31 @@ export class InteractiveEditorLivePreviewWidget extends ZoneWidget {

// --- show / hide --------------------

get isVisible(): boolean {
return this._isVisible;
}

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

override show(): void {
throw new Error('not supported like this, use showDiff');
}

showDiff(range: () => Range, changes: LineRangeMapping[]): void {
showDiff(): void {
assertType(this.editor.hasModel());
this._sessionStore.clear();

this._sessionStore.add(this._diffEditor.onDidUpdateDiff(() => {
const result = this._diffEditor.getDiffComputationResult();
const hasFocus = this._diffEditor.hasTextFocus();
this._updateFromChanges(range(), 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(range(), changes);
this._updateFromChanges(this._session.wholeRange, this._session.lastTextModelChanges);
this._isVisible = true;
}

private _updateFromChanges(range: Range, changes: LineRangeMapping[]): void {
assertType(this.editor.hasModel());

if (changes.length === 0 || this._textModelv0.getValueLength() === 0) {
if (changes.length === 0 || this._session.textModel0.getValueLength() === 0) {
// no change or changes to an empty file
this._logService.debug('[IE] livePreview-mode: no diff');
this.hide();
Expand All @@ -170,7 +162,7 @@ export class InteractiveEditorLivePreviewWidget extends ZoneWidget {
// --- inline diff

private _renderChangesWithInlineDiff(changes: LineRangeMapping[]) {
const original = this._textModelv0;
const original = this._session.textModel0;

const decorations: IModelDeltaDecoration[] = [];

Expand Down Expand Up @@ -267,7 +259,7 @@ export class InteractiveEditorLivePreviewWidget extends ZoneWidget {
originalLineRange = new LineRange(originalLineRange.startLineNumber, originalLineRange.endLineNumberExclusive + endDelta);
}

const originalDiffHidden = invertLineRange(originalLineRange, this._textModelv0);
const originalDiffHidden = invertLineRange(originalLineRange, this._session.textModel0);
const modifiedDiffHidden = invertLineRange(modifiedLineRange, model);

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import 'vs/css!./interactiveEditor';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { StableEditorScrollState } from 'vs/editor/browser/stableEditorScroll';
import { EditOperation, ISingleEditOperation } from 'vs/editor/common/core/editOperation';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { LineRangeMapping } from 'vs/editor/common/diff/linesDiffComputer';
import { IEditorDecorationsCollection } from 'vs/editor/common/editorCommon';
import { ICursorStateComputer, IModelDecorationOptions, IModelDeltaDecoration, IValidEditOperation } from 'vs/editor/common/model';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
Expand All @@ -24,7 +24,7 @@ import { InteractiveEditorFileCreatePreviewWidget, InteractiveEditorLivePreviewW
import { EditResponse, Session } from 'vs/workbench/contrib/interactiveEditor/browser/interactiveEditorSession';
import { InteractiveEditorWidget } from 'vs/workbench/contrib/interactiveEditor/browser/interactiveEditorWidget';
import { getValueFromSnapshot } from 'vs/workbench/contrib/interactiveEditor/browser/utils';
import { CTX_INTERACTIVE_EDITOR_INLNE_DIFF, CTX_INTERACTIVE_EDITOR_DOCUMENT_CHANGED } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
import { CTX_INTERACTIVE_EDITOR_SHOWING_DIFF, CTX_INTERACTIVE_EDITOR_DOCUMENT_CHANGED } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';

export abstract class EditModeStrategy {
Expand All @@ -39,9 +39,9 @@ export abstract class EditModeStrategy {

abstract makeChanges(response: EditResponse, edits: ISingleEditOperation[]): Promise<void>;

abstract renderChanges(response: EditResponse, changes: LineRangeMapping[]): Promise<void>;
abstract renderChanges(response: EditResponse): Promise<void>;

abstract toggleInlineDiff(): void;
abstract toggleDiff(): void;
}

export class PreviewStrategy extends EditModeStrategy {
Expand Down Expand Up @@ -111,10 +111,10 @@ export class PreviewStrategy extends EditModeStrategy {
// nothing to do
}

override async renderChanges(response: EditResponse, changes: LineRangeMapping[]): Promise<void> {
override async renderChanges(response: EditResponse): Promise<void> {
if (response.localEdits.length > 0) {
const edits = response.localEdits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text));
this._widget.showEditsPreview(this._session.textModel0, edits, changes);
this._widget.showEditsPreview(this._session.textModel0, edits, this._session.lastTextModelChanges);
} else {
this._widget.hideEditsPreview();
}
Expand All @@ -126,7 +126,9 @@ export class PreviewStrategy extends EditModeStrategy {
}
}

toggleInlineDiff(): void { }
toggleDiff(): void {
// nothing to do
}
}

class InlineDiffDecorations {
Expand Down Expand Up @@ -202,7 +204,7 @@ export class LiveStrategy extends EditModeStrategy {
private _inlineDiffEnabled: boolean = false;

private readonly _inlineDiffDecorations: InlineDiffDecorations;
private readonly _ctxInlineDiff: IContextKey<boolean>;
protected readonly _ctxShowingDiff: IContextKey<boolean>;
private _lastResponse?: EditResponse;
private _editCount: number = 0;

Expand All @@ -218,25 +220,25 @@ export class LiveStrategy extends EditModeStrategy {
) {
super();
this._inlineDiffDecorations = new InlineDiffDecorations(this._editor, this._inlineDiffEnabled);
this._ctxInlineDiff = CTX_INTERACTIVE_EDITOR_INLNE_DIFF.bindTo(contextKeyService);
this._ctxShowingDiff = CTX_INTERACTIVE_EDITOR_SHOWING_DIFF.bindTo(contextKeyService);

this._inlineDiffEnabled = _storageService.getBoolean(LiveStrategy._inlineDiffStorageKey, StorageScope.PROFILE, false);
this._ctxInlineDiff.set(this._inlineDiffEnabled);
this._ctxShowingDiff.set(this._inlineDiffEnabled);
this._inlineDiffDecorations.visible = this._inlineDiffEnabled;
}

override dispose(): void {
this._inlineDiffEnabled = this._inlineDiffDecorations.visible;
this._storageService.store(LiveStrategy._inlineDiffStorageKey, this._inlineDiffEnabled, StorageScope.PROFILE, StorageTarget.USER);
this._inlineDiffDecorations.clear();
this._ctxInlineDiff.reset();
this._ctxShowingDiff.reset();

super.dispose();
}

toggleInlineDiff(): void {
toggleDiff(): void {
this._inlineDiffEnabled = !this._inlineDiffEnabled;
this._ctxInlineDiff.set(this._inlineDiffEnabled);
this._ctxShowingDiff.set(this._inlineDiffEnabled);
this._inlineDiffDecorations.visible = this._inlineDiffEnabled;
this._storageService.store(LiveStrategy._inlineDiffStorageKey, this._inlineDiffEnabled, StorageScope.PROFILE, StorageTarget.USER);
}
Expand Down Expand Up @@ -298,10 +300,10 @@ export class LiveStrategy extends EditModeStrategy {
this._editor.executeEdits('interactive-editor-live', edits, ignoreInlineDiff ? undefined : cursorStateComputerAndInlineDiffCollection);
}

override async renderChanges(response: EditResponse, textModel0Changes: LineRangeMapping[]) {
override async renderChanges(response: EditResponse) {

this._inlineDiffDecorations.update();
this._updateSummaryMessage(textModel0Changes);
this._updateSummaryMessage();

if (response.singleCreateFileEdit) {
this._widget.showCreatePreview(response.singleCreateFileEdit.uri, await Promise.all(response.singleCreateFileEdit.edits));
Expand All @@ -310,12 +312,10 @@ export class LiveStrategy extends EditModeStrategy {
}
}

protected _updateSummaryMessage(textModel0Changes: LineRangeMapping[]) {
protected _updateSummaryMessage() {
let linesChanged = 0;
if (textModel0Changes) {
for (const change of textModel0Changes) {
linesChanged += change.changedLineCount;
}
for (const change of this._session.lastTextModelChanges) {
linesChanged += change.changedLineCount;
}
let message: string;
if (linesChanged === 0) {
Expand Down Expand Up @@ -346,7 +346,7 @@ export class LivePreviewStrategy extends LiveStrategy {
) {
super(session, editor, widget, contextKeyService, storageService, bulkEditService, editorWorkerService, instaService);

this._diffZone = instaService.createInstance(InteractiveEditorLivePreviewWidget, editor, session.textModel0);
this._diffZone = instaService.createInstance(InteractiveEditorLivePreviewWidget, editor, session);
this._previewZone = instaService.createInstance(InteractiveEditorFileCreatePreviewWidget, editor);
}

Expand All @@ -362,17 +362,31 @@ export class LivePreviewStrategy extends LiveStrategy {
super.makeChanges(_response, edits, true);
}

override async renderChanges(response: EditResponse, changes: LineRangeMapping[]) {
override async renderChanges(response: EditResponse) {

this._diffZone.showDiff(() => this._session.wholeRange, changes);
this._updateSummaryMessage(changes);
this._diffZone.showDiff();
this._updateSummaryMessage();
this._ctxShowingDiff.set(true);

if (response.singleCreateFileEdit) {
this._previewZone.showCreation(this._session.wholeRange, response.singleCreateFileEdit.uri, await Promise.all(response.singleCreateFileEdit.edits));
} else {
this._previewZone.hide();
}
}

override toggleDiff(): void {
// TODO@jrieken should this be persisted like we do in live-mode?
const scrollState = StableEditorScrollState.capture(this._editor);
if (this._diffZone.isVisible) {
this._diffZone.hide();
this._ctxShowingDiff.set(false);
} else {
this._diffZone.showDiff();
this._ctxShowingDiff.set(true);
}
scrollState.restore(this._editor);
}
}

function showSingleCreateFile(accessor: ServicesAccessor, edit: EditResponse) {
Expand Down
Loading

0 comments on commit 3e4ed47

Please sign in to comment.