Add Void: Copy Prompt as menu item to the ExplorerContext window

This commit is contained in:
Steven Wexler 2025-05-09 15:38:32 -06:00
parent eeb6167c12
commit 168b92f6c4
3 changed files with 96 additions and 2 deletions

View file

@ -0,0 +1,89 @@
import { localize2 } from '../../../../nls.js';
import { URI } from '../../../../base/common/uri.js';
import { Action2, registerAction2, MenuId } from '../../../../platform/actions/common/actions.js';
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
import { INotificationService } from '../../../../platform/notification/common/notification.js';
import { IFileService } from '../../../../platform/files/common/files.js';
import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
import { IDirectoryStrService } from '../common/directoryStrService.js';
import { readFile, DEFAULT_FILE_SIZE_LIMIT } from '../common/prompt/prompts.js';
async function filePrompt(fileService: IFileService, uri: URI, clipboardService: IClipboardService): Promise<string> {
const { val } = await readFile(fileService, uri, DEFAULT_FILE_SIZE_LIMIT)
const fileName = uri.fsPath.split('/').pop() ?? ''
if (!val) {
throw new Error('Failed to copy prompt')
}
const prompt = `
${fileName}:
\`\`\`
${val}
\`\`\``.trim()
return prompt
}
/**
* Add a menu item to the explorer context menu that copies a prompt for the selected file or directory.
*
* Example file prompt:
*
* ```
* index.js:
* \`\`\`
* console.log('Hello World!');
* \`\`\`
*
* Example directory prompt:
* ```
* Directory of /path/to/src:
* src/
* index.ts
* src.ts
* latest/
* index.ts
* src.ts
* types.ts
* util.ts
* ```
*/
class FilePromptActionService extends Action2 {
private static readonly VOID_COPY_FILE_PROMPT_ID = 'void.copyfileprompt'
constructor() {
super({
id: FilePromptActionService.VOID_COPY_FILE_PROMPT_ID,
title: localize2('voidCopyPrompt', "Void: Copy Prompt"),
menu: [{
id: MenuId.ExplorerContext,
group: '8_void',
order: 1,
}]
});
}
async run(accessor: ServicesAccessor, uri: URI): Promise<void> {
try {
const fileService = accessor.get(IFileService);
const clipboardService = accessor.get(IClipboardService)
const directoryStrService = accessor.get(IDirectoryStrService)
const stat = await fileService.resolve(uri)
const prompt = stat.isFile
? await filePrompt(fileService, uri, clipboardService)
: await directoryStrService.getDirectoryStrTool(uri)
await clipboardService.writeText(prompt)
} catch (error) {
const notificationService = accessor.get(INotificationService)
FilePromptActionService._onError(notificationService, error)
}
}
private static _onError(notificationService: INotificationService, error: Error) {
const errorMessage = localize2('voidCopyPromptError', 'Failed to copy prompt')
notificationService.error(errorMessage.value)
throw error
}
}
registerAction2(FilePromptActionService)

View file

@ -58,6 +58,9 @@ import './voidOnboardingService.js'
// register misc service
import './miscWokrbenchContrib.js'
// register file service (for explorer context menu)
import './fileService.js'
// ---------- common (unclear if these actually need to be imported, because they're already imported wherever they're used) ----------
// llmMessage

View file

@ -525,7 +525,9 @@ ${details.map((d, i) => `${i + 1}. ${d}`).join('\n\n')}`)
// chat_systemMessage({ chatMode, workspaceFolders: [], openedURIs: [], activeURI: 'pee', persistentTerminalIDs: [], directoryStr: 'lol', }))
// }
const readFile = async (fileService: IFileService, uri: URI, fileSizeLimit: number): Promise<{
export const DEFAULT_FILE_SIZE_LIMIT = 2_000_000
export const readFile = async (fileService: IFileService, uri: URI, fileSizeLimit: number): Promise<{
val: string,
truncated: boolean,
fullFileLen: number,
@ -561,7 +563,7 @@ export const chat_userMessageContent = async (instructions: string, currSelns: S
selnsStrs = await Promise.all(currSelns?.map(async (s) => {
if (s.type === 'File' || s.type === 'CodeSelection') {
const { val } = await readFile(opts.fileService, s.uri, 2_000_000)
const { val } = await readFile(opts.fileService, s.uri, DEFAULT_FILE_SIZE_LIMIT)
const lineNumAdd = s.type === 'CodeSelection' ? lineNumAddition(s.range) : ''
const content = val === null ? 'null' : `${tripleTick[0]}${s.language}\n${val}\n${tripleTick[1]}`
const str = `${s.uri.fsPath}${lineNumAdd}:\n${content}`