Skip to content

Commit eb2f7c1

Browse files
authored
add secondary inline chat menu and render response commands there (microsoft#226621)
fixes microsoft/vscode-copilot#7368 fixes microsoft/vscode-copilot#6650
1 parent c059291 commit eb2f7c1

File tree

10 files changed

+108
-79
lines changed

10 files changed

+108
-79
lines changed

src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
1818
import { CONTEXT_CHAT_RESPONSE_SUPPORT_ISSUE_REPORTING, CONTEXT_IN_CHAT_INPUT, CONTEXT_IN_CHAT_SESSION, CONTEXT_REQUEST, CONTEXT_RESPONSE, CONTEXT_RESPONSE_ERROR, CONTEXT_RESPONSE_FILTERED, CONTEXT_RESPONSE_VOTE, CONTEXT_VOTE_UP_ENABLED } from 'vs/workbench/contrib/chat/common/chatContextKeys';
1919
import { IChatService, ChatAgentVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
2020
import { isRequestVM, isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
21+
import { MENU_INLINE_CHAT_WIDGET_SECONDARY } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
2122
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
2223
import { CellEditType, CellKind, NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon';
2324
import { NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
@@ -33,12 +34,17 @@ export function registerChatTitleActions() {
3334
category: CHAT_CATEGORY,
3435
icon: Codicon.thumbsup,
3536
toggled: CONTEXT_RESPONSE_VOTE.isEqualTo('up'),
36-
menu: {
37+
menu: [{
3738
id: MenuId.ChatMessageTitle,
3839
group: 'navigation',
3940
order: 1,
4041
when: ContextKeyExpr.and(CONTEXT_RESPONSE, CONTEXT_VOTE_UP_ENABLED, CONTEXT_RESPONSE_ERROR.negate())
41-
}
42+
}, {
43+
id: MENU_INLINE_CHAT_WIDGET_SECONDARY,
44+
group: 'navigation',
45+
order: 1,
46+
when: ContextKeyExpr.and(CONTEXT_RESPONSE, CONTEXT_VOTE_UP_ENABLED, CONTEXT_RESPONSE_ERROR.negate())
47+
}]
4248
});
4349
}
4450

@@ -73,12 +79,17 @@ export function registerChatTitleActions() {
7379
category: CHAT_CATEGORY,
7480
icon: Codicon.thumbsdown,
7581
toggled: CONTEXT_RESPONSE_VOTE.isEqualTo('down'),
76-
menu: {
82+
menu: [{
7783
id: MenuId.ChatMessageTitle,
7884
group: 'navigation',
7985
order: 2,
8086
when: ContextKeyExpr.and(CONTEXT_RESPONSE, CONTEXT_RESPONSE_ERROR.negate())
81-
}
87+
}, {
88+
id: MENU_INLINE_CHAT_WIDGET_SECONDARY,
89+
group: 'navigation',
90+
order: 2,
91+
when: ContextKeyExpr.and(CONTEXT_RESPONSE, CONTEXT_RESPONSE_ERROR.negate())
92+
}]
8293
});
8394
}
8495

@@ -112,12 +123,17 @@ export function registerChatTitleActions() {
112123
f1: false,
113124
category: CHAT_CATEGORY,
114125
icon: Codicon.report,
115-
menu: {
126+
menu: [{
116127
id: MenuId.ChatMessageTitle,
117128
group: 'navigation',
118129
order: 3,
119130
when: ContextKeyExpr.and(CONTEXT_CHAT_RESPONSE_SUPPORT_ISSUE_REPORTING, CONTEXT_RESPONSE)
120-
}
131+
}, {
132+
id: MENU_INLINE_CHAT_WIDGET_SECONDARY,
133+
group: 'navigation',
134+
order: 3,
135+
when: ContextKeyExpr.and(CONTEXT_CHAT_RESPONSE_SUPPORT_ISSUE_REPORTING, CONTEXT_RESPONSE)
136+
}]
121137
});
122138
}
123139

src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import { isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
4343
import { IVoiceChatService, VoiceChatInProgress as GlobalVoiceChatInProgress } from 'vs/workbench/contrib/chat/common/voiceChatService';
4444
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
4545
import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
46-
import { CTX_INLINE_CHAT_FOCUSED } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
46+
import { CTX_INLINE_CHAT_FOCUSED, MENU_INLINE_CHAT_WIDGET_SECONDARY } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
4747
import { NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
4848
import { HasSpeechProvider, ISpeechService, KeywordRecognitionStatus, SpeechToTextInProgress, SpeechToTextStatus, TextToSpeechStatus, TextToSpeechInProgress as GlobalTextToSpeechInProgress } from 'vs/workbench/contrib/speech/common/speechService';
4949
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
@@ -877,7 +877,7 @@ export class ReadChatResponseAloud extends Action2 {
877877
title: localize2('workbench.action.chat.readChatResponseAloud', "Read Aloud"),
878878
icon: Codicon.unmute,
879879
precondition: CanVoiceChat,
880-
menu: {
880+
menu: [{
881881
id: MenuId.ChatMessageTitle,
882882
when: ContextKeyExpr.and(
883883
CanVoiceChat,
@@ -886,7 +886,16 @@ export class ReadChatResponseAloud extends Action2 {
886886
CONTEXT_RESPONSE_FILTERED.negate() // and not when response is filtered
887887
),
888888
group: 'navigation'
889-
}
889+
}, {
890+
id: MENU_INLINE_CHAT_WIDGET_SECONDARY,
891+
when: ContextKeyExpr.and(
892+
CanVoiceChat,
893+
CONTEXT_RESPONSE, // only for responses
894+
ScopedChatSynthesisInProgress.negate(), // but not when already in progress
895+
CONTEXT_RESPONSE_FILTERED.negate() // and not when response is filtered
896+
),
897+
group: 'navigation'
898+
}]
890899
});
891900
}
892901

@@ -932,6 +941,12 @@ export class StopReadAloud extends Action2 {
932941
when: ScopedChatSynthesisInProgress,
933942
group: 'navigation',
934943
order: -1
944+
},
945+
{
946+
id: MENU_INLINE_CHAT_WIDGET_SECONDARY,
947+
when: ScopedChatSynthesisInProgress,
948+
group: 'navigation',
949+
order: -1
935950
}
936951
]
937952
});

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,6 @@ registerAction2(InlineChatActions.ViewInChatAction);
107107
registerAction2(InlineChatActions.ToggleDiffForChange);
108108
registerAction2(InlineChatActions.AcceptChanges);
109109

110-
registerAction2(InlineChatActions.ReportIssueAction);
111-
112110
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
113111
workbenchContributionsRegistry.registerWorkbenchContribution(InlineChatNotebookContribution, LifecyclePhase.Restored);
114112

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

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/diffEditor/em
1111
import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/codeEditor/embeddedCodeEditorWidget';
1212
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
1313
import { InlineChatController, InlineChatRunOptions } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
14-
import { ACTION_ACCEPT_CHANGES, CTX_INLINE_CHAT_HAS_AGENT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_EDIT_MODE, EditMode, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, InlineChatResponseType, ACTION_REGENERATE_RESPONSE, MENU_INLINE_CHAT_CONTENT_STATUS, ACTION_VIEW_IN_CHAT, ACTION_TOGGLE_DIFF, CTX_INLINE_CHAT_CHANGE_HAS_DIFF, CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF, MENU_INLINE_CHAT_ZONE, CTX_INLINE_CHAT_SUPPORT_REPORT_ISSUE, ACTION_REPORT_ISSUE } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
14+
import { ACTION_ACCEPT_CHANGES, CTX_INLINE_CHAT_HAS_AGENT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_EDIT_MODE, EditMode, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, InlineChatResponseType, ACTION_REGENERATE_RESPONSE, MENU_INLINE_CHAT_CONTENT_STATUS, ACTION_VIEW_IN_CHAT, ACTION_TOGGLE_DIFF, CTX_INLINE_CHAT_CHANGE_HAS_DIFF, CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF, MENU_INLINE_CHAT_ZONE } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
1515
import { localize, localize2 } from 'vs/nls';
1616
import { Action2, IAction2Options } from 'vs/platform/actions/common/actions';
1717
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
@@ -516,28 +516,3 @@ export class ToggleDiffForChange extends AbstractInlineChatAction {
516516
ctrl.toggleDiff(hunkInfo);
517517
}
518518
}
519-
520-
export class ReportIssueAction extends AbstractInlineChatAction {
521-
constructor() {
522-
super({
523-
id: ACTION_REPORT_ISSUE,
524-
title: localize2('reportIssue', 'Report Issue'),
525-
icon: Codicon.report,
526-
menu: [{
527-
id: MENU_INLINE_CHAT_WIDGET_STATUS,
528-
group: '0_main',
529-
order: 6,
530-
when: ContextKeyExpr.and(
531-
CTX_INLINE_CHAT_VISIBLE,
532-
CTX_INLINE_CHAT_SUPPORT_REPORT_ISSUE,
533-
CTX_INLINE_CHAT_RESPONSE_TYPE.notEqualsTo(InlineChatResponseType.None),
534-
CTX_INLINE_CHAT_REQUEST_IN_PROGRESS.negate()
535-
)
536-
}]
537-
});
538-
}
539-
540-
override runInlineChatCommand(_accessor: ServicesAccessor, ctrl: InlineChatController): void {
541-
ctrl.reportIssue();
542-
}
543-
}

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,14 @@ import { InlineChatContentWidget } from 'vs/workbench/contrib/inlineChat/browser
4242
import { HunkInformation, Session, StashedSession } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession';
4343
import { InlineChatError } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl';
4444
import { EditModeStrategy, HunkAction, IEditObserver, LiveStrategy, PreviewStrategy, ProgressingEditsOptions } from 'vs/workbench/contrib/inlineChat/browser/inlineChatStrategies';
45-
import { CTX_INLINE_CHAT_EDITING, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, CTX_INLINE_CHAT_SUPPORT_REPORT_ISSUE, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_VISIBLE, EditMode, INLINE_CHAT_ID, InlineChatConfigKeys, InlineChatResponseType } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
45+
import { CTX_INLINE_CHAT_EDITING, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_VISIBLE, EditMode, INLINE_CHAT_ID, InlineChatConfigKeys, InlineChatResponseType } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
4646
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/services/notebookEditorService';
4747
import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
4848
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
4949
import { IInlineChatSavingService } from './inlineChatSavingService';
5050
import { IInlineChatSessionService } from './inlineChatSessionService';
5151
import { InlineChatZoneWidget } from './inlineChatZoneWidget';
52+
import { CONTEXT_RESPONSE, CONTEXT_RESPONSE_ERROR } from 'vs/workbench/contrib/chat/common/chatContextKeys';
5253

