Skip to content

Commit 9e5ddd4

Browse files
authored
joh/remarkable egret (microsoft#182507)
* For preview modes bring back actions to discard but keep changes in clipboard or new file, in live modes ESC accepts, in preview is cancels, DropDownWithDefault tweaks so that the first option can always be the default * handle reentrant editor chat with cancel or accept (depending on mode)
1 parent e14e406 commit 9e5ddd4

File tree

8 files changed

+164
-120
lines changed

8 files changed

+164
-120
lines changed

src/vs/platform/actions/browser/menuEntryActionViewItem.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -320,14 +320,15 @@ export class SubmenuEntryActionViewItem extends DropdownMenuActionViewItem {
320320

321321
export interface IDropdownWithDefaultActionViewItemOptions extends IDropdownMenuActionViewItemOptions {
322322
renderKeybindingWithDefaultActionLabel?: boolean;
323+
persistLastActionId?: boolean;
323324
}
324325

325326
export class DropdownWithDefaultActionViewItem extends BaseActionViewItem {
326327
private readonly _options: IDropdownWithDefaultActionViewItemOptions | undefined;
327328
private _defaultAction: ActionViewItem;
328-
private _dropdown: DropdownMenuActionViewItem;
329+
private readonly _dropdown: DropdownMenuActionViewItem;
329330
private _container: HTMLElement | null = null;
330-
private _storageKey: string;
331+
private readonly _storageKey: string;
331332

332333
get onDidChangeDropdownVisibility(): Event<boolean> {
333334
return this._dropdown.onDidChangeVisibility;
@@ -349,7 +350,7 @@ export class DropdownWithDefaultActionViewItem extends BaseActionViewItem {
349350

350351
// determine default action
351352
let defaultAction: IAction | undefined;
352-
const defaultActionId = _storageService.get(this._storageKey, StorageScope.WORKSPACE);
353+
const defaultActionId = options?.persistLastActionId ? _storageService.get(this._storageKey, StorageScope.WORKSPACE) : undefined;
353354
if (defaultActionId) {
354355
defaultAction = submenuAction.actions.find(a => defaultActionId === a.id);
355356
}
@@ -359,11 +360,13 @@ export class DropdownWithDefaultActionViewItem extends BaseActionViewItem {
359360

360361
this._defaultAction = this._instaService.createInstance(MenuEntryActionViewItem, <MenuItemAction>defaultAction, { keybinding: this._getDefaultActionKeybindingLabel(defaultAction) });
361362

362-
const dropdownOptions = Object.assign({}, options ?? Object.create(null), {
363+
const dropdownOptions: IDropdownMenuActionViewItemOptions = {
364+
keybindingProvider: action => this._keybindingService.lookupKeybinding(action.id),
365+
...options,
363366
menuAsChild: options?.menuAsChild ?? true,
364367
classNames: options?.classNames ?? ['codicon', 'codicon-chevron-down'],
365-
actionRunner: options?.actionRunner ?? new ActionRunner()
366-
});
368+
actionRunner: options?.actionRunner ?? new ActionRunner(),
369+
};
367370

368371
this._dropdown = new DropdownMenuActionViewItem(submenuAction, submenuAction.actions, this._contextMenuService, dropdownOptions);
369372
this._dropdown.actionRunner.onDidRun((e: IRunEvent) => {
@@ -374,7 +377,9 @@ export class DropdownWithDefaultActionViewItem extends BaseActionViewItem {
374377
}
375378

376379
private update(lastAction: MenuItemAction): void {
377-
this._storageService.store(this._storageKey, lastAction.id, StorageScope.WORKSPACE, StorageTarget.MACHINE);
380+
if (this._options?.persistLastActionId) {
381+
this._storageService.store(this._storageKey, lastAction.id, StorageScope.WORKSPACE, StorageTarget.MACHINE);
382+
}
378383

379384
this._defaultAction.dispose();
380385
this._defaultAction = this._instaService.createInstance(MenuEntryActionViewItem, lastAction, { keybinding: this._getDefaultActionKeybindingLabel(lastAction) });
@@ -505,7 +510,7 @@ export function createActionViewItem(instaService: IInstantiationService, action
505510
return instaService.createInstance(SubmenuEntrySelectActionViewItem, action);
506511
} else {
507512
if (action.item.rememberDefaultAction) {
508-
return instaService.createInstance(DropdownWithDefaultActionViewItem, action, options);
513+
return instaService.createInstance(DropdownWithDefaultActionViewItem, action, { ...options, persistLastActionId: true });
509514
} else {
510515
return instaService.createInstance(SubmenuEntryActionViewItem, action, options);
511516
}

src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditor.contribution.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ registerEditorContribution(INTERACTIVE_EDITOR_ID, InteractiveEditorController, E
2020
registerAction2(interactiveEditorActions.StartSessionAction);
2121
registerAction2(interactiveEditorActions.MakeRequestAction);
2222
registerAction2(interactiveEditorActions.StopRequestAction);
23+
registerAction2(interactiveEditorActions.DicardAction);
24+
registerAction2(interactiveEditorActions.DiscardToClipboardAction);
25+
registerAction2(interactiveEditorActions.DiscardUndoToNewFileAction);
2326
registerAction2(interactiveEditorActions.CancelSessionAction);
27+
2428
registerAction2(interactiveEditorActions.ArrowOutUpAction);
2529
registerAction2(interactiveEditorActions.ArrowOutDownAction);
2630
registerAction2(interactiveEditorActions.FocusInteractiveEditor);
@@ -30,9 +34,6 @@ registerAction2(interactiveEditorActions.ViewInChatAction);
3034
registerAction2(interactiveEditorActions.ExpandMessageAction);
3135
registerAction2(interactiveEditorActions.ContractMessageAction);
3236

33-
registerAction2(interactiveEditorActions.UndoToClipboard);
34-
registerAction2(interactiveEditorActions.UndoToNewFile);
35-
registerAction2(interactiveEditorActions.UndoCommand);
3637
registerAction2(interactiveEditorActions.ToggleInlineDiff);
3738
registerAction2(interactiveEditorActions.FeebackHelpfulCommand);
3839
registerAction2(interactiveEditorActions.FeebackUnhelpfulCommand);

src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorActions.ts

Lines changed: 58 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { EditorAction2 } from 'vs/editor/browser/editorExtensions';
1010
import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
1111
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
1212
import { InteractiveEditorController, InteractiveEditorRunOptions } from 'vs/workbench/contrib/interactiveEditor/browser/interactiveEditorController';
13-
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, CTX_INTERACTIVE_EDITOR_LAST_EDIT_TYPE, MENU_INTERACTIVE_EDITOR_WIDGET_UNDO, 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 } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
13+
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';
1414
import { localize } from 'vs/nls';
1515
import { IAction2Options } from 'vs/platform/actions/common/actions';
1616
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
@@ -20,7 +20,6 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
2020
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
2121
import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
2222
import { IUntitledTextResourceEditorInput } from 'vs/workbench/common/editor';
23-
import { ILogService } from 'vs/platform/log/common/log';
2423
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
2524
import { Range } from 'vs/editor/common/core/range';
2625
import { fromNow } from 'vs/base/common/date';
@@ -251,86 +250,79 @@ export class NextFromHistory extends AbstractInteractiveEditorAction {
251250
}
252251
}
253252

254-
255-
export class UndoToClipboard extends AbstractInteractiveEditorAction {
253+
export class DicardAction extends AbstractInteractiveEditorAction {
256254

257255
constructor() {
258256
super({
259-
id: 'interactiveEditor.undoToClipboard',
260-
title: localize('undo.clipboard', 'Undo to Clipboard'),
261-
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, CTX_INTERACTIVE_EDITOR_LAST_EDIT_TYPE.isEqualTo('simple')),
262-
keybinding: {
263-
weight: KeybindingWeight.EditorContrib + 10,
264-
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyZ,
265-
mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyZ },
266-
},
257+
id: 'interactiveEditor.discard',
258+
title: localize('discard', 'Discard'),
259+
icon: Codicon.discard,
260+
precondition: CTX_INTERACTIVE_EDITOR_VISIBLE,
261+
// keybinding: {
262+
// weight: KeybindingWeight.EditorContrib - 1,
263+
// primary: KeyCode.Escape
264+
// },
267265
menu: {
268-
when: CTX_INTERACTIVE_EDITOR_LAST_EDIT_TYPE.isEqualTo('simple'),
269-
id: MENU_INTERACTIVE_EDITOR_WIDGET_UNDO,
270-
group: '1_undo',
271-
order: 1
266+
id: MENU_INTERACTIVE_EDITOR_WIDGET_DISCARD,
267+
order: 0
272268
}
273269
});
274270
}
275271

276-
override runInteractiveEditorCommand(accessor: ServicesAccessor, ctrl: InteractiveEditorController): void {
277-
const clipboardService = accessor.get(IClipboardService);
278-
const lastText = ctrl.undoLast();
279-
if (lastText !== undefined) {
280-
clipboardService.writeText(lastText);
281-
}
272+
async runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController, _editor: ICodeEditor, ..._args: any[]): Promise<void> {
273+
await ctrl.cancelSession();
282274
}
283275
}
284276

285-
export class UndoToNewFile extends AbstractInteractiveEditorAction {
277+
export class DiscardToClipboardAction extends AbstractInteractiveEditorAction {
286278

287279
constructor() {
288280
super({
289-
id: 'interactiveEditor.undoToFile',
290-
title: localize('undo.newfile', 'Undo to New File'),
291-
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, CTX_INTERACTIVE_EDITOR_LAST_EDIT_TYPE.isEqualTo('simple')),
281+
id: 'interactiveEditor.discardToClipboard',
282+
title: localize('undo.clipboard', 'Discard to Clipboard'),
283+
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, CTX_INTERACTIVE_EDITOR_DID_EDIT),
284+
// keybinding: {
285+
// weight: KeybindingWeight.EditorContrib + 10,
286+
// primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyZ,
287+
// mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyZ },
288+
// },
292289
menu: {
293-
when: CTX_INTERACTIVE_EDITOR_LAST_EDIT_TYPE.isEqualTo('simple'),
294-
id: MENU_INTERACTIVE_EDITOR_WIDGET_UNDO,
295-
group: '1_undo',
296-
order: 2
290+
id: MENU_INTERACTIVE_EDITOR_WIDGET_DISCARD,
291+
order: 1
297292
}
298293
});
299294
}
300295

301-
override runInteractiveEditorCommand(accessor: ServicesAccessor, ctrl: InteractiveEditorController, editor: ICodeEditor, ..._args: any[]): void {
302-
const editorService = accessor.get(IEditorService);
303-
const lastText = ctrl.undoLast();
304-
if (lastText !== undefined) {
305-
const input: IUntitledTextResourceEditorInput = { forceUntitled: true, resource: undefined, contents: lastText, languageId: editor.getModel()?.getLanguageId() };
306-
editorService.openEditor(input, SIDE_GROUP);
296+
override async runInteractiveEditorCommand(accessor: ServicesAccessor, ctrl: InteractiveEditorController): Promise<void> {
297+
const clipboardService = accessor.get(IClipboardService);
298+
const changedText = await ctrl.cancelSession();
299+
if (changedText !== undefined) {
300+
clipboardService.writeText(changedText);
307301
}
308302
}
309303
}
310304

311-
export class UndoCommand extends AbstractInteractiveEditorAction {
305+
export class DiscardUndoToNewFileAction extends AbstractInteractiveEditorAction {
312306

313307
constructor() {
314308
super({
315-
id: 'interactiveEditor.undo',
316-
title: localize('undo', 'Undo'),
317-
icon: Codicon.commentDiscussion,
318-
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, CTX_INTERACTIVE_EDITOR_LAST_EDIT_TYPE.isEqualTo('simple')),
319-
// keybinding: {
320-
// weight: KeybindingWeight.EditorContrib + 10,
321-
// primary: KeyMod.CtrlCmd | KeyCode.KeyZ,
322-
// },
309+
id: 'interactiveEditor.discardToFile',
310+
title: localize('undo.newfile', 'Discard to New File'),
311+
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, CTX_INTERACTIVE_EDITOR_DID_EDIT),
323312
menu: {
324-
when: CTX_INTERACTIVE_EDITOR_LAST_EDIT_TYPE.isEqualTo('simple'),
325-
id: MENU_INTERACTIVE_EDITOR_WIDGET_UNDO,
326-
group: '1_undo',
327-
order: 3
313+
id: MENU_INTERACTIVE_EDITOR_WIDGET_DISCARD,
314+
order: 2
328315
}
329316
});
330317
}
331318

332-
override runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController): void {
333-
ctrl.undoLast();
319+
override async runInteractiveEditorCommand(accessor: ServicesAccessor, ctrl: InteractiveEditorController, editor: ICodeEditor, ..._args: any[]): Promise<void> {
320+
const editorService = accessor.get(IEditorService);
321+
const changedText = await ctrl.cancelSession();
322+
if (changedText !== undefined) {
323+
const input: IUntitledTextResourceEditorInput = { forceUntitled: true, resource: undefined, contents: changedText, languageId: editor.getModel()?.getLanguageId() };
324+
editorService.openEditor(input, SIDE_GROUP);
325+
}
334326
}
335327
}
336328

@@ -409,30 +401,25 @@ export class ApplyPreviewEdits extends AbstractInteractiveEditorAction {
409401
title: localize('applyEdits', 'Apply Changes'),
410402
icon: Codicon.check,
411403
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, ContextKeyExpr.or(CTX_INTERACTIVE_EDITOR_DOCUMENT_CHANGED.toNegated(), CTX_INTERACTIVE_EDITOR_EDIT_MODE.notEqualsTo(EditMode.Preview))),
412-
keybinding: {
404+
keybinding: [{
413405
weight: KeybindingWeight.EditorContrib + 10,
414-
primary: KeyMod.CtrlCmd | KeyCode.Enter
415-
},
406+
primary: KeyMod.CtrlCmd | KeyCode.Enter,
407+
}, {
408+
weight: KeybindingWeight.EditorContrib + 10,
409+
primary: KeyCode.Escape,
410+
when: CTX_INTERACTIVE_EDITOR_EDIT_MODE.notEqualsTo(EditMode.Preview)
411+
}],
416412
menu: {
417413
id: MENU_INTERACTIVE_EDITOR_WIDGET_STATUS,
414+
when: CTX_INTERACTIVE_EDITOR_EDIT_MODE.isEqualTo(EditMode.Preview),
418415
group: '0_main',
419416
order: 0
420417
}
421418
});
422419
}
423420

424-
override async runInteractiveEditorCommand(accessor: ServicesAccessor, ctrl: InteractiveEditorController): Promise<void> {
425-
const logService = accessor.get(ILogService);
426-
const editorService = accessor.get(IEditorService);
427-
const edit = await ctrl.applyChanges();
428-
if (!edit) {
429-
logService.warn('FAILED to apply changes, no edit response');
430-
return;
431-
}
432-
if (edit.singleCreateFileEdit) {
433-
editorService.openEditor({ resource: edit.singleCreateFileEdit.uri }, SIDE_GROUP);
434-
}
435-
421+
override async runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController): Promise<void> {
422+
await ctrl.applyChanges();
436423
}
437424
}
438425

@@ -441,15 +428,16 @@ export class CancelSessionAction extends AbstractInteractiveEditorAction {
441428
constructor() {
442429
super({
443430
id: 'interactiveEditor.cancel',
444-
title: localize('discard', 'Discard Changes'),
431+
title: localize('cancel', 'Cancel'),
445432
icon: Codicon.clearAll,
446-
precondition: CTX_INTERACTIVE_EDITOR_VISIBLE,
433+
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, CTX_INTERACTIVE_EDITOR_EDIT_MODE.isEqualTo(EditMode.Preview)),
447434
keybinding: {
448435
weight: KeybindingWeight.EditorContrib - 1,
449436
primary: KeyCode.Escape
450437
},
451438
menu: {
452439
id: MENU_INTERACTIVE_EDITOR_WIDGET_STATUS,
440+
when: CTX_INTERACTIVE_EDITOR_EDIT_MODE.isEqualTo(EditMode.Preview),
453441
group: '0_main',
454442
order: 1
455443
}
@@ -468,7 +456,8 @@ export class CopyRecordings extends AbstractInteractiveEditorAction {
468456
id: 'interactiveEditor.copyRecordings',
469457
f1: true,
470458
title: {
471-
value: localize('copyRecordings', '(Developer) Write Exchange to Clipboard'), original: '(Developer) Write Exchange to Clipboard'
459+
value: localize('copyRecordings', '(Developer) Write Exchange to Clipboard'),
460+
original: '(Developer) Write Exchange to Clipboard'
472461
}
473462
});
474463
}

0 commit comments

Comments
 (0)