mirror of
https://github.com/voideditor/void
synced 2026-05-23 09:28:23 +00:00
file and folder copy uniform
This commit is contained in:
parent
08274637e1
commit
7066b4285b
2 changed files with 93 additions and 81 deletions
|
|
@ -6,47 +6,11 @@ import { INotificationService } from '../../../../platform/notification/common/n
|
|||
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';
|
||||
import { messageOfSelection } from '../common/prompt/prompts.js';
|
||||
import { IVoidModelService } from '../common/voidModelService.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'
|
||||
|
||||
|
|
@ -67,22 +31,48 @@ class FilePromptActionService extends Action2 {
|
|||
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)
|
||||
const voidModelService = accessor.get(IVoidModelService)
|
||||
|
||||
const stat = await fileService.stat(uri)
|
||||
|
||||
const folderOpts = {
|
||||
maxChildren: 1000,
|
||||
maxCharsPerFile: 2_000_000,
|
||||
} as const
|
||||
|
||||
let m: string = 'No contents detected'
|
||||
if (stat.isFile) {
|
||||
m = await messageOfSelection({
|
||||
type: 'File',
|
||||
uri,
|
||||
language: (await voidModelService.getModelSafe(uri)).model?.getLanguageId() || '',
|
||||
state: { wasAddedAsCurrentFile: false, },
|
||||
}, {
|
||||
folderOpts,
|
||||
directoryStrService,
|
||||
fileService,
|
||||
})
|
||||
}
|
||||
|
||||
if (stat.isDirectory) {
|
||||
m = await messageOfSelection({
|
||||
type: 'Folder',
|
||||
uri,
|
||||
}, {
|
||||
folderOpts,
|
||||
fileService,
|
||||
directoryStrService,
|
||||
})
|
||||
}
|
||||
|
||||
await clipboardService.writeText(m)
|
||||
|
||||
} catch (error) {
|
||||
const notificationService = accessor.get(INotificationService)
|
||||
FilePromptActionService._onError(notificationService, error)
|
||||
notificationService.error(error + '')
|
||||
}
|
||||
}
|
||||
|
||||
private static _onError(notificationService: INotificationService, error: Error) {
|
||||
const errorMessage = localize2('voidCopyPromptError', 'Failed to copy prompt')
|
||||
notificationService.error(errorMessage.value)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
registerAction2(FilePromptActionService)
|
||||
|
|
|
|||
|
|
@ -551,46 +551,68 @@ export const readFile = async (fileService: IFileService, uri: URI, fileSizeLimi
|
|||
|
||||
|
||||
|
||||
export const messageOfSelection = async (
|
||||
s: StagingSelectionItem,
|
||||
opts: {
|
||||
directoryStrService: IDirectoryStrService,
|
||||
fileService: IFileService,
|
||||
folderOpts: {
|
||||
maxChildren: number,
|
||||
maxCharsPerFile: number,
|
||||
}
|
||||
}
|
||||
) => {
|
||||
const lineNumAddition = (range: [number, number]) => ` (lines ${range[0]}:${range[1]})`
|
||||
|
||||
if (s.type === 'File' || s.type === 'CodeSelection') {
|
||||
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}`
|
||||
return str
|
||||
}
|
||||
else if (s.type === 'Folder') {
|
||||
const dirStr: string = await opts.directoryStrService.getDirectoryStrTool(s.uri)
|
||||
const folderStructure = `${s.uri.fsPath} folder structure:${tripleTick[0]}\n${dirStr}\n${tripleTick[1]}`
|
||||
|
||||
const uris = await opts.directoryStrService.getAllURIsInDirectory(s.uri, { maxResults: opts.folderOpts.maxChildren })
|
||||
const strOfFiles = await Promise.all(uris.map(async uri => {
|
||||
const { val, truncated } = await readFile(opts.fileService, uri, opts.folderOpts.maxCharsPerFile)
|
||||
const truncationStr = truncated ? `\n... file truncated ...` : ''
|
||||
const content = val === null ? 'null' : `${tripleTick[0]}\n${val}${truncationStr}\n${tripleTick[1]}`
|
||||
const str = `${uri.fsPath}:\n${content}`
|
||||
return str
|
||||
}))
|
||||
const contentStr = [folderStructure, ...strOfFiles].join('\n\n')
|
||||
return contentStr
|
||||
}
|
||||
else
|
||||
return ''
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const chat_userMessageContent = async (instructions: string, currSelns: StagingSelectionItem[] | null,
|
||||
opts: { directoryStrService: IDirectoryStrService, fileService: IFileService }
|
||||
export const chat_userMessageContent = async (
|
||||
instructions: string,
|
||||
currSelns: StagingSelectionItem[] | null,
|
||||
opts: {
|
||||
directoryStrService: IDirectoryStrService,
|
||||
fileService: IFileService
|
||||
},
|
||||
) => {
|
||||
|
||||
const lineNumAddition = (range: [number, number]) => ` (lines ${range[0]}:${range[1]})`
|
||||
let selnsStrs: string[] = []
|
||||
selnsStrs = await Promise.all(currSelns?.map(async (s) => {
|
||||
const selnsStrs = await Promise.all((currSelns ?? []).map(async (s) =>
|
||||
messageOfSelection(s, {
|
||||
...opts,
|
||||
folderOpts: { maxChildren: 100, maxCharsPerFile: 100_000, }
|
||||
})
|
||||
))
|
||||
|
||||
if (s.type === 'File' || s.type === 'CodeSelection') {
|
||||
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}`
|
||||
return str
|
||||
}
|
||||
else if (s.type === 'Folder') {
|
||||
const dirStr: string = await opts.directoryStrService.getDirectoryStrTool(s.uri)
|
||||
const folderStructure = `${s.uri.fsPath} folder structure:${tripleTick[0]}\n${dirStr}\n${tripleTick[1]}`
|
||||
|
||||
const uris = await opts.directoryStrService.getAllURIsInDirectory(s.uri, { maxResults: 100 })
|
||||
const strOfFiles = await Promise.all(uris.map(async uri => {
|
||||
const { val, truncated } = await readFile(opts.fileService, uri, 100_000)
|
||||
const truncationStr = truncated ? `\n... file truncated ...` : ''
|
||||
const content = val === null ? 'null' : `${tripleTick[0]}\n${val}${truncationStr}\n${tripleTick[1]}`
|
||||
const str = `${uri.fsPath}:\n${content}`
|
||||
return str
|
||||
}))
|
||||
const contentStr = [folderStructure, ...strOfFiles].join('\n\n')
|
||||
return contentStr
|
||||
}
|
||||
else
|
||||
return ''
|
||||
}) ?? [])
|
||||
|
||||
const selnsStr = selnsStrs.join('\n') ?? ''
|
||||
let str = ''
|
||||
str += `${instructions}`
|
||||
|
||||
const selnsStr = selnsStrs.join('\n\n') ?? ''
|
||||
if (selnsStr) str += `\n---\nSELECTIONS\n${selnsStr}`
|
||||
return str;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue