Skip to content

Commit 1beeb2e

Browse files
authored
Repopulate slash command in chat input editor (microsoft#187207)
* Repopulate slash command in chat input editor
1 parent 0422c8f commit 1beeb2e

File tree

4 files changed

+44
-1
lines changed

4 files changed

+44
-1
lines changed

src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { IChatWidget, IChatWidgetService } from 'vs/workbench/contrib/chat/brows
2121
import { ChatWidget } from 'vs/workbench/contrib/chat/browser/chatWidget';
2222
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
2323
import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart';
24+
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
2425

2526
const decorationDescription = 'chat';
2627
const slashCommandPlaceholderDecorationType = 'chat-session-detail';
@@ -131,7 +132,36 @@ class InputEditorDecorations extends Disposable {
131132
}
132133
}
133134

134-
ChatWidget.CONTRIBS.push(InputEditorDecorations);
135+
class InputEditorSlashCommandFollowups extends Disposable {
136+
constructor(
137+
private readonly widget: IChatWidget,
138+
@IChatService private readonly chatService: IChatService
139+
) {
140+
super();
141+
this._register(this.chatService.onDidCompleteSlashCommand(({ slashCommand, sessionId }) => this.repopulateSlashCommand(slashCommand, sessionId)));
142+
}
143+
144+
private async repopulateSlashCommand(slashCommand: string, sessionId: string) {
145+
if (this.widget.viewModel?.sessionId !== sessionId) {
146+
return;
147+
}
148+
149+
const slashCommands = await this.widget.getSlashCommands();
150+
151+
if (this.widget.inputEditor.getValue().trim().length !== 0) {
152+
return;
153+
}
154+
155+
if (slashCommands?.find(c => c.command === slashCommand)?.shouldRepopulate) {
156+
const value = `/${slashCommand} `;
157+
this.widget.inputEditor.setValue(value);
158+
this.widget.inputEditor.setPosition({ lineNumber: 1, column: value.length + 1 });
159+
160+
}
161+
}
162+
}
163+
164+
ChatWidget.CONTRIBS.push(InputEditorDecorations, InputEditorSlashCommandFollowups);
135165

136166
class SlashCommandCompletions extends Disposable {
137167
constructor(

src/vs/workbench/contrib/chat/common/chatService.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export interface ISlashCommandProvider {
6767

6868
export interface ISlashCommand {
6969
command: string;
70+
shouldRepopulate?: boolean;
7071
provider?: ISlashCommandProvider;
7172
sortText?: string;
7273
detail?: string;
@@ -176,6 +177,8 @@ export const IChatService = createDecorator<IChatService>('IChatService');
176177
export interface IChatService {
177178
_serviceBrand: undefined;
178179
transferredSessionId: string | undefined;
180+
181+
onDidCompleteSlashCommand: Event<{ slashCommand: string; sessionId: string }>;
179182
registerProvider(provider: IChatProvider): IDisposable;
180183
registerSlashCommandProvider(provider: ISlashCommandProvider): IDisposable;
181184
getProviderInfos(): IChatProviderInfo[];

src/vs/workbench/contrib/chat/common/chatServiceImpl.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ export class ChatService extends Disposable implements IChatService {
135135
private readonly _onDidPerformUserAction = this._register(new Emitter<IChatUserActionEvent>());
136136
public readonly onDidPerformUserAction: Event<IChatUserActionEvent> = this._onDidPerformUserAction.event;
137137

138+
private readonly _onDidCompleteSlashCommand = this._register(new Emitter<{ slashCommand: string; sessionId: string }>());
139+
public readonly onDidCompleteSlashCommand = this._onDidCompleteSlashCommand.event;
140+
138141
constructor(
139142
@IStorageService private readonly storageService: IStorageService,
140143
@ILogService private readonly logService: ILogService,
@@ -472,9 +475,15 @@ export class ChatService extends Disposable implements IChatService {
472475
Promise.resolve(provider.provideFollowups(model.session!, CancellationToken.None)).then(followups => {
473476
model.setFollowups(request, withNullAsUndefined(followups));
474477
model.completeResponse(request);
478+
if (usedSlashCommand?.command) {
479+
this._onDidCompleteSlashCommand.fire({ slashCommand: usedSlashCommand.command, sessionId: model.sessionId });
480+
}
475481
});
476482
} else {
477483
model.completeResponse(request);
484+
if (usedSlashCommand?.command) {
485+
this._onDidCompleteSlashCommand.fire({ slashCommand: usedSlashCommand.command, sessionId: model.sessionId });
486+
}
478487
}
479488
}
480489
});

src/vscode-dts/vscode.proposed.interactive.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ declare module 'vscode' {
128128

129129
export interface InteractiveSessionSlashCommand {
130130
command: string;
131+
shouldRepopulate?: boolean;
131132
kind: CompletionItemKind;
132133
detail?: string;
133134
}

0 commit comments

Comments
 (0)