From 555257b68e97d2d4c785a445a061dfdca7fb6f72 Mon Sep 17 00:00:00 2001 From: Oleg Solomko Date: Thu, 27 Feb 2025 10:53:41 -0800 Subject: [PATCH] refactor the ask-to-select-prompt dialog --- .../chatAttachPromptAction.ts | 2 +- .../dialogs/askToSelectPrompt.ts | 67 +++++++++++-------- .../browser/actions/chatContextActions.ts | 2 +- .../contributions/usePromptCommand.ts | 3 + 4 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatAttachPromptAction/chatAttachPromptAction.ts b/src/vs/workbench/contrib/chat/browser/actions/chatAttachPromptAction/chatAttachPromptAction.ts index 2c6779d059f..40535af08eb 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatAttachPromptAction/chatAttachPromptAction.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatAttachPromptAction/chatAttachPromptAction.ts @@ -24,7 +24,7 @@ export const ATTACH_PROMPT_ACTION_ID = 'workbench.action.chat.attach.prompt'; * Options for the {@link AttachPromptAction} action. */ export interface IChatAttachPromptActionOptions extends Pick< - ISelectPromptOptions, 'resource' | 'widget' + ISelectPromptOptions, 'resource' | 'widget' | 'viewsService' > { } /** diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatAttachPromptAction/dialogs/askToSelectPrompt.ts b/src/vs/workbench/contrib/chat/browser/actions/chatAttachPromptAction/dialogs/askToSelectPrompt.ts index 7c97b754a9a..4916c2e2c36 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatAttachPromptAction/dialogs/askToSelectPrompt.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatAttachPromptAction/dialogs/askToSelectPrompt.ts @@ -102,7 +102,7 @@ export const askToSelectPrompt = async ( } // otherwise show the prompt file selection dialog - const { viewsService, openerService } = options; + const { openerService } = options; const quickPick = quickInputService.createQuickPick>(); quickPick.activeItems = activeItem ? [activeItem] : []; @@ -126,36 +126,16 @@ export const askToSelectPrompt = async ( }); disposables.add(quickPick.onDidAccept(async (event) => { + const { selectedItems } = quickPick; const { alt, ctrlCmd } = quickPick.keyMods; - // TODO: @lego - refactor? - // if `cmd`/`ctrl` key was pressed, open the selected prompt file(s) + // if `super` key was pressed, open the selected prompt file(s) if (ctrlCmd) { - for (const selectedItem of quickPick.selectedItems) { - await openerService.open(selectedItem.value); - } - - // if user submitted their selection, close the dialog - if (!event.inBackground) { - disposables.dispose(); - } - - return; + return await openFiles(selectedItems, openerService); } // otherwise attach the selected prompt to a chat input - lastActiveWidget = await getChatWidgetObject( - options, - alt, - viewsService, - ); - - for (const selectedItem of quickPick.selectedItems) { - lastActiveWidget - .attachmentModel - .promptInstructions - .add(selectedItem.value); - } + lastActiveWidget = await attachFiles(selectedItems, options, alt); // if user submitted their selection, close the dialog if (!event.inBackground) { @@ -216,18 +196,51 @@ const createPlaceholderText = (options: ISelectPromptOptions): string => { return text; }; +/** + * Opens provided files in the editor. + */ +const openFiles = async ( + files: readonly WithUriValue[], + openerService: IOpenerService, +) => { + for (const file of files) { + await openerService.open(file.value); + } +}; + +/** + * Attaches provided files to a chat input. + */ +const attachFiles = async ( + files: readonly WithUriValue[], + options: ISelectPromptOptions, + altOption: boolean, +): Promise => { + const widget = await getChatWidgetObject(options, altOption); + + for (const file of files) { + widget + .attachmentModel + .promptInstructions + .add(file.value); + } + + return widget; +}; + /** * Gets a chat widget based on the provided {@link IChatAttachPromptActionOptions.widget widget} * reference. If no widget reference is provided, the function will reveal a `chat panel` by default * (either a last focused, or a new one), but if the {@link altOption} is set to `true`, a `chat edits` * panel will be revealed instead (likewise either a last focused, or a new one). + * + * @throws if failed to reveal a chat widget. */ const getChatWidgetObject = async ( options: IChatAttachPromptActionOptions, altOption: boolean, - viewsService: IViewsService, ): Promise => { - const { widget } = options; + const { widget, viewsService } = options; // if no widget reference is present, the command was triggered from outside of // an active chat input, so we reveal a chat widget window based on the `alt` diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts index 3aaf9fc132b..11a2c31cfdb 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts @@ -615,7 +615,7 @@ export class AttachContextAction extends Action2 { toAttach.push(convertBufferToScreenshotVariable(blob)); } } else if (isPromptInstructionsQuickPickItem(pick)) { - const options: IChatAttachPromptActionOptions = { widget }; + const options: IChatAttachPromptActionOptions = { widget, viewsService }; await commandService.executeCommand(ATTACH_PROMPT_ACTION_ID, options); } else { // Anything else is an attachment diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/usePromptCommand.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/usePromptCommand.ts index 20a075f0cd0..0c486a00d8d 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/usePromptCommand.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/usePromptCommand.ts @@ -8,6 +8,7 @@ import { URI } from '../../../../../../base/common/uri.js'; import { CHAT_CATEGORY } from '../../actions/chatActions.js'; import { IChatWidget, IChatWidgetService } from '../../chat.js'; import { KeyMod, KeyCode } from '../../../../../../base/common/keyCodes.js'; +import { IViewsService } from '../../../../../services/views/common/viewsService.js'; import { isPromptFile } from '../../../../../../platform/prompts/common/constants.js'; import { IEditorService } from '../../../../../services/editor/common/editorService.js'; import { ICommandService } from '../../../../../../platform/commands/common/commands.js'; @@ -51,10 +52,12 @@ const command = async ( accessor: ServicesAccessor, ): Promise => { const commandService = accessor.get(ICommandService); + const viewsService = accessor.get(IViewsService); const options: IChatAttachPromptActionOptions = { resource: getActivePromptUri(accessor), widget: getFocusedChatWidget(accessor), + viewsService, }; await commandService.executeCommand(ATTACH_PROMPT_ACTION_ID, options);