5354
export const enum State {
5455
CREATE_SESSION = 'CREATE_SESSION',
@@ -113,7 +114,8 @@ export class InlineChatController implements IEditorContribution {
113114
private readonly _ctxResponseType: IContextKey<undefined | InlineChatResponseType>;
114115
private readonly _ctxUserDidEdit: IContextKey<boolean>;
115116
private readonly _ctxRequestInProgress: IContextKey<boolean>;
116-
private readonly _ctxSupportsReportIssue: IContextKey<boolean>;
117+
118+
private readonly _ctxResponse: IContextKey<boolean>;
117119

118120
private readonly _messages = this._store.add(new Emitter<Message>());
119121
protected readonly _onDidEnterState = this._store.add(new Emitter<State>());
@@ -154,7 +156,9 @@ export class InlineChatController implements IEditorContribution {
154156
this._ctxUserDidEdit = CTX_INLINE_CHAT_USER_DID_EDIT.bindTo(contextKeyService);
155157
this._ctxResponseType = CTX_INLINE_CHAT_RESPONSE_TYPE.bindTo(contextKeyService);
156158
this._ctxRequestInProgress = CTX_INLINE_CHAT_REQUEST_IN_PROGRESS.bindTo(contextKeyService);
157-
this._ctxSupportsReportIssue = CTX_INLINE_CHAT_SUPPORT_REPORT_ISSUE.bindTo(contextKeyService);
159+
160+
this._ctxResponse = CONTEXT_RESPONSE.bindTo(contextKeyService);
161+
CONTEXT_RESPONSE_ERROR.bindTo(contextKeyService);
158162

159163
this._ui = new Lazy(() => {
160164

@@ -487,6 +491,8 @@ export class InlineChatController implements IEditorContribution {
487491
const diff = await this._editorWorkerService.computeDiff(this._session.textModel0.uri, this._session.textModelN.uri, { computeMoves: false, maxComputationTimeMs: Number.MAX_SAFE_INTEGER, ignoreTrimWhitespace: false }, 'advanced');
488492
this._session.wholeRange.fixup(diff?.changes ?? []);
489493
await this._session.hunkData.recompute(editState, diff);
494+
495+
this._updateCtxResponseType();
490496
}
491497
options.position = await this._strategy.renderChanges();
492498

@@ -575,8 +581,6 @@ export class InlineChatController implements IEditorContribution {
575581
assertType(request);
576582
assertType(request.response);
577583

578-
this._ctxSupportsReportIssue.set(request.response.agent?.metadata.supportIssueReporting ?? false);
579-
580584
this._showWidget(this._session.headless, false);
581585
this._ui.value.zone.widget.selectAll(false);
582586
this._ui.value.zone.widget.updateInfo('');
@@ -928,6 +932,7 @@ export class InlineChatController implements IEditorContribution {
928932
}
929933
}
930934
this._ctxResponseType.set(responseType);
935+
this._ctxResponse.set(responseType !== InlineChatResponseType.None);
931936
}
932937

933938
private _createChatTextEditGroupState(): IChatTextEditGroupState {

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

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import { IModelDecorationsChangeAccessor, IModelDeltaDecoration, IValidEditOpera
2121
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
2222
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
2323
import { InlineDecoration, InlineDecorationType } from 'vs/editor/common/viewModel';
24-
import { localize } from 'vs/nls';
2524
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
2625
import { Progress } from 'vs/platform/progress/common/progress';
2726
import { SaveReason } from 'vs/workbench/common/editor';
@@ -592,9 +591,6 @@ export class LiveStrategy extends EditModeStrategy {
592591
if (widgetData) {
593592
this._zone.updatePositionAndHeight(widgetData.position);
594593

595-
const remainingHunks = this._session.hunkData.pending;
596-
this._updateSummaryMessage(remainingHunks, this._session.hunkData.size);
597-
598594

599595
const mode = this._configService.getValue<'on' | 'off' | 'auto'>(InlineChatConfigKeys.AccessibleDiffView);
600596
if (mode === 'on' || mode === 'auto' && this._accessibilityService.isScreenReaderOptimized()) {
@@ -625,30 +621,6 @@ export class LiveStrategy extends EditModeStrategy {
625621
return renderHunks()?.position;
626622
}
627623

628-
private _updateSummaryMessage(remaining: number, total: number) {
629-
630-
const needsReview = this._configService.getValue<boolean>(InlineChatConfigKeys.AcceptedOrDiscardBeforeSave);
631-
let message: string;
632-
if (total === 0) {
633-
message = localize('change.0', "Nothing changed.");
634-
} else if (remaining === 1) {
635-
message = needsReview
636-
? localize('review.1', "$(info) Accept or Discard change")
637-
: localize('change.1', "1 change");
638-
} else {
639-
message = needsReview
640-
? localize('review.N', "$(info) Accept or Discard {0} changes", remaining)
641-
: localize('change.N', "{0} changes", total);
642-
}
643-
644-
let title: string | undefined;
645-
if (needsReview) {
646-
title = localize('review', "Review (accept or discard) all changes before continuing");
647-
}
648-
649-
this._zone.widget.updateStatus(message, { title });
650-
}
651-
652624
hasFocus(): boolean {
653625
return this._zone.widget.hasFocus();
654626
}

0 commit comments

Comments
 (0)