Skip to content

Commit e54405c

Browse files
committed
render view in chat as primary btn, render view in chat and accept depending on having mixed reply types or not
microsoft/vscode-copilot#299
1 parent 7a3e367 commit e54405c

File tree

6 files changed

+49
-12
lines changed

6 files changed

+49
-12
lines changed

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
1818
export type IButtonConfigProvider = (action: IAction) => {
1919
showIcon?: boolean;
2020
showLabel?: boolean;
21+
isSecondary?: boolean;
2122
} | undefined;
2223

2324
export interface IMenuWorkbenchButtonBarOptions {
@@ -68,6 +69,7 @@ export class MenuWorkbenchButtonBar extends ButtonBar {
6869
.flatMap(entry => entry[1]);
6970

7071
for (let i = 0; i < actions.length; i++) {
72+
7173
const secondary = i > 0;
7274
const actionOrSubmenu = actions[i];
7375
let action: MenuItemAction | SubmenuItemAction;
@@ -77,14 +79,16 @@ export class MenuWorkbenchButtonBar extends ButtonBar {
7779
const [first, ...rest] = actionOrSubmenu.actions;
7880
action = <MenuItemAction>first;
7981
btn = this.addButtonWithDropdown({
80-
secondary,
82+
secondary: conifgProvider(action)?.isSecondary ?? secondary,
8183
actionRunner,
8284
actions: rest,
8385
contextMenuProvider: contextMenuService,
8486
});
8587
} else {
8688
action = actionOrSubmenu;
87-
btn = this.addButton({ secondary });
89+
btn = this.addButton({
90+
secondary: conifgProvider(action)?.isSecondary ?? secondary,
91+
});
8892
}
8993

9094
btn.enabled = action.enabled;

src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts

Lines changed: 9 additions & 8 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 { InlineChatController, InlineChatRunOptions } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
13-
import { CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST, CTX_INLINE_CHAT_HAS_PROVIDER, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_EMPTY, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_VISIBLE, MENU_INLINE_CHAT_WIDGET, MENU_INLINE_CHAT_WIDGET_DISCARD, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_LAST_FEEDBACK, CTX_INLINE_CHAT_SHOWING_DIFF, CTX_INLINE_CHAT_EDIT_MODE, EditMode, CTX_INLINE_CHAT_LAST_RESPONSE_TYPE, MENU_INLINE_CHAT_WIDGET_MARKDOWN_MESSAGE, CTX_INLINE_CHAT_MESSAGE_CROP_STATE, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_DID_EDIT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, MENU_INLINE_CHAT_WIDGET_FEEDBACK, ACTION_ACCEPT_CHANGES, ACTION_REGENERATE_RESPONSE, InlineChatResponseType } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
13+
import { CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST, CTX_INLINE_CHAT_HAS_PROVIDER, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_EMPTY, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_VISIBLE, MENU_INLINE_CHAT_WIDGET, MENU_INLINE_CHAT_WIDGET_DISCARD, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_LAST_FEEDBACK, CTX_INLINE_CHAT_SHOWING_DIFF, CTX_INLINE_CHAT_EDIT_MODE, EditMode, CTX_INLINE_CHAT_LAST_RESPONSE_TYPE, MENU_INLINE_CHAT_WIDGET_MARKDOWN_MESSAGE, CTX_INLINE_CHAT_MESSAGE_CROP_STATE, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_DID_EDIT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, MENU_INLINE_CHAT_WIDGET_FEEDBACK, ACTION_ACCEPT_CHANGES, ACTION_REGENERATE_RESPONSE, InlineChatResponseType, CTX_INLINE_CHAT_RESPONSE_TYPES, InlineChateResponseTypes, ACTION_VIEW_IN_CHAT } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
1414
import { localize } from 'vs/nls';
1515
import { IAction2Options, MenuRegistry } from 'vs/platform/actions/common/actions';
1616
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
@@ -313,8 +313,8 @@ MenuRegistry.appendMenuItem(MENU_INLINE_CHAT_WIDGET_STATUS, {
313313
title: localize('discardMenu', "Discard..."),
314314
icon: Codicon.discard,
315315
group: '0_main',
316-
order: 3,
317-
when: CTX_INLINE_CHAT_EDIT_MODE.notEqualsTo(EditMode.Preview),
316+
order: 2,
317+
when: ContextKeyExpr.and(CTX_INLINE_CHAT_EDIT_MODE.notEqualsTo(EditMode.Preview), CTX_INLINE_CHAT_RESPONSE_TYPES.notEqualsTo(InlineChateResponseTypes.OnlyMessages)),
318318
rememberDefaultAction: true
319319
});
320320

@@ -479,6 +479,7 @@ export class ApplyPreviewEdits extends AbstractInlineChatAction {
479479
primary: KeyMod.CtrlCmd | KeyCode.Enter,
480480
}],
481481
menu: {
482+
when: CTX_INLINE_CHAT_RESPONSE_TYPES.notEqualsTo(InlineChateResponseTypes.OnlyMessages),
482483
id: MENU_INLINE_CHAT_WIDGET_STATUS,
483484
group: '0_main',
484485
order: 0
@@ -498,16 +499,16 @@ export class CancelSessionAction extends AbstractInlineChatAction {
498499
id: 'inlineChat.cancel',
499500
title: localize('cancel', 'Cancel'),
500501
icon: Codicon.clearAll,
501-
precondition: ContextKeyExpr.and(CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_EDIT_MODE.isEqualTo(EditMode.Preview)),
502+
precondition: CTX_INLINE_CHAT_VISIBLE,
502503
keybinding: {
503504
weight: KeybindingWeight.EditorContrib - 1,
504505
primary: KeyCode.Escape
505506
},
506507
menu: {
507508
id: MENU_INLINE_CHAT_WIDGET_STATUS,
508-
when: CTX_INLINE_CHAT_EDIT_MODE.isEqualTo(EditMode.Preview),
509+
when: ContextKeyExpr.or(CTX_INLINE_CHAT_EDIT_MODE.isEqualTo(EditMode.Preview), CTX_INLINE_CHAT_RESPONSE_TYPES.isEqualTo(InlineChateResponseTypes.OnlyMessages)),
509510
group: '0_main',
510-
order: 1
511+
order: 3
511512
}
512513
});
513514
}
@@ -559,15 +560,15 @@ export class CopyRecordings extends AbstractInlineChatAction {
559560
export class ViewInChatAction extends AbstractInlineChatAction {
560561
constructor() {
561562
super({
562-
id: 'inlineChat.viewInChat',
563+
id: ACTION_VIEW_IN_CHAT,
563564
title: localize('viewInChat', 'View in Chat'),
564565
icon: Codicon.commentDiscussion,
565566
precondition: CTX_INLINE_CHAT_VISIBLE,
566567
menu: {
567568
id: MENU_INLINE_CHAT_WIDGET_STATUS,
568569
when: CTX_INLINE_CHAT_LAST_RESPONSE_TYPE.isEqualTo(InlineChatResponseType.Message),
569570
group: '0_main',
570-
order: 2
571+
order: 1
571572
}
572573
});
573574
}

src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { ILogService } from 'vs/platform/log/common/log';
3131
import { EditResponse, EmptyResponse, ErrorResponse, ExpansionState, IInlineChatSessionService, MarkdownResponse, Session, SessionExchange, SessionPrompt } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession';
3232
import { EditModeStrategy, LivePreviewStrategy, LiveStrategy, PreviewStrategy } from 'vs/workbench/contrib/inlineChat/browser/inlineChatStrategies';
3333
import { InlineChatZoneWidget } from 'vs/workbench/contrib/inlineChat/browser/inlineChatWidget';
34-
import { CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST, CTX_INLINE_CHAT_LAST_FEEDBACK, IInlineChatRequest, IInlineChatResponse, INLINE_CHAT_ID, EditMode, InlineChatResponseFeedbackKind, CTX_INLINE_CHAT_LAST_RESPONSE_TYPE, InlineChatResponseType, CTX_INLINE_CHAT_DID_EDIT, CTX_INLINE_CHAT_HAS_STASHED_SESSION } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
34+
import { CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST, CTX_INLINE_CHAT_LAST_FEEDBACK, IInlineChatRequest, IInlineChatResponse, INLINE_CHAT_ID, EditMode, InlineChatResponseFeedbackKind, CTX_INLINE_CHAT_LAST_RESPONSE_TYPE, InlineChatResponseType, CTX_INLINE_CHAT_DID_EDIT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, InlineChateResponseTypes, CTX_INLINE_CHAT_RESPONSE_TYPES } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
3535
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
3636
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
3737
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/services/notebookEditorService';
@@ -90,6 +90,7 @@ export class InlineChatController implements IEditorContribution {
9090
private readonly _zone: Lazy<InlineChatZoneWidget>;
9191
private readonly _ctxHasActiveRequest: IContextKey<boolean>;
9292
private readonly _ctxLastResponseType: IContextKey<undefined | InlineChatResponseType>;
93+
private readonly _ctxResponseTypes: IContextKey<undefined | InlineChateResponseTypes>;
9394
private readonly _ctxDidEdit: IContextKey<boolean>;
9495
private readonly _ctxLastFeedbackKind: IContextKey<'helpful' | 'unhelpful' | ''>;
9596

@@ -117,6 +118,7 @@ export class InlineChatController implements IEditorContribution {
117118
) {
118119
this._ctxHasActiveRequest = CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST.bindTo(contextKeyService);
119120
this._ctxDidEdit = CTX_INLINE_CHAT_DID_EDIT.bindTo(contextKeyService);
121+
this._ctxResponseTypes = CTX_INLINE_CHAT_RESPONSE_TYPES.bindTo(contextKeyService);
120122
this._ctxLastResponseType = CTX_INLINE_CHAT_LAST_RESPONSE_TYPE.bindTo(contextKeyService);
121123
this._ctxLastFeedbackKind = CTX_INLINE_CHAT_LAST_FEEDBACK.bindTo(contextKeyService);
122124
this._zone = new Lazy(() => this._store.add(_instaService.createInstance(InlineChatZoneWidget, this._editor)));
@@ -598,6 +600,22 @@ export class InlineChatController implements IEditorContribution {
598600
? response.raw.type
599601
: undefined);
600602

603+
let responseTypes: InlineChateResponseTypes | undefined;
604+
for (const { response } of this._activeSession.exchanges) {
605+
606+
const thisType = response instanceof MarkdownResponse
607+
? InlineChateResponseTypes.OnlyMessages : response instanceof EditResponse
608+
? InlineChateResponseTypes.OnlyEdits : undefined;
609+
610+
if (responseTypes === undefined) {
611+
responseTypes = thisType;
612+
} else if (responseTypes !== thisType) {
613+
responseTypes = InlineChateResponseTypes.Mixed;
614+
break;
615+
}
616+
}
617+
this._ctxResponseTypes.set(responseTypes);
618+
601619
if (response instanceof EmptyResponse) {
602620
// show status message
603621
this._zone.value.widget.updateStatus(localize('empty', "No results, please refine your input and try again"), { classes: ['warn'] });

src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ export class Session {
179179
this._teldata.rounds += `${newLen}|`;
180180
}
181181

182+
get exchanges(): Iterable<SessionExchange> {
183+
return this._exchange;
184+
}
185+
182186
get lastExchange(): SessionExchange | undefined {
183187
return this._exchange[this._exchange.length - 1];
184188
}

src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { localize } from 'vs/nls';
1212
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
1313
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
1414
import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/browser/zoneWidget';
15-
import { CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_EMPTY, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_VISIBLE, MENU_INLINE_CHAT_WIDGET, MENU_INLINE_CHAT_WIDGET_STATUS, MENU_INLINE_CHAT_WIDGET_MARKDOWN_MESSAGE, CTX_INLINE_CHAT_MESSAGE_CROP_STATE, IInlineChatSlashCommand, MENU_INLINE_CHAT_WIDGET_FEEDBACK, ACTION_REGENERATE_RESPONSE } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
15+
import { CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_EMPTY, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_VISIBLE, MENU_INLINE_CHAT_WIDGET, MENU_INLINE_CHAT_WIDGET_STATUS, MENU_INLINE_CHAT_WIDGET_MARKDOWN_MESSAGE, CTX_INLINE_CHAT_MESSAGE_CROP_STATE, IInlineChatSlashCommand, MENU_INLINE_CHAT_WIDGET_FEEDBACK, ACTION_REGENERATE_RESPONSE, ACTION_VIEW_IN_CHAT } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
1616
import { IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';
1717
import { Dimension, addDisposableListener, getActiveElement, getTotalHeight, getTotalWidth, h, reset } from 'vs/base/browser/dom';
1818
import { Emitter, Event, MicrotaskEmitter } from 'vs/base/common/event';
@@ -294,6 +294,8 @@ export class InlineChatWidget {
294294
buttonConfigProvider: action => {
295295
if (action.id === ACTION_REGENERATE_RESPONSE) {
296296
return { showIcon: true, showLabel: false };
297+
} else if (action.id === ACTION_VIEW_IN_CHAT) {
298+
return { isSecondary: false };
297299
}
298300
return undefined;
299301
}

src/vs/workbench/contrib/inlineChat/common/inlineChat.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ export const enum InlineChatResponseType {
4949
Message = 'message'
5050
}
5151

52+
export const enum InlineChateResponseTypes {
53+
OnlyMessages = 'onlyMessages',
54+
OnlyEdits = 'onlyEdits',
55+
Mixed = 'mixed'
56+
}
57+
5258
export interface IInlineChatEditResponse {
5359
id: number;
5460
type: InlineChatResponseType.EditorEdit;
@@ -114,6 +120,7 @@ export const CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST = new RawContextKey<boolean>('in
114120
export const CTX_INLINE_CHAT_HAS_STASHED_SESSION = new RawContextKey<boolean>('inlineChatHasStashedSession', false, localize('inlineChatHasStashedSession', "Whether interactive editor has kept a session for quick restore"));
115121
export const CTX_INLINE_CHAT_SHOWING_DIFF = new RawContextKey<boolean>('inlineChatDiff', false, localize('inlineChatDiff', "Whether interactive editor show diffs for changes"));
116122
export const CTX_INLINE_CHAT_LAST_RESPONSE_TYPE = new RawContextKey<InlineChatResponseType | undefined>('inlineChatLastResponseType', undefined, localize('inlineChatResponseType', "What type was the last response of the current interactive editor session"));
123+
export const CTX_INLINE_CHAT_RESPONSE_TYPES = new RawContextKey<InlineChateResponseTypes | undefined>('inlineChatResponseTypes', undefined, localize('inlineChatResponseTypes', "What type was the responses have been receieved"));
117124
export const CTX_INLINE_CHAT_DID_EDIT = new RawContextKey<boolean>('inlineChatDidEdit', false, localize('inlineChatDidEdit', "Whether interactive editor did change any code"));
118125
export const CTX_INLINE_CHAT_LAST_FEEDBACK = new RawContextKey<'unhelpful' | 'helpful' | ''>('inlineChatLastFeedbackKind', '', localize('inlineChatLastFeedbackKind', "The last kind of feedback that was provided"));
119126
export const CTX_INLINE_CHAT_DOCUMENT_CHANGED = new RawContextKey<boolean>('inlineChatDocumentChanged', false, localize('inlineChatDocumentChanged', "Whether the document has changed concurrently"));
@@ -123,6 +130,7 @@ export const CTX_INLINE_CHAT_EDIT_MODE = new RawContextKey<EditMode>('config.inl
123130

124131
export const ACTION_ACCEPT_CHANGES = 'interactive.acceptChanges';
125132
export const ACTION_REGENERATE_RESPONSE = 'inlineChat.regenerate';
133+
export const ACTION_VIEW_IN_CHAT = 'inlineChat.viewInChat';
126134

127135
// --- menus
128136

0 commit comments

Comments
 (0)