@narumitw/pi-files 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +102 -2
- package/dist/chunks/chunk-3GQ7VS22.ts +273 -0
- package/dist/chunks/chunk-3GQ7VS22.ts.map +7 -0
- package/dist/chunks/chunk-AXW73HDJ.ts +31 -0
- package/dist/chunks/chunk-AXW73HDJ.ts.map +7 -0
- package/dist/chunks/chunk-F5QFC255.ts +101 -0
- package/dist/chunks/chunk-F5QFC255.ts.map +7 -0
- package/dist/chunks/chunk-NFNGJETD.ts +77 -0
- package/dist/chunks/chunk-NFNGJETD.ts.map +7 -0
- package/dist/chunks/chunk-OPGTWNJI.ts +258 -0
- package/dist/chunks/chunk-OPGTWNJI.ts.map +7 -0
- package/dist/chunks/chunk-WOTDNRTG.ts +242 -0
- package/dist/chunks/chunk-WOTDNRTG.ts.map +7 -0
- package/dist/chunks/file-context-explorer-WR6GQZHF.ts +1793 -0
- package/dist/chunks/file-context-explorer-WR6GQZHF.ts.map +7 -0
- package/dist/chunks/file-context-menu-VPLHUUQ6.ts +302 -0
- package/dist/chunks/file-context-menu-VPLHUUQ6.ts.map +7 -0
- package/dist/chunks/files-menu-MES4MQ4F.ts +119 -0
- package/dist/chunks/files-menu-MES4MQ4F.ts.map +7 -0
- package/dist/chunks/files-settings-NYXQU2HV.ts +295 -0
- package/dist/chunks/files-settings-NYXQU2HV.ts.map +7 -0
- package/dist/chunks/menu-P6IBMROH.ts +876 -0
- package/dist/chunks/menu-P6IBMROH.ts.map +7 -0
- package/dist/index.ts +1789 -0
- package/dist/index.ts.map +7 -0
- package/docs/edit-scope-reference.md +142 -0
- package/docs/file-context-reference.md +91 -0
- package/docs/migration.md +105 -0
- package/docs/verification.md +99 -0
- package/package.json +58 -4
- package/src/content-search-session.ts +204 -0
- package/src/content-search-ui.ts +159 -0
- package/src/content-search.ts +170 -0
- package/src/context-service.ts +515 -0
- package/src/external-editor.ts +143 -0
- package/src/file-browser-ui.ts +128 -0
- package/src/file-browser.ts +76 -0
- package/src/file-context-explorer.ts +992 -0
- package/src/file-context-menu.ts +360 -0
- package/src/file-context-preview-ui.ts +354 -0
- package/src/file-context-settings.ts +301 -0
- package/src/file-context.ts +321 -0
- package/src/file-search.ts +246 -0
- package/src/files-menu.ts +125 -0
- package/src/files-settings.ts +314 -0
- package/src/files-widget.ts +65 -0
- package/src/files.ts +148 -0
- package/src/git-context.ts +485 -0
- package/src/index.ts +1 -0
- package/src/scope/contracts.ts +243 -0
- package/src/scope/display.ts +27 -0
- package/src/scope/edit-scope.ts +435 -0
- package/src/scope/files.ts +118 -0
- package/src/scope/input.ts +207 -0
- package/src/scope/menu.ts +277 -0
- package/src/scope/paths.ts +142 -0
- package/src/scope/picker-keys.ts +154 -0
- package/src/scope/picker.ts +484 -0
- package/src/scope/policy.ts +55 -0
- package/src/scope/settings.ts +138 -0
- package/src/scope/state.ts +91 -0
- package/src/scope/ui.ts +106 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/file-context-explorer.ts", "../../src/content-search-session.ts", "../../src/content-search.ts", "../../src/content-search-ui.ts", "../../src/file-browser.ts", "../../src/file-browser-ui.ts", "../../src/file-context-preview-ui.ts", "../../src/file-search.ts"],
|
|
4
|
+
"sourcesContent": ["import type { KeybindingsManager, Theme } from \"@earendil-works/pi-coding-agent\";\nimport {\n type Component,\n type Focusable,\n Input,\n Key,\n matchesKey,\n type TUI,\n truncateToWidth,\n visibleWidth,\n} from \"@earendil-works/pi-tui\";\nimport type { ContentSearchMatch } from \"./content-search.js\";\nimport { ContentSearchSession } from \"./content-search-session.js\";\nimport {\n safeTerminalText as escapeTerminalControls,\n type ProjectBrowserItem,\n ProjectFileBrowser,\n parentProjectDirectory,\n} from \"./file-browser.js\";\nimport { renderFileBrowser } from \"./file-browser-ui.js\";\nimport {\n createFileQuoteSnapshot,\n createPreviewQuote,\n type FileQuote,\n type LoadedProjectTextFile,\n} from \"./file-context.js\";\nimport {\n fitRows,\n renderFileHistory,\n renderFilePreview,\n renderFilePreviewHelp,\n type SelectedContextState,\n} from \"./file-context-preview-ui.js\";\nimport { ProjectFileSearch } from \"./file-search.js\";\nimport type { GitBlameInfo, GitContext, GitFileContext, GitHistoryEntry, GitRevisionFile } from \"./git-context.js\";\n\nconst RESERVED_APP_ROWS = 3;\nconst EXPLORER_CHROME_ROWS = 4;\nconst DIFF_CHROME_ROWS = 3;\n\nexport type FileQuoteExplorerResult =\n | { kind: \"quote\"; quote: FileQuote }\n | { kind: \"reference\"; path: string }\n | { kind: \"back\" }\n | { kind: \"close\" };\n\ninterface FileQuoteExplorerOptions {\n tui: TUI;\n theme: Theme;\n keybindings: KeybindingsManager;\n files: readonly string[];\n cwd?: string;\n loadFile: (path: string, signal?: AbortSignal) => Promise<LoadedProjectTextFile>;\n editFile?: (path: string, signal?: AbortSignal) => Promise<void>;\n gitContext?: GitContext;\n rootNavigation?: boolean;\n getSelectedContextState?: () => SelectedContextState;\n validateQuote?: (quote: FileQuote) => void;\n onAddAndContinue?: (quote: FileQuote) => void;\n done: (result: FileQuoteExplorerResult | undefined) => void;\n}\n\n/**\n * Keeps the explorer's coupled mode transitions and request generations in one controller so every\n * cancellation path invalidates the same state instead of coordinating lifecycle across components.\n */\nexport class FileQuoteExplorer implements Component, Focusable {\n private readonly search = new Input();\n private readonly contentSearch: ContentSearchSession;\n private readonly revisionInput = new Input();\n private readonly fileSearch: ProjectFileSearch;\n private readonly fileBrowser: ProjectFileBrowser;\n private fileItems: ProjectBrowserItem[];\n private currentDirectory = \"\";\n private readonly directoryPositions = new Map<string, { index: number; offset: number }>();\n private selectedFileIndex = 0;\n private fileScrollOffset = 0;\n private mode: \"files\" | \"contents\" | \"preview\" | \"preview-help\" | \"history\" | \"revision\" | \"diff\" = \"files\";\n private previewReturnMode: \"files\" | \"contents\" = \"files\";\n private activeContentMatch: ContentSearchMatch | undefined;\n private loadedFile: LoadedProjectTextFile | undefined;\n private loadedGit: GitFileContext | undefined;\n private previewCursor = 0;\n private previewAnchor: number | undefined;\n private previewScrollOffset = 0;\n private hunkIndex = -1;\n private blame: GitBlameInfo | undefined;\n private history: GitHistoryEntry[] = [];\n private historyIndex = 0;\n private loadedRevision: GitRevisionFile | undefined;\n private diffHunkIndex = 0;\n private diffScrollOffset = 0;\n private detailRequest = 0;\n private detailController: AbortController | undefined;\n private openRequest = 0;\n private openController: AbortController | undefined;\n private editRequest = 0;\n private editController: AbortController | undefined;\n private loading = false;\n private error: string | undefined;\n private finished = false;\n private disposed = false;\n private isFocused = false;\n\n constructor(private readonly options: FileQuoteExplorerOptions) {\n this.fileSearch = new ProjectFileSearch(options.files);\n this.fileBrowser = new ProjectFileBrowser(options.files);\n this.fileItems = this.fileBrowser.list(\"\");\n this.contentSearch = new ContentSearchSession({\n tui: options.tui,\n theme: options.theme,\n keybindings: options.keybindings,\n files: options.files,\n cwd: options.cwd,\n loadFile: options.loadFile,\n onPreview: (match) => {\n void this.openFile(match.path, {\n returnMode: \"contents\",\n cursorIndex: match.lineNumber - 1,\n match,\n });\n },\n onReference: (path) => this.finish({ kind: \"reference\", path }),\n onSwitchFiles: () => this.showFileSearch(),\n onCancel: () => this.finish(this.rootExit(\"back\")),\n });\n }\n\n get capturesViewportInput(): boolean {\n // Revision entry and static help do not own list or preview navigation.\n return this.mode !== \"revision\" && this.mode !== \"preview-help\";\n }\n\n get focused(): boolean {\n return this.isFocused;\n }\n\n set focused(value: boolean) {\n this.isFocused = value;\n this.search.focused = value && this.mode === \"files\";\n this.contentSearch.focused = value && this.mode === \"contents\";\n this.revisionInput.focused = value && this.mode === \"revision\";\n }\n\n render(width: number): string[] {\n const safeWidth = Number.isFinite(width) ? Math.max(0, Math.floor(width)) : 0;\n if (safeWidth === 0) return [];\n if (this.mode === \"files\") return this.renderFileList(safeWidth);\n if (this.mode === \"contents\") return this.renderContentSearch(safeWidth);\n if (this.mode === \"history\") return this.renderHistory(safeWidth);\n if (this.mode === \"revision\") return this.renderRevisionInput(safeWidth);\n if (this.mode === \"diff\") return this.renderDiff(safeWidth);\n if (this.mode === \"preview-help\") return this.renderPreviewHelp(safeWidth);\n return this.renderPreview(safeWidth);\n }\n\n handleInput(data: string): void {\n if (this.finished || this.disposed) return;\n if (matchesKey(data, Key.ctrl(\"c\"))) {\n this.finish(this.rootExit(\"close\"));\n return;\n }\n if (this.mode === \"files\") this.handleFileInput(data);\n else if (this.mode === \"contents\") this.handleContentInput(data);\n else if (this.mode === \"history\") this.handleHistoryInput(data);\n else if (this.mode === \"revision\") this.handleRevisionInput(data);\n else if (this.mode === \"diff\") this.handleDiffInput(data);\n else if (this.mode === \"preview-help\") this.handlePreviewHelpInput(data);\n else this.handlePreviewInput(data);\n if (!this.finished) this.options.tui.requestRender();\n }\n\n invalidate(): void {\n this.search.invalidate();\n this.contentSearch.invalidate();\n this.revisionInput.invalidate();\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.contentSearch.dispose();\n this.cancelOpenRequest();\n this.cancelDetailRequest();\n this.cancelEditRequest();\n if (!this.finished) {\n this.finished = true;\n this.options.done(undefined);\n }\n }\n\n private renderFileList(width: number): string[] {\n const availableRows = Math.max(1, this.options.tui.terminal.rows - RESERVED_APP_ROWS);\n const listHeight = Math.max(1, availableRows - EXPLORER_CHROME_ROWS);\n this.keepFileVisible(listHeight);\n const project = this.options.gitContext?.project;\n const repositoryLabel = project\n ? ` \u00B7 ${escapeTerminalControls(project.branch)}@${project.head.slice(0, 12)}${project.dirty ? \" \u00B7 dirty\" : \"\"}`\n : \"\";\n const queryLabel = this.options.theme.fg(\"muted\", \"Search: \");\n const queryWidth = Math.max(1, width - visibleWidth(queryLabel));\n const searchLine = `${queryLabel}${this.search.render(queryWidth)[0] ?? \"\"}`;\n return fitRows(\n renderFileBrowser({\n theme: this.options.theme,\n keybindings: this.options.keybindings,\n width,\n height: listHeight,\n items: this.fileItems,\n selectedIndex: this.selectedFileIndex,\n scrollOffset: this.fileScrollOffset,\n currentDirectory: this.currentDirectory,\n searchLine,\n searchActive: this.isFileSearchActive(),\n repositoryLabel,\n statuses: this.options.gitContext?.statuses,\n loading: this.loading,\n error: this.error,\n }),\n availableRows,\n );\n }\n\n private renderContentSearch(width: number): string[] {\n const availableRows = Math.max(1, this.options.tui.terminal.rows - RESERVED_APP_ROWS);\n return this.contentSearch.render(width, availableRows, this.loading, this.error);\n }\n\n private renderPreview(width: number): string[] {\n const availableRows = Math.max(1, this.options.tui.terminal.rows - RESERVED_APP_ROWS);\n if (!this.loadedFile) return [this.options.theme.fg(\"warning\", \"Loading preview\u2026\")];\n return renderFilePreview({\n theme: this.options.theme,\n keybindings: this.options.keybindings,\n width,\n availableRows,\n file: this.loadedFile,\n fileGit: this.loadedGit,\n project: this.options.gitContext?.project,\n revision: this.loadedRevision,\n contentMatch: this.activeContentMatch,\n blame: this.blame,\n cursor: this.previewCursor,\n anchor: this.previewAnchor,\n scrollOffset: this.previewScrollOffset,\n error: this.error,\n selectedContext: this.options.getSelectedContextState?.(),\n canContinue: this.options.onAddAndContinue !== undefined,\n canEdit: this.options.editFile !== undefined && this.loadedRevision === undefined,\n });\n }\n\n private renderPreviewHelp(width: number): string[] {\n const availableRows = Math.max(1, this.options.tui.terminal.rows - RESERVED_APP_ROWS);\n return renderFilePreviewHelp(\n this.options.theme,\n this.options.keybindings,\n width,\n availableRows,\n this.options.editFile !== undefined && this.loadedRevision === undefined,\n );\n }\n\n private renderRevisionInput(width: number): string[] {\n const availableRows = Math.max(1, this.options.tui.terminal.rows - RESERVED_APP_ROWS);\n const title = this.options.theme.fg(\n \"accent\",\n this.options.theme.bold(`Open Git revision \u00B7 ${escapeTerminalControls(this.loadedFile?.path ?? \"\")}`),\n );\n const label = this.options.theme.fg(\"muted\", \"Revision: \");\n const inputWidth = Math.max(1, width - visibleWidth(label));\n const input = `${label}${this.revisionInput.render(inputWidth)[0] ?? \"\"}`;\n const state = this.error\n ? this.options.theme.fg(\"error\", escapeTerminalControls(this.error))\n : this.loading\n ? this.options.theme.fg(\"warning\", \"Loading revision\u2026\")\n : this.options.theme.fg(\"muted\", \"Enter open commit/branch/tag \u00B7 Esc preview\");\n return fitRows(\n [truncateToWidth(title, width, \"\"), truncateToWidth(input, width, \"\"), truncateToWidth(state, width, \"\")],\n availableRows,\n );\n }\n\n private renderDiff(width: number): string[] {\n const availableRows = Math.max(1, this.options.tui.terminal.rows - RESERVED_APP_ROWS);\n const contentHeight = Math.max(1, availableRows - DIFF_CHROME_ROWS);\n const hunk = this.loadedGit?.hunks[this.diffHunkIndex];\n const path = escapeTerminalControls(this.loadedFile?.path ?? \"\");\n const title = this.options.theme.fg(\"accent\", this.options.theme.bold(`Git diff \u00B7 ${path} \u00B7 HEAD \u2192 worktree`));\n const hunkLines = hunk?.lines ?? [\"No changed hunks\"];\n const maxScroll = Math.max(0, hunkLines.length - contentHeight);\n this.diffScrollOffset = Math.min(this.diffScrollOffset, maxScroll);\n const lines = hunkLines\n .slice(this.diffScrollOffset, this.diffScrollOffset + contentHeight)\n .map((line) =>\n truncateToWidth(\n line.startsWith(\"+\")\n ? this.options.theme.fg(\"success\", escapeTerminalControls(line))\n : line.startsWith(\"-\")\n ? this.options.theme.fg(\"error\", escapeTerminalControls(line))\n : escapeTerminalControls(line),\n width,\n \"\",\n ),\n );\n const text = hunk?.lines.join(\"\\n\") ?? \"\";\n const tokens = Math.max(1, Math.ceil(Buffer.byteLength(text, \"utf8\") / 4));\n const footer = this.error\n ? this.options.theme.fg(\"error\", escapeTerminalControls(this.error))\n : `~${tokens} tokens \u00B7 Enter attach diff \u00B7 Hunk ${hunk ? this.diffHunkIndex + 1 : 0}/${this.loadedGit?.hunks.length ?? 0} \u00B7 rows ${hunkLines.length === 0 ? 0 : this.diffScrollOffset + 1}-${Math.min(hunkLines.length, this.diffScrollOffset + contentHeight)}/${hunkLines.length} \u00B7 \u2191\u2193 scroll \u00B7 [] navigate \u00B7 Esc preview`;\n return fitRows(\n [truncateToWidth(title, width, \"\"), ...lines, truncateToWidth(this.options.theme.fg(\"muted\", footer), width, \"\")],\n availableRows,\n );\n }\n\n private renderHistory(width: number): string[] {\n return renderFileHistory({\n width,\n availableRows: Math.max(1, this.options.tui.terminal.rows - RESERVED_APP_ROWS),\n theme: this.options.theme,\n path: this.loadedFile?.path ?? \"\",\n history: this.history,\n index: this.historyIndex,\n error: this.error,\n });\n }\n\n private handleFileInput(data: string): void {\n if (this.options.keybindings.matches(data, \"tui.select.cancel\")) {\n this.cancelFileList();\n return;\n }\n if (matchesKey(data, Key.ctrl(\"f\"))) {\n this.showContentSearch();\n return;\n }\n if (matchesKey(data, Key.escape)) {\n this.cancelFileList();\n return;\n }\n if (this.loading) return;\n if (this.options.keybindings.matches(data, \"tui.select.up\")) {\n this.selectedFileIndex = Math.max(0, this.selectedFileIndex - 1);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.down\")) {\n this.selectedFileIndex = Math.min(Math.max(0, this.fileItems.length - 1), this.selectedFileIndex + 1);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.pageUp\")) {\n this.selectedFileIndex = Math.max(0, this.selectedFileIndex - 10);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.pageDown\")) {\n this.selectedFileIndex = Math.min(Math.max(0, this.fileItems.length - 1), this.selectedFileIndex + 10);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.confirm\")) {\n this.openSelectedFileItem();\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.input.tab\")) {\n const item = this.fileItems[this.selectedFileIndex];\n if (item?.kind === \"file\") this.finish({ kind: \"reference\", path: item.path });\n return;\n }\n if (\n !this.isFileSearchActive() &&\n this.currentDirectory &&\n (matchesKey(data, Key.left) || matchesKey(data, Key.backspace))\n ) {\n this.showParentDirectory();\n return;\n }\n if (!this.isFileSearchActive() && matchesKey(data, Key.right)) {\n const item = this.fileItems[this.selectedFileIndex];\n if (item?.kind === \"directory\") this.showDirectory(item.path);\n return;\n }\n\n const previousQuery = this.search.getValue();\n this.search.handleInput(data);\n const query = this.search.getValue();\n if (query !== previousQuery) {\n this.refreshFileItems(query);\n this.selectedFileIndex = 0;\n this.fileScrollOffset = 0;\n this.error = undefined;\n }\n }\n\n private handleContentInput(data: string): void {\n this.cancelOpenRequest();\n this.error = undefined;\n this.contentSearch.handleInput(data);\n }\n\n private handlePreviewInput(data: string): void {\n const loadedFile = this.loadedFile;\n if (!loadedFile) return;\n const lines = loadedFile.lines;\n if (this.options.keybindings.matches(data, \"app.editor.external\")) {\n if (this.loadedRevision) {\n this.error = \"Historical revisions are read-only; return to the worktree preview to edit\";\n } else if (this.options.editFile && !this.loading) {\n void this.editCurrentFile();\n } else if (!this.options.editFile) {\n this.error = \"External editing is unavailable\";\n }\n return;\n }\n if (matchesKey(data, Key.escape)) {\n this.returnToOrigin();\n return;\n }\n if (data === \"?\") {\n this.cancelDetailRequest();\n this.mode = \"preview-help\";\n this.search.focused = false;\n this.contentSearch.focused = false;\n return;\n }\n if (data === \"a\" && this.options.onAddAndContinue) {\n try {\n const quote = this.createSelectedQuote();\n this.options.onAddAndContinue(quote);\n this.returnToOrigin();\n } catch (error: unknown) {\n this.error = formatError(error);\n }\n return;\n }\n if (data === \" \") {\n this.previewAnchor = this.previewAnchor === undefined ? this.previewCursor : undefined;\n this.error = undefined;\n return;\n }\n if (data === \"b\") {\n void this.loadBlame();\n return;\n }\n if (data === \"h\") {\n void this.loadHistory();\n return;\n }\n if (data === \"r\") {\n this.mode = \"revision\";\n this.revisionInput.setValue(\"\");\n this.revisionInput.focused = this.isFocused;\n this.error = undefined;\n return;\n }\n if (data === \"d\") {\n if (this.loadedRevision) {\n this.error = \"Diff context is available from the worktree preview\";\n return;\n }\n if ((this.loadedGit?.hunks.length ?? 0) === 0) {\n this.error = \"No changed hunks for this file\";\n return;\n }\n this.diffHunkIndex = Math.max(0, this.hunkIndex);\n this.diffScrollOffset = 0;\n this.mode = \"diff\";\n this.error = undefined;\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.up\")) {\n this.movePreviewCursor(Math.max(0, this.previewCursor - 1));\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.down\")) {\n this.movePreviewCursor(Math.min(Math.max(0, lines.length - 1), this.previewCursor + 1));\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.pageUp\")) {\n this.movePreviewCursor(Math.max(0, this.previewCursor - 10));\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.pageDown\")) {\n this.movePreviewCursor(Math.min(Math.max(0, lines.length - 1), this.previewCursor + 10));\n return;\n }\n if (data === \"]\" || data === \"[\") {\n this.navigateHunk(data === \"]\" ? 1 : -1);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.confirm\")) {\n try {\n const quote = this.createSelectedQuote();\n this.options.validateQuote?.(quote);\n this.finish({ kind: \"quote\", quote });\n } catch (error: unknown) {\n this.error = formatError(error);\n }\n }\n }\n\n private handlePreviewHelpInput(data: string): void {\n if (matchesKey(data, Key.escape)) this.mode = \"preview\";\n }\n\n private handleHistoryInput(data: string): void {\n if (matchesKey(data, Key.escape)) {\n this.cancelDetailRequest();\n this.mode = \"preview\";\n this.error = undefined;\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.up\")) {\n this.historyIndex = Math.max(0, this.historyIndex - 1);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.down\")) {\n this.historyIndex = Math.min(Math.max(0, this.history.length - 1), this.historyIndex + 1);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.confirm\")) {\n const entry = this.history[this.historyIndex];\n if (entry) void this.loadRevision(entry.commit, entry.path);\n }\n }\n\n private handleRevisionInput(data: string): void {\n if (matchesKey(data, Key.escape)) {\n this.cancelDetailRequest();\n this.mode = \"preview\";\n this.revisionInput.focused = false;\n this.error = undefined;\n return;\n }\n if (this.loading) return;\n if (this.options.keybindings.matches(data, \"tui.select.confirm\")) {\n void this.loadRevision(this.revisionInput.getValue());\n return;\n }\n this.revisionInput.handleInput(data);\n }\n\n private handleDiffInput(data: string): void {\n if (matchesKey(data, Key.escape)) {\n this.mode = \"preview\";\n this.error = undefined;\n return;\n }\n const hunks = this.loadedGit?.hunks ?? [];\n const hunkLines = hunks[this.diffHunkIndex]?.lines ?? [];\n if (this.options.keybindings.matches(data, \"tui.select.up\")) {\n this.diffScrollOffset = Math.max(0, this.diffScrollOffset - 1);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.down\")) {\n this.diffScrollOffset = Math.min(Math.max(0, hunkLines.length - 1), this.diffScrollOffset + 1);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.pageUp\")) {\n this.diffScrollOffset = Math.max(0, this.diffScrollOffset - 10);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.pageDown\")) {\n this.diffScrollOffset = Math.min(Math.max(0, hunkLines.length - 1), this.diffScrollOffset + 10);\n return;\n }\n if (data === \"]\" || data === \"[\") {\n if (hunks.length > 0) {\n const direction = data === \"]\" ? 1 : -1;\n this.diffHunkIndex = (this.diffHunkIndex + direction + hunks.length) % hunks.length;\n this.diffScrollOffset = 0;\n }\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.confirm\")) {\n const hunk = hunks[this.diffHunkIndex];\n const loadedFile = this.loadedFile;\n const project = this.options.gitContext?.project;\n if (!hunk || !loadedFile || !project) return;\n try {\n const startLine = Math.max(1, hunk.newStart);\n const endLine = Math.max(startLine, hunk.newStart + hunk.newCount - 1);\n const quote = createFileQuoteSnapshot(loadedFile.path, startLine, endLine, hunk.lines.join(\"\\n\"), {\n head: project.head,\n branch: project.branch,\n status: this.loadedGit?.status?.label ?? \"modified\",\n blob: this.loadedGit?.blob,\n source: \"git_diff\",\n base: \"HEAD\",\n });\n this.options.validateQuote?.(quote);\n this.finish({ kind: \"quote\", quote });\n } catch (error: unknown) {\n this.error = formatError(error);\n }\n }\n }\n\n private async editCurrentFile(): Promise<void> {\n const path = this.loadedFile?.path;\n const editFile = this.options.editFile;\n if (!path || !editFile || this.loadedRevision) return;\n this.cancelOpenRequest();\n this.cancelDetailRequest();\n this.cancelEditRequest();\n const request = this.editRequest;\n const controller = new AbortController();\n this.editController = controller;\n this.loading = true;\n this.error = undefined;\n this.options.tui.requestRender();\n try {\n await editFile(path, controller.signal);\n if (!this.isCurrentEditRequest(request, controller, path)) return;\n const gitContext = this.options.gitContext;\n const [loadedFile, loadedGit] = await Promise.all([\n this.options.loadFile(path, controller.signal),\n gitContext\n ? (gitContext.refreshFileContext?.(path, controller.signal) ??\n gitContext.getFileContext(path, controller.signal))\n : undefined,\n ]);\n if (!this.isCurrentEditRequest(request, controller, path)) return;\n const maximumIndex = Math.max(0, loadedFile.lines.length - 1);\n this.loadedFile = loadedFile;\n this.loadedGit = loadedGit;\n this.previewCursor = Math.min(this.previewCursor, maximumIndex);\n if (this.previewAnchor !== undefined) {\n this.previewAnchor = Math.min(this.previewAnchor, maximumIndex);\n }\n this.previewScrollOffset = Math.min(this.previewScrollOffset, maximumIndex);\n this.activeContentMatch = undefined;\n this.hunkIndex = -1;\n this.blame = undefined;\n this.history = [];\n this.error = undefined;\n } catch (error: unknown) {\n if (this.isCurrentEditRequest(request, controller, path) && !isAbortError(error)) {\n this.error = formatError(error);\n }\n } finally {\n if (request === this.editRequest && this.editController === controller) {\n this.loading = false;\n this.editController = undefined;\n }\n if (!this.finished && !this.disposed) this.options.tui.requestRender(true);\n }\n }\n\n private async loadRevision(revision: string, historicalPath?: string): Promise<void> {\n const path = this.loadedFile?.path;\n const gitContext = this.options.gitContext;\n if (!path || !gitContext) {\n this.error = \"Git revision browsing is unavailable\";\n return;\n }\n const { request, signal } = this.beginDetailRequest();\n this.error = undefined;\n this.options.tui.requestRender();\n try {\n const loadedRevision = await gitContext.loadRevision(path, revision, historicalPath, signal);\n if (this.finished || request !== this.detailRequest) return;\n this.loadedRevision = loadedRevision;\n this.loadedFile = { path: loadedRevision.path, lines: loadedRevision.lines };\n this.activeContentMatch = undefined;\n this.previewCursor = 0;\n this.previewAnchor = undefined;\n this.previewScrollOffset = 0;\n this.blame = undefined;\n this.mode = \"preview\";\n this.revisionInput.focused = false;\n } catch (error: unknown) {\n if (request === this.detailRequest && !isAbortError(error)) this.error = formatError(error);\n } finally {\n this.finishDetailRequest(request);\n }\n }\n\n private async loadBlame(): Promise<void> {\n const path = this.loadedFile?.path;\n const gitContext = this.options.gitContext;\n if (!path || !gitContext) {\n this.error = \"Git blame is unavailable\";\n return;\n }\n const { request, signal } = this.beginDetailRequest();\n const requestedLine = this.previewCursor + 1;\n this.error = undefined;\n this.options.tui.requestRender();\n try {\n const blame = await gitContext.getBlame(path, requestedLine, this.loadedRevision?.commit, signal);\n if (\n this.finished ||\n request !== this.detailRequest ||\n this.mode !== \"preview\" ||\n requestedLine !== this.previewCursor + 1\n ) {\n return;\n }\n this.blame = blame;\n if (!blame) this.error = \"No blame information for this line\";\n } catch (error: unknown) {\n if (request === this.detailRequest && !isAbortError(error)) this.error = formatError(error);\n } finally {\n this.finishDetailRequest(request);\n }\n }\n\n private async loadHistory(): Promise<void> {\n const path = this.loadedFile?.path;\n const gitContext = this.options.gitContext;\n if (!path || !gitContext) {\n this.error = \"Git history is unavailable\";\n return;\n }\n const { request, signal } = this.beginDetailRequest();\n this.error = undefined;\n this.options.tui.requestRender();\n try {\n const history = await gitContext.getHistory(path, signal);\n if (this.finished || request !== this.detailRequest || this.mode !== \"preview\") return;\n this.history = history;\n this.historyIndex = 0;\n this.mode = \"history\";\n } catch (error: unknown) {\n if (request === this.detailRequest && !isAbortError(error)) this.error = formatError(error);\n } finally {\n this.finishDetailRequest(request);\n }\n }\n\n private async openFile(\n path: string,\n options: {\n returnMode?: \"files\" | \"contents\";\n cursorIndex?: number;\n match?: ContentSearchMatch;\n } = {},\n ): Promise<void> {\n this.cancelOpenRequest();\n const request = this.openRequest;\n const controller = new AbortController();\n this.openController = controller;\n this.loading = true;\n this.error = undefined;\n this.options.tui.requestRender();\n try {\n const [loadedFile, loadedGit] = await Promise.all([\n this.options.loadFile(path, controller.signal),\n this.options.gitContext?.getFileContext(path, controller.signal),\n ]);\n if (!this.isCurrentOpenRequest(request, controller)) return;\n this.loadedFile = loadedFile;\n this.loadedGit = loadedGit;\n this.loadedRevision = undefined;\n this.mode = \"preview\";\n this.previewReturnMode = options.returnMode ?? \"files\";\n this.activeContentMatch = options.match;\n this.previewCursor = Math.max(0, Math.min(Math.max(0, loadedFile.lines.length - 1), options.cursorIndex ?? 0));\n this.previewAnchor = undefined;\n this.previewScrollOffset = Math.max(0, this.previewCursor - 1);\n this.hunkIndex = -1;\n this.blame = undefined;\n this.history = [];\n this.detailRequest += 1;\n this.error = undefined;\n this.search.focused = false;\n this.contentSearch.focused = false;\n } catch (error: unknown) {\n if (this.isCurrentOpenRequest(request, controller) && !isAbortError(error)) {\n this.error = formatError(error);\n }\n } finally {\n if (request === this.openRequest) {\n this.loading = false;\n this.openController = undefined;\n }\n if (!this.finished && !this.disposed) this.options.tui.requestRender();\n }\n }\n\n private navigateHunk(direction: 1 | -1): void {\n const hunks = this.loadedGit?.hunks ?? [];\n const lineCount = this.loadedFile?.lines.length ?? 0;\n if (hunks.length === 0 || lineCount === 0) {\n this.error = \"No changed hunks for this file\";\n return;\n }\n this.hunkIndex =\n this.hunkIndex < 0\n ? direction > 0\n ? 0\n : hunks.length - 1\n : (this.hunkIndex + direction + hunks.length) % hunks.length;\n const hunk = hunks[this.hunkIndex];\n const selectedLines = hunk.changedLines.length > 0 ? hunk.changedLines : [hunk.newStart];\n const start = Math.max(0, Math.min(...selectedLines) - 1);\n const end = Math.max(start, Math.min(lineCount - 1, Math.max(...selectedLines) - 1));\n this.previewAnchor = start;\n this.movePreviewCursor(end);\n this.error = undefined;\n }\n\n private showContentSearch(): void {\n this.cancelOpenRequest();\n this.mode = \"contents\";\n this.search.focused = false;\n this.contentSearch.activate();\n this.contentSearch.focused = this.isFocused;\n this.error = undefined;\n }\n\n private showFileSearch(): void {\n this.contentSearch.deactivate();\n this.cancelOpenRequest();\n this.mode = \"files\";\n this.search.focused = this.isFocused;\n this.error = undefined;\n }\n\n private openSelectedFileItem(): void {\n const item = this.fileItems[this.selectedFileIndex];\n if (item?.kind === \"directory\") {\n this.showDirectory(item.path);\n return;\n }\n if (item?.kind === \"file\") void this.openFile(item.path);\n }\n\n private showDirectory(directory: string): void {\n this.directoryPositions.set(this.currentDirectory, {\n index: this.selectedFileIndex,\n offset: this.fileScrollOffset,\n });\n this.currentDirectory = directory;\n this.refreshFileItems(\"\");\n const position = this.directoryPositions.get(directory);\n this.selectedFileIndex = Math.min(position?.index ?? 0, Math.max(0, this.fileItems.length - 1));\n this.fileScrollOffset = Math.min(position?.offset ?? 0, this.selectedFileIndex);\n this.error = undefined;\n }\n\n private showParentDirectory(): void {\n this.cancelOpenRequest();\n this.currentDirectory = parentProjectDirectory(this.currentDirectory);\n this.refreshFileItems(\"\");\n const position = this.directoryPositions.get(this.currentDirectory);\n this.selectedFileIndex = Math.min(position?.index ?? 0, Math.max(0, this.fileItems.length - 1));\n this.fileScrollOffset = Math.min(position?.offset ?? 0, this.selectedFileIndex);\n this.error = undefined;\n }\n\n private refreshFileItems(query: string): void {\n this.fileItems = this.isFileSearchActive(query)\n ? this.fileBrowser.searchResults(this.fileSearch.search(query))\n : this.fileBrowser.list(this.currentDirectory);\n }\n\n private isFileSearchActive(query = this.search.getValue()): boolean {\n return escapeTerminalControls(query).trim().length > 0;\n }\n\n private cancelFileList(): void {\n if (this.currentDirectory && !this.isFileSearchActive()) {\n this.showParentDirectory();\n return;\n }\n this.finish(this.rootExit(\"back\"));\n }\n\n private cancelOpenRequest(): void {\n this.openRequest += 1;\n this.openController?.abort();\n this.openController = undefined;\n this.loading = false;\n }\n\n private isCurrentOpenRequest(request: number, controller: AbortController): boolean {\n return (\n !this.finished &&\n !this.disposed &&\n request === this.openRequest &&\n this.openController === controller &&\n !controller.signal.aborted\n );\n }\n\n private isCurrentEditRequest(request: number, controller: AbortController, path: string): boolean {\n return (\n !this.finished &&\n !this.disposed &&\n this.mode === \"preview\" &&\n this.loadedRevision === undefined &&\n this.loadedFile?.path === path &&\n request === this.editRequest &&\n this.editController === controller &&\n !controller.signal.aborted\n );\n }\n\n private beginDetailRequest(): { request: number; signal: AbortSignal } {\n this.cancelDetailRequest();\n const request = this.detailRequest;\n const controller = new AbortController();\n this.detailController = controller;\n this.loading = true;\n return { request, signal: controller.signal };\n }\n\n private finishDetailRequest(request: number): void {\n if (request === this.detailRequest) {\n this.loading = false;\n this.detailController = undefined;\n }\n if (!this.finished && !this.disposed) this.options.tui.requestRender();\n }\n\n private cancelDetailRequest(): void {\n this.detailRequest += 1;\n this.detailController?.abort();\n this.detailController = undefined;\n this.loading = false;\n }\n\n private cancelEditRequest(): void {\n this.editRequest += 1;\n this.editController?.abort();\n this.editController = undefined;\n this.loading = false;\n }\n\n private movePreviewCursor(next: number): void {\n if (next === this.previewCursor) return;\n this.cancelDetailRequest();\n this.previewCursor = next;\n this.blame = undefined;\n this.error = undefined;\n }\n\n private createSelectedQuote(): FileQuote {\n if (!this.loadedFile) throw new Error(\"No file is open\");\n return createPreviewQuote(\n this.loadedFile,\n this.previewAnchor ?? this.previewCursor,\n this.previewCursor,\n this.options.gitContext?.project,\n this.loadedGit,\n this.loadedRevision,\n );\n }\n\n private returnToOrigin(): void {\n this.cancelDetailRequest();\n this.cancelOpenRequest();\n this.cancelEditRequest();\n this.mode = this.previewReturnMode;\n this.loadedFile = undefined;\n this.loadedGit = undefined;\n this.loadedRevision = undefined;\n this.previewAnchor = undefined;\n this.blame = undefined;\n this.error = undefined;\n this.search.focused = this.isFocused && this.mode === \"files\";\n this.contentSearch.focused = this.isFocused && this.mode === \"contents\";\n }\n\n private finish(result: FileQuoteExplorerResult | undefined): void {\n this.finished = true;\n this.contentSearch.dispose();\n this.cancelOpenRequest();\n this.cancelDetailRequest();\n this.cancelEditRequest();\n this.options.done(result);\n }\n\n private rootExit(kind: \"back\" | \"close\"): FileQuoteExplorerResult | undefined {\n return this.options.rootNavigation ? { kind } : undefined;\n }\n\n private keepFileVisible(height: number): void {\n if (this.selectedFileIndex < this.fileScrollOffset) this.fileScrollOffset = this.selectedFileIndex;\n if (this.selectedFileIndex >= this.fileScrollOffset + height) {\n this.fileScrollOffset = this.selectedFileIndex - height + 1;\n }\n }\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === \"AbortError\";\n}\n\nfunction formatError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n", "import type { KeybindingsManager, Theme } from \"@earendil-works/pi-coding-agent\";\nimport { Input, Key, matchesKey, type TUI, visibleWidth } from \"@earendil-works/pi-tui\";\nimport { type ContentSearchMatch, searchProjectContents } from \"./content-search.js\";\nimport { contentSearchCardCapacity, renderContentSearchScreen } from \"./content-search-ui.js\";\nimport type { LoadedProjectTextFile } from \"./file-context.js\";\n\ninterface ContentSearchSessionOptions {\n tui: TUI;\n theme: Theme;\n keybindings: KeybindingsManager;\n files: readonly string[];\n cwd?: string;\n loadFile: (path: string, signal?: AbortSignal) => Promise<LoadedProjectTextFile>;\n onPreview: (match: ContentSearchMatch) => void;\n onReference: (path: string) => void;\n onSwitchFiles: () => void;\n onCancel: () => void;\n}\n\nexport class ContentSearchSession {\n private readonly input = new Input();\n private matches: ContentSearchMatch[] = [];\n private selectedIndex = 0;\n private scrollOffset = 0;\n private caseSensitive = false;\n private fuzzy = false;\n private truncated = false;\n private skippedFiles = 0;\n private loading = false;\n private request = 0;\n private controller: AbortController | undefined;\n private error: string | undefined;\n private disposed = false;\n\n constructor(private readonly options: ContentSearchSessionOptions) {}\n\n set focused(value: boolean) {\n this.input.focused = value;\n }\n\n activate(): void {\n this.disposed = false;\n if (this.input.getValue().trim()) this.startSearch();\n }\n\n deactivate(): void {\n this.focused = false;\n this.cancelSearch();\n }\n\n render(width: number, availableRows: number, opening: boolean, externalError?: string): string[] {\n const capacity = contentSearchCardCapacity(availableRows);\n this.keepSelectionVisible(capacity);\n const queryLabel = this.options.theme.fg(\"muted\", \"Search: \");\n const queryWidth = Math.max(1, width - visibleWidth(queryLabel));\n const queryLine = `${queryLabel}${this.input.render(queryWidth)[0] ?? \"\"}`;\n return renderContentSearchScreen({\n theme: this.options.theme,\n width,\n availableRows,\n queryLine,\n query: this.input.getValue(),\n cwd: this.options.cwd,\n matches: this.matches,\n selectedIndex: this.selectedIndex,\n scrollOffset: this.scrollOffset,\n caseSensitive: this.caseSensitive,\n fuzzy: this.fuzzy,\n loading: this.loading,\n opening,\n truncated: this.truncated,\n skippedFiles: this.skippedFiles,\n error: externalError ?? this.error,\n });\n }\n\n handleInput(data: string): void {\n if (this.disposed) return;\n if (matchesKey(data, Key.ctrl(\"f\"))) {\n this.options.onSwitchFiles();\n return;\n }\n if (matchesKey(data, Key.escape)) {\n this.options.onCancel();\n return;\n }\n if (matchesKey(data, Key.alt(\"c\"))) {\n this.caseSensitive = !this.caseSensitive;\n this.startSearch();\n return;\n }\n if (matchesKey(data, Key.alt(\"f\"))) {\n this.fuzzy = !this.fuzzy;\n this.startSearch();\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.up\")) {\n this.selectedIndex = Math.max(0, this.selectedIndex - 1);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.down\")) {\n this.selectedIndex = Math.min(Math.max(0, this.matches.length - 1), this.selectedIndex + 1);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.pageUp\")) {\n this.selectedIndex = Math.max(0, this.selectedIndex - 10);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.pageDown\")) {\n this.selectedIndex = Math.min(Math.max(0, this.matches.length - 1), this.selectedIndex + 10);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.select.confirm\")) {\n const match = this.matches[this.selectedIndex];\n if (match) this.options.onPreview(match);\n return;\n }\n if (this.options.keybindings.matches(data, \"tui.input.tab\")) {\n const match = this.matches[this.selectedIndex];\n if (match) this.options.onReference(match.path);\n return;\n }\n\n const previousQuery = this.input.getValue();\n this.input.handleInput(data);\n if (this.input.getValue() !== previousQuery) this.startSearch();\n }\n\n invalidate(): void {\n this.input.invalidate();\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.cancelSearch();\n }\n\n private startSearch(): void {\n this.cancelSearch();\n const query = this.input.getValue();\n this.matches = [];\n this.selectedIndex = 0;\n this.scrollOffset = 0;\n this.truncated = false;\n this.skippedFiles = 0;\n this.error = undefined;\n if (!query.trim()) return;\n\n const request = this.request;\n const controller = new AbortController();\n this.controller = controller;\n this.loading = true;\n void searchProjectContents(this.options.files, this.options.loadFile, query, {\n caseSensitive: this.caseSensitive,\n fuzzy: this.fuzzy,\n signal: controller.signal,\n })\n .then((result) => {\n if (!this.isCurrent(request, controller)) return;\n this.matches = result.matches;\n this.truncated = result.truncated;\n this.skippedFiles = result.skippedFiles;\n })\n .catch((error: unknown) => {\n if (this.isCurrent(request, controller) && !isAbortError(error)) {\n this.error = formatError(error);\n }\n })\n .finally(() => {\n if (request === this.request) {\n this.loading = false;\n this.controller = undefined;\n }\n if (!this.disposed) this.options.tui.requestRender();\n });\n }\n\n private cancelSearch(): void {\n this.request += 1;\n this.controller?.abort();\n this.controller = undefined;\n this.loading = false;\n }\n\n private isCurrent(request: number, controller: AbortController): boolean {\n return !this.disposed && request === this.request && this.controller === controller && !controller.signal.aborted;\n }\n\n private keepSelectionVisible(capacity: number): void {\n if (this.selectedIndex < this.scrollOffset) this.scrollOffset = this.selectedIndex;\n if (this.selectedIndex >= this.scrollOffset + capacity) {\n this.scrollOffset = this.selectedIndex - capacity + 1;\n }\n }\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === \"AbortError\";\n}\n\nfunction formatError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n", "const MAX_CONTENT_QUERY_LENGTH = 256;\nconst DEFAULT_MAX_RESULTS = 100;\n\nexport interface ContentMatchRange {\n start: number;\n end: number;\n}\n\nexport interface ContentSearchMatch {\n path: string;\n lineNumber: number;\n line: string;\n ranges: ContentMatchRange[];\n fuzzy: boolean;\n}\n\nexport interface ContentSearchResult {\n matches: ContentSearchMatch[];\n truncated: boolean;\n skippedFiles: number;\n}\n\nexport interface ContentSearchOptions {\n caseSensitive?: boolean;\n fuzzy?: boolean;\n maxResults?: number;\n signal?: AbortSignal;\n}\n\ninterface SearchableTextFile {\n path: string;\n lines: readonly string[];\n}\n\ntype IndexedCharacter = { start: number; end: number; comparable: string };\n\ntype LoadSearchableFile = (path: string, signal?: AbortSignal) => Promise<SearchableTextFile>;\n\nexport async function searchProjectContents(\n files: readonly string[],\n loadFile: LoadSearchableFile,\n query: string,\n options: ContentSearchOptions = {},\n): Promise<ContentSearchResult> {\n const signal = options.signal;\n signal?.throwIfAborted();\n if (!query.trim() || query.length > MAX_CONTENT_QUERY_LENGTH) {\n return { matches: [], truncated: false, skippedFiles: 0 };\n }\n\n const maxResults = Math.max(1, options.maxResults ?? DEFAULT_MAX_RESULTS);\n const caseSensitive = options.caseSensitive ?? false;\n const literalExpression = new RegExp(escapeRegExp(query), caseSensitive ? \"g\" : \"gi\");\n const fuzzyQuery = options.fuzzy ? indexedCharacters(query, caseSensitive) : [];\n const matches: ContentSearchMatch[] = [];\n let truncated = false;\n let skippedFiles = 0;\n\n for (const path of files) {\n signal?.throwIfAborted();\n let file: SearchableTextFile;\n try {\n file = await loadFile(path, signal);\n } catch (error: unknown) {\n if (isAbortError(error) || signal?.aborted) throw error;\n skippedFiles += 1;\n continue;\n }\n signal?.throwIfAborted();\n\n for (let lineIndex = 0; lineIndex < file.lines.length; lineIndex += 1) {\n const line = file.lines[lineIndex] ?? \"\";\n const literalRanges = findLiteralRanges(line, literalExpression);\n if (literalRanges.length > 0) {\n if (matches.length < maxResults) {\n matches.push({\n path: file.path,\n lineNumber: lineIndex + 1,\n line,\n ranges: literalRanges,\n fuzzy: false,\n });\n } else {\n truncated = true;\n }\n continue;\n }\n\n if (!options.fuzzy) continue;\n const fuzzyRanges = findSubsequenceRanges(line, fuzzyQuery, caseSensitive);\n if (!fuzzyRanges) continue;\n if (matches.length < maxResults) {\n matches.push({\n path: file.path,\n lineNumber: lineIndex + 1,\n line,\n ranges: fuzzyRanges,\n fuzzy: true,\n });\n } else {\n truncated = true;\n }\n }\n }\n\n return { matches, truncated, skippedFiles };\n}\n\nfunction findLiteralRanges(line: string, expression: RegExp): ContentMatchRange[] {\n const ranges: ContentMatchRange[] = [];\n expression.lastIndex = 0;\n for (let match = expression.exec(line); match; match = expression.exec(line)) {\n const start = match.index;\n ranges.push({ start, end: start + match[0].length });\n }\n return ranges;\n}\n\nfunction findSubsequenceRanges(\n line: string,\n queryCharacters: readonly IndexedCharacter[],\n caseSensitive: boolean,\n): ContentMatchRange[] | undefined {\n const lineCharacters = indexedCharacters(line, caseSensitive);\n const positions: Array<{ start: number; end: number }> = [];\n let queryIndex = 0;\n for (let lineIndex = 0; lineIndex < lineCharacters.length && queryIndex < queryCharacters.length; lineIndex += 1) {\n const lineCharacter = lineCharacters[lineIndex];\n const queryCharacter = queryCharacters[queryIndex];\n if (!lineCharacter || !queryCharacter || lineCharacter.comparable !== queryCharacter.comparable) {\n continue;\n }\n positions.push({ start: lineCharacter.start, end: lineCharacter.end });\n queryIndex += 1;\n }\n if (queryIndex !== queryCharacters.length) return undefined;\n\n const ranges: ContentMatchRange[] = [];\n for (const position of positions) {\n const previous = ranges.at(-1);\n if (previous?.end === position.start) previous.end = position.end;\n else ranges.push(position);\n }\n return ranges;\n}\n\nfunction indexedCharacters(value: string, caseSensitive: boolean): IndexedCharacter[] {\n const characters: IndexedCharacter[] = [];\n for (let start = 0; start < value.length; ) {\n const codePoint = value.codePointAt(start);\n if (codePoint === undefined) break;\n const character = String.fromCodePoint(codePoint);\n const end = start + character.length;\n characters.push({\n start,\n end,\n comparable: caseSensitive ? character : character.toLowerCase(),\n });\n start = end;\n }\n return characters;\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === \"AbortError\";\n}\n", "import type { Theme } from \"@earendil-works/pi-coding-agent\";\nimport { truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { ContentMatchRange, ContentSearchMatch } from \"./content-search.js\";\n\nexport const CONTENT_SEARCH_CARD_ROWS = 3;\n\ninterface ContentSearchScreenOptions {\n theme: Theme;\n width: number;\n availableRows: number;\n queryLine: string;\n query: string;\n cwd?: string;\n matches: readonly ContentSearchMatch[];\n selectedIndex: number;\n scrollOffset: number;\n caseSensitive: boolean;\n fuzzy: boolean;\n loading: boolean;\n opening: boolean;\n truncated: boolean;\n skippedFiles: number;\n error?: string;\n}\n\nexport function contentSearchCardCapacity(availableRows: number): number {\n return Math.max(1, Math.floor((availableRows - 4) / CONTENT_SEARCH_CARD_ROWS));\n}\n\nexport function renderContentSearchScreen(options: ContentSearchScreenOptions): string[] {\n const { theme, width, availableRows } = options;\n const capacity = contentSearchCardCapacity(availableRows);\n const cwdLabel = options.cwd ? ` \u00B7 cwd: ${escapeTerminalControls(options.cwd)}` : \"\";\n const title = theme.fg(\"accent\", theme.bold(`File Context \u00B7 Content Search${cwdLabel}`));\n const modes = theme.fg(\n \"muted\",\n `Case: ${options.caseSensitive ? \"on\" : \"off\"} \u00B7 Fuzzy: ${options.fuzzy ? \"on\" : \"off\"} \u00B7 Alt+C case \u00B7 Alt+F fuzzy`,\n );\n const body: string[] = [];\n\n if (options.error) {\n body.push(theme.fg(\"error\", ` Search failed: ${escapeTerminalControls(options.error)}`));\n } else if (options.loading) {\n body.push(theme.fg(\"warning\", \" Searching\u2026\"));\n } else if (!options.query.trim()) {\n body.push(theme.fg(\"muted\", \" Type text to search project contents\"));\n } else if (options.matches.length === 0) {\n body.push(\n theme.fg(\n \"muted\",\n ` No matches for \"${escapeTerminalControls(options.query)}\"${options.fuzzy ? \"\" : \" \u00B7 Alt+F enables fuzzy matching\"}`,\n ),\n );\n } else {\n const visible = options.matches.slice(options.scrollOffset, options.scrollOffset + capacity);\n for (let visibleIndex = 0; visibleIndex < visible.length; visibleIndex += 1) {\n const index = options.scrollOffset + visibleIndex;\n const match = visible[visibleIndex];\n if (match) {\n body.push(...renderContentSearchCard(match, index === options.selectedIndex, width, theme));\n }\n }\n }\n\n const count = `${options.matches.length}${options.truncated ? \"+\" : \"\"} matches`;\n const skipped = options.skippedFiles > 0 ? ` \u00B7 ${options.skippedFiles} skipped` : \"\";\n const action = options.opening\n ? \"Opening\u2026\"\n : `${count}${skipped} \u00B7 \u2191\u2193 navigate \u00B7 Enter preview \u00B7 Tab reference \u00B7 Ctrl+F files \u00B7 Esc cancel`;\n return fitRows(\n [\n truncateToWidth(title, width, \"\"),\n truncateToWidth(options.queryLine, width, \"\"),\n truncateToWidth(modes, width, \"\"),\n ...body.map((line) => truncateToWidth(line, width, \"\")),\n truncateToWidth(theme.fg(options.opening ? \"warning\" : \"muted\", action), width, \"\"),\n ],\n availableRows,\n );\n}\n\nexport function highlightContentRanges(line: string, ranges: readonly ContentMatchRange[], theme: Theme): string {\n let result = \"\";\n let index = 0;\n for (const range of ranges) {\n const start = Math.max(index, Math.min(line.length, range.start));\n const end = Math.max(start, Math.min(line.length, range.end));\n result += escapeTerminalControls(line.slice(index, start));\n result += theme.fg(\"warning\", theme.bold(escapeTerminalControls(line.slice(start, end))));\n index = end;\n }\n return result + escapeTerminalControls(line.slice(index));\n}\n\nfunction renderContentSearchCard(match: ContentSearchMatch, selected: boolean, width: number, theme: Theme): string[] {\n if (width < 8) {\n return [truncateToWidth(`${selected ? \">\" : \" \"}${escapeTerminalControls(match.path)}`, width, \"\")];\n }\n const prefix = selected ? theme.fg(\"accent\", \"> \") : \" \";\n const cardWidth = Math.max(4, width - visibleWidth(prefix));\n const innerWidth = Math.max(1, cardWidth - 2);\n const borderColor = selected ? \"borderAccent\" : \"borderMuted\";\n const border = (text: string) => theme.fg(borderColor, text);\n const rawTitle = ` ${escapeTerminalControls(match.path)} \u00B7 L${match.lineNumber} `;\n const title = truncateToWidth(rawTitle, innerWidth, \"\");\n const titleFill = \"\u2500\".repeat(Math.max(0, innerWidth - visibleWidth(title)));\n const context = clipMatchContext(match, Math.max(1, innerWidth - 1));\n const highlighted = highlightContentRanges(context.line, context.ranges, theme);\n const content = truncateToWidth(` ${highlighted}`, innerWidth, \"\");\n const contentFill = \" \".repeat(Math.max(0, innerWidth - visibleWidth(content)));\n const contentLine = `${border(\"\u2502\")}${content}${contentFill}${border(\"\u2502\")}`;\n return [\n `${prefix}${border(\"\u256D\")}${title}${border(`${titleFill}\u256E`)}`,\n `${\" \".repeat(visibleWidth(prefix))}${selected ? theme.bg(\"selectedBg\", contentLine) : contentLine}`,\n `${\" \".repeat(visibleWidth(prefix))}${border(`\u2570${\"\u2500\".repeat(innerWidth)}\u256F`)}`,\n ];\n}\n\nfunction clipMatchContext(\n match: ContentSearchMatch,\n maxCharacters: number,\n): { line: string; ranges: ContentMatchRange[] } {\n const firstStart = match.ranges[0]?.start ?? 0;\n const lastEnd = match.ranges.at(-1)?.end ?? firstStart;\n const matchSpan = Math.max(1, lastEnd - firstStart);\n const before = Math.max(0, Math.floor((maxCharacters - Math.min(matchSpan, maxCharacters)) / 3));\n const rawStart = Math.max(0, firstStart - before);\n const prefix = rawStart > 0 ? \"\u2026\" : \"\";\n const availableRawCharacters = Math.max(1, maxCharacters - prefix.length - 1);\n let rawEnd = Math.min(match.line.length, rawStart + availableRawCharacters);\n if (rawEnd < lastEnd) rawEnd = Math.min(match.line.length, lastEnd);\n const suffix = rawEnd < match.line.length ? \"\u2026\" : \"\";\n const line = `${prefix}${match.line.slice(rawStart, rawEnd)}${suffix}`;\n const ranges = match.ranges.flatMap((range): ContentMatchRange[] => {\n const start = Math.max(rawStart, range.start);\n const end = Math.min(rawEnd, range.end);\n return end > start ? [{ start: prefix.length + start - rawStart, end: prefix.length + end - rawStart }] : [];\n });\n return { line, ranges };\n}\n\nfunction fitRows(lines: string[], height: number): string[] {\n if (lines.length <= height) return lines;\n if (height <= 1) return lines.slice(0, 1);\n return [...lines.slice(0, height - 1), lines.at(-1) ?? \"\"];\n}\n\nfunction escapeTerminalControls(text: string): string {\n return [...text]\n .map((character) => {\n if (character === \"\\t\") return \" \";\n const code = character.charCodeAt(0);\n if (code <= 31 || (code >= 127 && code <= 159)) {\n return `\\\\x${code.toString(16).padStart(2, \"0\")}`;\n }\n return character;\n })\n .join(\"\");\n}\n", "interface IndexedProjectFile {\n path: string;\n displayPath: string;\n segments: readonly string[];\n}\n\nexport type ProjectBrowserItem =\n | { kind: \"directory\"; path: string; label: string }\n | { kind: \"file\"; path: string; label: string };\n\nexport class ProjectFileBrowser {\n private readonly files: readonly IndexedProjectFile[];\n private readonly filesByPath: ReadonlyMap<string, IndexedProjectFile>;\n\n constructor(paths: readonly string[]) {\n this.files = paths.map((path) => {\n const displayPath = safeTerminalText(path);\n return { path, displayPath, segments: displayPath.split(\"/\") };\n });\n this.filesByPath = new Map(this.files.map((file) => [file.path, file]));\n }\n\n list(directory: string): ProjectBrowserItem[] {\n const directorySegments = directory ? directory.split(\"/\") : [];\n const directories = new Map<string, ProjectBrowserItem>();\n const files: ProjectBrowserItem[] = [];\n\n for (const file of this.files) {\n if (!startsWithSegments(file.segments, directorySegments)) continue;\n const childIndex = directorySegments.length;\n const label = file.segments[childIndex];\n if (!label) continue;\n if (file.segments.length > childIndex + 1) {\n const path = [...directorySegments, label].join(\"/\");\n directories.set(path, { kind: \"directory\", path, label });\n continue;\n }\n files.push({ kind: \"file\", path: file.path, label });\n }\n\n return [...[...directories.values()].sort(compareBrowserItems), ...files.sort(compareBrowserItems)];\n }\n\n searchResults(paths: readonly string[]): ProjectBrowserItem[] {\n return paths.flatMap((path) => {\n const file = this.filesByPath.get(path);\n return file ? [{ kind: \"file\" as const, path: file.path, label: file.displayPath }] : [];\n });\n }\n}\n\nexport function parentProjectDirectory(directory: string): string {\n const separator = directory.lastIndexOf(\"/\");\n return separator < 0 ? \"\" : directory.slice(0, separator);\n}\n\nexport function safeTerminalText(text: string): string {\n return [...text]\n .map((character) => {\n if (character === \"\\t\") return \" \";\n const code = character.charCodeAt(0);\n if (code <= 31 || (code >= 127 && code <= 159)) {\n return `\\\\x${code.toString(16).padStart(2, \"0\")}`;\n }\n return character;\n })\n .join(\"\");\n}\n\nfunction startsWithSegments(path: readonly string[], prefix: readonly string[]): boolean {\n return prefix.every((segment, index) => path[index] === segment);\n}\n\nfunction compareBrowserItems(left: ProjectBrowserItem, right: ProjectBrowserItem): number {\n return left.label < right.label ? -1 : left.label > right.label ? 1 : 0;\n}\n", "import type { KeybindingsManager, Theme } from \"@earendil-works/pi-coding-agent\";\nimport { truncateToWidth } from \"@earendil-works/pi-tui\";\nimport type { ProjectBrowserItem } from \"./file-browser.js\";\nimport { safeTerminalText } from \"./file-browser.js\";\n\ninterface FileBrowserRenderOptions {\n theme: Theme;\n keybindings: KeybindingsManager;\n width: number;\n height: number;\n items: readonly ProjectBrowserItem[];\n selectedIndex: number;\n scrollOffset: number;\n currentDirectory: string;\n searchLine: string;\n searchActive: boolean;\n repositoryLabel: string;\n statuses?: ReadonlyMap<string, { code: string }>;\n loading: boolean;\n error?: string;\n}\n\nexport function renderFileBrowser(options: FileBrowserRenderOptions): string[] {\n const location = options.currentDirectory ? `/${options.currentDirectory}` : \"/\";\n const title = options.theme.fg(\n \"accent\",\n options.theme.bold(`File Context \u00B7 files \u00B7 ${location}${options.repositoryLabel}`),\n );\n const visibleItems = options.items.slice(options.scrollOffset, options.scrollOffset + options.height);\n const itemLines = visibleItems.map((item, visibleIndex) => {\n const index = options.scrollOffset + visibleIndex;\n const prefix = index === options.selectedIndex ? \"> \" : \" \";\n const status = item.kind === \"file\" ? (options.statuses?.get(item.path)?.code ?? \" \") : \" \";\n const suffix = item.kind === \"directory\" ? \"/\" : \"\";\n const line = `${prefix}${status} ${item.label}${suffix}`;\n return truncateToWidth(\n index === options.selectedIndex ? options.theme.bg(\"selectedBg\", options.theme.fg(\"text\", line)) : line,\n options.width,\n \"\",\n );\n });\n if (itemLines.length === 0) {\n itemLines.push(truncateToWidth(options.theme.fg(\"muted\", \" No matching files\"), options.width, \"\"));\n }\n const state = options.loading\n ? options.theme.fg(\"warning\", \"Loading\u2026\")\n : options.error\n ? options.theme.fg(\"error\", safeTerminalText(options.error))\n : options.theme.fg(\"muted\", formatFileBrowserHint(options));\n return [\n truncateToWidth(title, options.width, \"\"),\n truncateToWidth(options.searchLine, options.width, \"\"),\n ...itemLines,\n truncateToWidth(state, options.width, \"\"),\n ];\n}\n\nfunction formatFileBrowserHint(options: FileBrowserRenderOptions): string {\n const selected = options.items[options.selectedIndex];\n const countLabel = options.searchActive\n ? `${options.items.length} matching ${options.items.length === 1 ? \"file\" : \"files\"}`\n : `${options.items.length} ${options.items.length === 1 ? \"item\" : \"items\"}`;\n const navigation = navigationHint(options.keybindings);\n const confirm = bindingHint(options.keybindings, \"tui.select.confirm\", [\"enter\"]);\n const tab = bindingHint(options.keybindings, \"tui.input.tab\", [\"tab\"]);\n const cancel = uniqueKeys([\n ...bindingKeys(options.keybindings, \"tui.select.cancel\", [\"escape\"]),\n formatHintKey(\"ctrl+c\"),\n ]).join(\"/\");\n return [\n countLabel,\n `${navigation} navigate`,\n `${confirm} ${selected?.kind === \"directory\" ? \"open folder\" : \"preview\"}`,\n ...(selected?.kind === \"file\" ? [`${tab} reference`] : []),\n \"Ctrl+F contents\",\n `${cancel} ${options.currentDirectory && !options.searchActive ? \"back\" : \"cancel\"}`,\n ].join(\" \u00B7 \");\n}\n\nfunction navigationHint(keybindings: KeybindingsManager): string {\n const up = bindingKeys(keybindings, \"tui.select.up\", [\"up\"]);\n const down = bindingKeys(keybindings, \"tui.select.down\", [\"down\"]);\n if (up.includes(\"\u2191\") && down.includes(\"\u2193\")) {\n return uniqueKeys([\"\u2191\u2193\", ...up.filter((key) => key !== \"\u2191\"), ...down.filter((key) => key !== \"\u2193\")]).join(\"/\");\n }\n return uniqueKeys([...up, ...down]).join(\"/\");\n}\n\nexport function bindingHint(\n keybindings: KeybindingsManager,\n binding: Parameters<KeybindingsManager[\"getKeys\"]>[0],\n fallback: readonly string[],\n): string {\n return bindingKeys(keybindings, binding, fallback).join(\"/\");\n}\n\nfunction bindingKeys(\n keybindings: KeybindingsManager,\n binding: Parameters<KeybindingsManager[\"getKeys\"]>[0],\n fallback: readonly string[],\n): string[] {\n const getKeys = keybindings.getKeys?.bind(keybindings);\n const keys = getKeys?.(binding) ?? fallback;\n return uniqueKeys(keys.map(formatHintKey));\n}\n\nfunction uniqueKeys(keys: readonly string[]): string[] {\n return [...new Set(keys.filter(Boolean))];\n}\n\nfunction formatHintKey(key: string): string {\n const normalized = safeTerminalText(key).toLowerCase();\n if (normalized === \"up\") return \"\u2191\";\n if (normalized === \"down\") return \"\u2193\";\n if (normalized === \"left\") return \"\u2190\";\n if (normalized === \"right\") return \"\u2192\";\n if (normalized === \"return\" || normalized === \"enter\") return \"Enter\";\n if (normalized === \"escape\" || normalized === \"esc\") return \"Esc\";\n if (normalized === \"tab\") return \"Tab\";\n return normalized\n .split(\"+\")\n .map((part, index) =>\n part === \"ctrl\" || part === \"alt\" || part === \"shift\" || (index > 0 && part.length === 1)\n ? `${part[0]?.toUpperCase()}${part.slice(1)}`\n : part,\n )\n .join(\"+\");\n}\n", "import type { KeybindingsManager, Theme } from \"@earendil-works/pi-coding-agent\";\nimport { truncateToWidth } from \"@earendil-works/pi-tui\";\nimport type { ContentSearchMatch } from \"./content-search.js\";\nimport { highlightContentRanges } from \"./content-search-ui.js\";\nimport { safeTerminalText as safeHistoryText } from \"./file-browser.js\";\nimport { bindingHint } from \"./file-browser-ui.js\";\nimport type { LoadedProjectTextFile } from \"./file-context.js\";\nimport type { GitBlameInfo, GitFileContext, GitHistoryEntry, GitProjectInfo, GitRevisionFile } from \"./git-context.js\";\n\nexport interface SelectedContextState {\n count: number;\n totalBytes: number;\n maximumCount: number;\n maximumBytes: number;\n maximumSnippetLines?: number;\n maximumSnippetBytes?: number;\n}\n\ninterface FilePreviewRenderOptions {\n theme: Theme;\n keybindings: KeybindingsManager;\n width: number;\n availableRows: number;\n file: LoadedProjectTextFile;\n fileGit?: GitFileContext;\n project?: GitProjectInfo;\n revision?: GitRevisionFile;\n contentMatch?: ContentSearchMatch;\n blame?: GitBlameInfo;\n cursor: number;\n anchor?: number;\n scrollOffset: number;\n error?: string;\n selectedContext?: SelectedContextState;\n canContinue: boolean;\n canEdit: boolean;\n}\n\nexport function renderFilePreview(options: FilePreviewRenderOptions): string[] {\n const { file, theme, width } = options;\n const range = selectionRange(options.anchor, options.cursor);\n const selectedText = file.lines.slice(range.start, range.end + 1).join(\"\\n\");\n const selectedBytes = Buffer.byteLength(selectedText, \"utf8\");\n const estimatedTokens = Math.max(1, Math.ceil(selectedBytes / 4));\n const externalEditorKey = bindingHint(options.keybindings, \"app.editor.external\", []);\n const footer = options.error\n ? { lines: [escapeTerminalControls(options.error)], primaryIndexes: [0] }\n : previewFooterLines(\n width,\n range.start + 1,\n range.end + 1,\n estimatedTokens,\n selectedBytes,\n options.selectedContext,\n options.canContinue,\n options.canEdit ? externalEditorKey : \"\",\n );\n const previewHeight = Math.max(1, options.availableRows - 1 - (options.blame ? 1 : 0) - footer.lines.length);\n const scrollOffset = visiblePreviewOffset(options.scrollOffset, options.cursor, previewHeight);\n const digits = String(Math.max(1, file.lines.length)).length;\n const changedLines = new Set(options.fileGit?.hunks.flatMap((hunk) => hunk.changedLines) ?? []);\n const deletedAtLines = new Set(\n (options.fileGit?.hunks ?? [])\n .filter((hunk) => hunk.changedLines.length === 0 && hunk.oldCount > 0)\n .map((hunk) => Math.max(1, hunk.newStart)),\n );\n const previewLines = file.lines.slice(scrollOffset, scrollOffset + previewHeight).map((rawLine, visibleIndex) => {\n const index = scrollOffset + visibleIndex;\n const selected = index >= range.start && index <= range.end;\n const cursor = index === options.cursor ? \">\" : \" \";\n const marker = changedLines.has(index + 1) ? \"+\" : deletedAtLines.has(index + 1) ? \"-\" : \" \";\n const number = String(index + 1).padStart(digits, \" \");\n const contentMatch =\n options.contentMatch?.path === file.path &&\n options.contentMatch.lineNumber === index + 1 &&\n options.contentMatch.line === rawLine\n ? options.contentMatch\n : undefined;\n const content = contentMatch\n ? highlightContentRanges(rawLine, contentMatch.ranges, theme)\n : escapeTerminalControls(rawLine);\n const line = `${cursor}${marker}${number} \u2502 ${content}`;\n const styled = selected\n ? theme.bg(\"selectedBg\", theme.fg(\"text\", line))\n : index === options.cursor\n ? theme.fg(\"accent\", line)\n : line;\n return truncateToWidth(styled, width, \"\");\n });\n if (previewLines.length === 0) {\n previewLines.push(truncateToWidth(theme.fg(\"muted\", \" Empty file\"), width, \"\"));\n }\n const gitLabel = options.revision\n ? `${escapeTerminalControls(options.revision.revision)}@${options.revision.commit.slice(0, 12)} \u00B7 historical`\n : options.project\n ? `${escapeTerminalControls(options.project.branch)}@${options.project.head.slice(0, 12)}${options.project.dirty ? \" \u00B7 dirty\" : \"\"}${options.fileGit?.status ? ` \u00B7 ${options.fileGit.status.label}` : \" \u00B7 clean\"}`\n : \"\";\n const blameLabel = options.blame\n ? `L${options.cursor + 1} \u00B7 ${options.blame.committed ? options.blame.commit.slice(0, 12) : \"uncommitted\"} \u00B7 ${escapeTerminalControls(options.blame.author)} \u00B7 ${escapeTerminalControls(options.blame.summary)}`\n : \"\";\n const titleLine = truncateToWidth(\n theme.fg(\"accent\", theme.bold(`${escapeTerminalControls(file.path)}${gitLabel ? ` \u00B7 ${gitLabel}` : \"\"}`)),\n width,\n \"\",\n );\n const blameLine = blameLabel ? truncateToWidth(theme.fg(\"muted\", blameLabel), width, \"\") : undefined;\n const renderedFooter = footer.lines.map((line) =>\n truncateToWidth(theme.fg(options.error ? \"error\" : \"muted\", line), width, \"\"),\n );\n return fitPreviewRows(\n titleLine,\n blameLine,\n previewLines,\n renderedFooter,\n footer.primaryIndexes,\n options.availableRows,\n );\n}\n\nexport function renderFilePreviewHelp(\n theme: Theme,\n keybindings: KeybindingsManager,\n width: number,\n availableRows: number,\n canEdit: boolean,\n): string[] {\n const externalEditorKey = bindingHint(keybindings, \"app.editor.external\", []);\n const editDetailed = canEdit\n ? externalEditorKey\n ? `${externalEditorKey.padEnd(6, \" \")} Edit the current worktree file in the external editor`\n : \"Edit External editor action is unbound\"\n : \"Edit Historical revisions are read-only\";\n const editCompact = canEdit\n ? externalEditorKey\n ? `${externalEditorKey} edit worktree`\n : \"External editor unbound\"\n : \"Historical revision \u00B7 read-only\";\n const detailed = [\n theme.fg(\"accent\", theme.bold(\"Preview actions\")),\n \"Enter Add selected lines and close File Context\",\n \"A Add selected lines and keep browsing\",\n \"Space Set or clear the range anchor; arrows extend the range\",\n \"[ / ] Select the previous or next changed hunk\",\n \"B Blame: show ownership for the current line when Git is available\",\n \"H History: browse earlier versions of this file\",\n \"R Revision: open a commit, branch, or tag\",\n \"D Git diff: review and add one explicit changed hunk\",\n editDetailed,\n \"Esc Return to the preview without changing selected context\",\n ];\n const compact = [\n theme.fg(\"accent\", theme.bold(\"Preview actions\")),\n \"Enter add \u00B7 A keep browsing \u00B7 Space range\",\n \"\u2191\u2193 extend \u00B7 [/] hunk \u00B7 B blame\",\n \"H history \u00B7 R revision \u00B7 D Git diff\",\n editCompact,\n \"Esc back without changing context\",\n ];\n const lines = availableRows < detailed.length ? compact : detailed;\n return fitRows(\n lines.map((line) => truncateToWidth(line, width, \"\")),\n availableRows,\n );\n}\n\nfunction previewFooterLines(\n width: number,\n startLine: number,\n endLine: number,\n tokens: number,\n selectedBytes: number,\n state: SelectedContextState | undefined,\n canContinue: boolean,\n externalEditorKey: string,\n): { lines: string[]; primaryIndexes: number[] } {\n const nextCount = state ? state.count + 1 : undefined;\n const nextBytes = state ? state.totalBytes + selectedBytes : undefined;\n const selectedLines = endLine - startLine + 1;\n const snippetOverLimit =\n state !== undefined &&\n ((state.maximumSnippetLines !== undefined && selectedLines > state.maximumSnippetLines) ||\n (state.maximumSnippetBytes !== undefined && selectedBytes > state.maximumSnippetBytes));\n const aggregateOverLimit =\n state !== undefined &&\n nextCount !== undefined &&\n (nextCount > state.maximumCount || (nextBytes ?? 0) > state.maximumBytes);\n const warning = snippetOverLimit\n ? \"Snippet limit exceeded\"\n : aggregateOverLimit\n ? \"Next prompt limit exceeded\"\n : undefined;\n if (width < 74) {\n const selection = `L${startLine}-${endLine} \u00B7 ~${tokens} tok`;\n const capacity = state ? (warning ?? `Next ${nextCount}/${state.maximumCount}`) : undefined;\n const lines = [\n [selection, capacity].filter(Boolean).join(\" \u00B7 \"),\n canContinue ? \"Enter add \u00B7 A keep browsing\" : \"Enter add & close\",\n \"\u2191\u2193 move \u00B7 Space range \u00B7 Esc back\",\n [externalEditorKey ? `${externalEditorKey} edit` : \"\", \"? actions\"].filter(Boolean).join(\" \u00B7 \"),\n \"B blame \u00B7 H history \u00B7 R revision\",\n \"D diff \u00B7 [/] hunk\",\n ];\n return { lines, primaryIndexes: [1, 3] };\n }\n const selection = `Lines ${startLine}-${endLine} \u00B7 ~${tokens} tokens`;\n const capacity = state\n ? snippetOverLimit\n ? \"Snippet limit exceeded; shorten the range before adding\"\n : aggregateOverLimit\n ? \"Next prompt limit exceeded; shorten the range or review selected context\"\n : `Next prompt: ${nextCount}/${state.maximumCount} snippets \u00B7 ~${estimateTokens(nextBytes ?? 0)} tokens`\n : undefined;\n const primaryActions = canContinue\n ? \"Enter add & close \u00B7 A add & continue \u00B7 \u2191\u2193 move \u00B7 Space range \u00B7 Esc back\"\n : \"Enter add & close \u00B7 \u2191\u2193 move \u00B7 Space range \u00B7 Esc back\";\n const editActions = [externalEditorKey ? `${externalEditorKey} edit` : \"\", \"? actions\"].filter(Boolean).join(\" \u00B7 \");\n return {\n lines: [\n [selection, capacity].filter(Boolean).join(\" \u00B7 \"),\n primaryActions,\n editActions,\n \"B blame \u00B7 H history \u00B7 R revision \u00B7 D diff \u00B7 [/] hunk\",\n ],\n primaryIndexes: [1, 2],\n };\n}\n\nfunction selectionRange(anchor: number | undefined, cursor: number) {\n const rangeAnchor = anchor ?? cursor;\n return {\n start: Math.min(rangeAnchor, cursor),\n end: Math.max(rangeAnchor, cursor),\n };\n}\n\nfunction visiblePreviewOffset(current: number, cursor: number, height: number): number {\n if (cursor < current) return cursor;\n if (cursor >= current + height) return cursor - height + 1;\n return current;\n}\n\nfunction estimateTokens(bytes: number): number {\n return bytes === 0 ? 0 : Math.max(1, Math.ceil(bytes / 4));\n}\n\nfunction fitPreviewRows(\n title: string,\n blame: string | undefined,\n previewLines: readonly string[],\n footerLines: readonly string[],\n primaryFooterIndexes: readonly number[],\n height: number,\n): string[] {\n let visibleTitle: string | undefined = title;\n let visibleBlame = blame;\n const visiblePreview = [...previewLines];\n const visibleFooter = footerLines.map((line, index) => ({\n line,\n primary: primaryFooterIndexes.includes(index),\n }));\n const rowCount = () => (visibleTitle ? 1 : 0) + (visibleBlame ? 1 : 0) + visiblePreview.length + visibleFooter.length;\n\n while (rowCount() > height) {\n if (visibleBlame) {\n visibleBlame = undefined;\n continue;\n }\n if (visiblePreview.length > 1) {\n visiblePreview.pop();\n continue;\n }\n let optionalFooter = -1;\n for (let index = visibleFooter.length - 1; index >= 0; index -= 1) {\n if (!visibleFooter[index]?.primary) {\n optionalFooter = index;\n break;\n }\n }\n if (optionalFooter >= 0) {\n visibleFooter.splice(optionalFooter, 1);\n continue;\n }\n if (visibleTitle) {\n visibleTitle = undefined;\n continue;\n }\n if (visiblePreview.length > 0) {\n visiblePreview.pop();\n continue;\n }\n break;\n }\n\n return [\n ...(visibleTitle ? [visibleTitle] : []),\n ...(visibleBlame ? [visibleBlame] : []),\n ...visiblePreview,\n ...visibleFooter.map(({ line }) => line),\n ];\n}\n\nexport function fitRows(lines: string[], height: number): string[] {\n if (lines.length <= height) return lines;\n if (height <= 1) return lines.slice(0, 1);\n return [...lines.slice(0, height - 1), lines.at(-1) ?? \"\"];\n}\n\nfunction escapeTerminalControls(text: string): string {\n return [...text]\n .map((character) => {\n if (character === \"\\t\") return \" \";\n const code = character.charCodeAt(0);\n if (code <= 31 || (code >= 127 && code <= 159)) {\n return `\\\\x${code.toString(16).padStart(2, \"0\")}`;\n }\n return character;\n })\n .join(\"\");\n}\n\nexport function formatHistoryDate(authorTime: number): string {\n const date = new Date(authorTime * 1_000);\n return Number.isFinite(date.getTime()) ? date.toISOString().slice(0, 10) : \"unknown-date\";\n}\n\nexport function renderFileHistory(options: {\n width: number;\n availableRows: number;\n theme: Theme;\n path: string;\n history: readonly GitHistoryEntry[];\n index: number;\n error?: string;\n}): string[] {\n const { width, availableRows, theme, history, index: selectedIndex, error } = options;\n const listHeight = Math.max(1, availableRows - 3);\n const title = theme.fg(\"accent\", theme.bold(`File history \u00B7 ${safeHistoryText(options.path)}`));\n const start = Math.max(0, selectedIndex - listHeight + 1);\n const entries = history.slice(start, start + listHeight).map((entry, visibleIndex) => {\n const index = start + visibleIndex;\n const prefix = index === selectedIndex ? \"> \" : \" \";\n const date = formatHistoryDate(entry.authorTime);\n const line = `${prefix}${entry.commit.slice(0, 12)} \u00B7 ${date} \u00B7 ${safeHistoryText(entry.author)} \u00B7 ${safeHistoryText(entry.summary)}`;\n return truncateToWidth(index === selectedIndex ? theme.bg(\"selectedBg\", theme.fg(\"text\", line)) : line, width, \"\");\n });\n if (entries.length === 0) {\n entries.push(truncateToWidth(theme.fg(\"muted\", \" No file history\"), width, \"\"));\n }\n const footer = error ? safeHistoryText(error) : \"\u2191\u2193 navigate \u00B7 Enter open revision \u00B7 Esc preview\";\n return fitRows(\n [truncateToWidth(title, width, \"\"), ...entries, truncateToWidth(theme.fg(\"muted\", footer), width, \"\")],\n availableRows,\n );\n}\n", "import { safeTerminalText } from \"./file-browser.js\";\n\nconst MAX_SEARCH_QUERY_LENGTH = 256;\nconst MAX_SEARCH_QUERY_PARTS = 8;\nconst PATH_SCORE_PENALTY = 50;\nconst PREFIX_SCORE = 100;\nconst SUBSTRING_SCORE = 200;\nconst TYPO_SCORE = 300;\nconst SUBSEQUENCE_SCORE = 400;\nconst TOKENIZED_SCORE = 500;\nconst NO_MATCH = Number.POSITIVE_INFINITY;\nconst PATH_PART_SEPARATOR = /[/._\\-\\s]+/u;\n\ninterface ProjectFileEntry {\n path: string;\n normalizedPath: string;\n normalizedBasename: string;\n basenameParts: readonly string[];\n pathParts: readonly string[];\n originalIndex: number;\n}\n\ninterface RankedProjectFile {\n path: string;\n score: number;\n originalIndex: number;\n}\n\ntype TypoDistanceCache = Map<string, Map<string, number | undefined>>;\n\nexport class ProjectFileSearch {\n private readonly files: readonly string[];\n private readonly entries: readonly ProjectFileEntry[];\n\n constructor(files: readonly string[]) {\n this.files = [...files];\n this.entries = this.files.map((path, originalIndex) => {\n const normalizedPath = safeTerminalText(path).toLowerCase();\n const normalizedBasename = normalizedPath.slice(normalizedPath.lastIndexOf(\"/\") + 1);\n return {\n path,\n normalizedPath,\n normalizedBasename,\n basenameParts: splitPathParts(normalizedBasename),\n pathParts: splitPathParts(normalizedPath),\n originalIndex,\n };\n });\n }\n\n search(query: string): string[] {\n const trimmedQuery = safeTerminalText(query).trim();\n if (!trimmedQuery) return [...this.files];\n if (trimmedQuery.length > MAX_SEARCH_QUERY_LENGTH) return [];\n const normalizedQuery = trimmedQuery.toLowerCase();\n const queryParts = splitPathParts(normalizedQuery);\n const typoDistanceCache: TypoDistanceCache = new Map();\n\n return this.entries\n .flatMap((entry): RankedProjectFile[] => {\n const score = scoreEntry(normalizedQuery, queryParts, entry, typoDistanceCache);\n return Number.isFinite(score) ? [{ path: entry.path, score, originalIndex: entry.originalIndex }] : [];\n })\n .sort((left, right) => left.score - right.score || left.originalIndex - right.originalIndex)\n .map((result) => result.path);\n }\n}\n\nfunction scoreEntry(\n query: string,\n queryParts: readonly string[],\n entry: ProjectFileEntry,\n typoDistanceCache: TypoDistanceCache,\n): number {\n const basenameScore = scoreField(query, queryParts, entry.normalizedBasename, entry.basenameParts, typoDistanceCache);\n const pathScore = scoreField(query, queryParts, entry.normalizedPath, entry.pathParts, typoDistanceCache);\n return Math.min(basenameScore, pathScore + PATH_SCORE_PENALTY);\n}\n\nfunction scoreField(\n query: string,\n queryParts: readonly string[],\n text: string,\n textParts: readonly string[],\n typoDistanceCache: TypoDistanceCache,\n): number {\n const directScore = scoreText(query, text);\n if (directScore < TYPO_SCORE) return directScore;\n const typoScore = scoreTypo(query, textParts, typoDistanceCache);\n if (Number.isFinite(typoScore)) return Math.min(directScore, typoScore);\n if (Number.isFinite(directScore)) return directScore;\n return scoreTokenized(queryParts, textParts, typoDistanceCache);\n}\n\nfunction scoreTokenized(\n queryParts: readonly string[],\n candidateParts: readonly string[],\n typoDistanceCache: TypoDistanceCache,\n): number {\n if (queryParts.length < 2 || queryParts.length > MAX_SEARCH_QUERY_PARTS) return NO_MATCH;\n\n let totalScore = TOKENIZED_SCORE;\n for (const queryPart of queryParts) {\n let bestDirectScore = NO_MATCH;\n for (let index = 0; index < candidateParts.length; index += 1) {\n bestDirectScore = Math.min(bestDirectScore, scoreText(queryPart, candidateParts[index] ?? \"\") + index * 2);\n }\n const bestPartScore =\n bestDirectScore < TYPO_SCORE\n ? bestDirectScore\n : Math.min(bestDirectScore, scoreTypo(queryPart, candidateParts, typoDistanceCache));\n if (!Number.isFinite(bestPartScore)) return NO_MATCH;\n totalScore += bestPartScore;\n }\n return totalScore;\n}\n\nfunction scoreText(query: string, text: string): number {\n if (query === text) return 0;\n if (text.startsWith(query)) return PREFIX_SCORE + lengthPenalty(query, text);\n\n const substringIndex = text.indexOf(query);\n if (substringIndex >= 0) {\n return SUBSTRING_SCORE + substringIndex * 2 + lengthPenalty(query, text);\n }\n\n return scoreSubsequence(query, text);\n}\n\nfunction scoreSubsequence(query: string, text: string): number {\n let queryIndex = 0;\n let firstMatch = -1;\n let previousMatch = -1;\n let gaps = 0;\n let boundaryMatches = 0;\n let consecutiveMatches = 0;\n\n for (let textIndex = 0; textIndex < text.length && queryIndex < query.length; textIndex += 1) {\n if (text[textIndex] !== query[queryIndex]) continue;\n if (firstMatch < 0) firstMatch = textIndex;\n if (previousMatch >= 0) {\n const gap = textIndex - previousMatch - 1;\n gaps += gap;\n if (gap === 0) consecutiveMatches += 1;\n }\n if (textIndex === 0 || PATH_PART_SEPARATOR.test(text[textIndex - 1] ?? \"\")) {\n boundaryMatches += 1;\n }\n previousMatch = textIndex;\n queryIndex += 1;\n }\n\n if (queryIndex !== query.length) return NO_MATCH;\n return (\n SUBSEQUENCE_SCORE +\n gaps * 3 +\n firstMatch * 2 +\n lengthPenalty(query, text) -\n boundaryMatches * 8 -\n consecutiveMatches\n );\n}\n\nfunction scoreTypo(query: string, parts: readonly string[], typoDistanceCache: TypoDistanceCache): number {\n const maxDistance = allowedTypoDistance(query.length);\n if (maxDistance === 0) return NO_MATCH;\n\n let bestScore = NO_MATCH;\n for (let index = 0; index < parts.length; index += 1) {\n const part = parts[index] ?? \"\";\n if (Math.abs(query.length - part.length) > maxDistance) continue;\n const distance = cachedTypoDistance(query, part, maxDistance, typoDistanceCache);\n if (distance === undefined || distance === 0) continue;\n bestScore = Math.min(bestScore, TYPO_SCORE + distance * 20 + index * 2 + Math.abs(query.length - part.length));\n }\n return bestScore;\n}\n\nfunction cachedTypoDistance(\n query: string,\n part: string,\n maxDistance: number,\n cache: TypoDistanceCache,\n): number | undefined {\n let queryCache = cache.get(query);\n if (!queryCache) {\n queryCache = new Map();\n cache.set(query, queryCache);\n }\n if (queryCache.has(part)) return queryCache.get(part);\n const distance = boundedDamerauLevenshtein(query, part, maxDistance);\n queryCache.set(part, distance);\n return distance;\n}\n\nfunction boundedDamerauLevenshtein(left: string, right: string, maxDistance: number): number | undefined {\n if (Math.abs(left.length - right.length) > maxDistance) return undefined;\n\n const unreachable = maxDistance + 1;\n let previousPrevious = Array.from({ length: left.length + 1 }, () => unreachable);\n let previous = Array.from({ length: left.length + 1 }, (_, index) => (index <= maxDistance ? index : unreachable));\n\n for (let rightIndex = 1; rightIndex <= right.length; rightIndex += 1) {\n const current = Array.from({ length: left.length + 1 }, () => unreachable);\n if (rightIndex <= maxDistance) current[0] = rightIndex;\n const start = Math.max(1, rightIndex - maxDistance);\n const end = Math.min(left.length, rightIndex + maxDistance);\n for (let leftIndex = start; leftIndex <= end; leftIndex += 1) {\n const substitutionCost = left[leftIndex - 1] === right[rightIndex - 1] ? 0 : 1;\n current[leftIndex] = Math.min(\n (previous[leftIndex] ?? unreachable) + 1,\n (current[leftIndex - 1] ?? unreachable) + 1,\n (previous[leftIndex - 1] ?? unreachable) + substitutionCost,\n );\n if (\n leftIndex > 1 &&\n rightIndex > 1 &&\n left[leftIndex - 1] === right[rightIndex - 2] &&\n left[leftIndex - 2] === right[rightIndex - 1]\n ) {\n current[leftIndex] = Math.min(\n current[leftIndex] ?? unreachable,\n (previousPrevious[leftIndex - 2] ?? unreachable) + 1,\n );\n }\n }\n previousPrevious = previous;\n previous = current;\n }\n\n const distance = previous[left.length] ?? unreachable;\n return distance <= maxDistance ? distance : undefined;\n}\n\nfunction allowedTypoDistance(queryLength: number): number {\n if (queryLength < 5) return 0;\n return queryLength < 10 ? 1 : 2;\n}\n\nfunction splitPathParts(value: string): string[] {\n return value.split(PATH_PART_SEPARATOR).filter(Boolean);\n}\n\nfunction lengthPenalty(query: string, text: string): number {\n return Math.max(0, text.length - query.length) / 100;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Input", "Key", "matchesKey", "truncateToWidth", "visibleWidth", "visibleWidth", "visibleWidth", "isAbortError", "truncateToWidth", "truncateToWidth", "truncateToWidth", "escapeTerminalControls", "truncateToWidth", "fitRows", "selection", "capacity", "Input", "matchesKey", "Key", "visibleWidth", "fitRows", "truncateToWidth", "formatError", "isAbortError"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
|
+
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
|
+
import {
|
|
4
|
+
normalizeKeyId
|
|
5
|
+
} from "./chunk-OPGTWNJI.ts";
|
|
6
|
+
|
|
7
|
+
// src/file-context-menu.ts
|
|
8
|
+
async function showFileContextMenu(ctx, options) {
|
|
9
|
+
const { defineMenu, runMenu } = await import("@narumitw/pi-tui-kit");
|
|
10
|
+
if (!options.isCurrent() || options.signal.aborted) return { kind: "stale" };
|
|
11
|
+
let addRequested = false;
|
|
12
|
+
let selectedQuoteId;
|
|
13
|
+
const menu = defineMenu({
|
|
14
|
+
start: options.start === "remove" ? "selected" : "main",
|
|
15
|
+
screens: {
|
|
16
|
+
main: ({ state }) => ({
|
|
17
|
+
kind: "actions",
|
|
18
|
+
title: "File Context",
|
|
19
|
+
lines: [
|
|
20
|
+
`Next prompt context: ${state.quotes.length}/${state.maximumQuotes} snippets \xB7 ~${estimateTokens(state.totalBytes)} tokens`,
|
|
21
|
+
`Shortcut: ${formatShortcut(state.shortcut)}`
|
|
22
|
+
],
|
|
23
|
+
items: [
|
|
24
|
+
{
|
|
25
|
+
id: "add",
|
|
26
|
+
label: "Add context snippet",
|
|
27
|
+
description: "Browse project files and select lines",
|
|
28
|
+
action: "add",
|
|
29
|
+
busyLabel: "Scanning project files",
|
|
30
|
+
disabled: addDisabledReason(state) !== void 0,
|
|
31
|
+
disabledReason: addDisabledReason(state)
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "selected",
|
|
35
|
+
label: `Review selected context (${state.quotes.length})`,
|
|
36
|
+
description: "Preview exact snapshots before removing them",
|
|
37
|
+
to: "selected",
|
|
38
|
+
disabled: state.quotes.length === 0,
|
|
39
|
+
disabledReason: state.quotes.length === 0 ? "No context selected for the next prompt" : void 0
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: "settings",
|
|
43
|
+
label: "Settings",
|
|
44
|
+
description: "Configure the shortcut used to open File Context",
|
|
45
|
+
to: "settings",
|
|
46
|
+
disabled: state.quotes.length > 0,
|
|
47
|
+
disabledReason: state.quotes.length > 0 ? "Submit or remove selected context first; applying a shortcut reloads Pi" : void 0
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: "status",
|
|
51
|
+
label: "Status",
|
|
52
|
+
description: "Review selected context, limits, and active settings",
|
|
53
|
+
to: "status"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: "help",
|
|
57
|
+
label: "Help",
|
|
58
|
+
description: "Review shortcuts and attachment behavior",
|
|
59
|
+
to: "help"
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
hint: "close"
|
|
63
|
+
}),
|
|
64
|
+
selected: ({ state }) => state.quotes.length === 0 ? {
|
|
65
|
+
kind: "detail",
|
|
66
|
+
title: "Selected context",
|
|
67
|
+
lines: ["No context selected for the next prompt."],
|
|
68
|
+
hint: "back"
|
|
69
|
+
} : {
|
|
70
|
+
kind: "choice",
|
|
71
|
+
title: "Selected context",
|
|
72
|
+
lines: [`${state.quotes.length} snippets \xB7 Enter reviews the exact snapshot before removal`],
|
|
73
|
+
items: state.quotes.map((quote, index) => ({
|
|
74
|
+
id: quote.id,
|
|
75
|
+
label: `${index + 1}. ${quote.path}`,
|
|
76
|
+
description: `lines ${quote.startLine}-${quote.endLine} \xB7 ~${estimateTokens(Buffer.byteLength(quote.text, "utf8"))} tokens`,
|
|
77
|
+
details: [`Lines ${quote.startLine}-${quote.endLine} \xB7 Preview: ${singleLinePreview(quote.text)}`]
|
|
78
|
+
})),
|
|
79
|
+
action: "review",
|
|
80
|
+
viewportSize: 8,
|
|
81
|
+
hint: "back"
|
|
82
|
+
},
|
|
83
|
+
quote: ({ state }) => {
|
|
84
|
+
const quote = state.quotes.find((candidate) => candidate.id === selectedQuoteId);
|
|
85
|
+
if (!quote) {
|
|
86
|
+
return {
|
|
87
|
+
kind: "detail",
|
|
88
|
+
title: "Review context snippet",
|
|
89
|
+
lines: ["That snippet is no longer selected. Go back to refresh the list."],
|
|
90
|
+
hint: "back"
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
kind: "review",
|
|
95
|
+
title: "Review context snippet",
|
|
96
|
+
lines: [
|
|
97
|
+
quote.path,
|
|
98
|
+
`Lines ${quote.startLine}-${quote.endLine} \xB7 ~${estimateTokens(Buffer.byteLength(quote.text, "utf8"))} tokens`
|
|
99
|
+
],
|
|
100
|
+
content: quote.text,
|
|
101
|
+
format: { kind: "text" },
|
|
102
|
+
viewportSize: "adaptive",
|
|
103
|
+
confirm: {
|
|
104
|
+
id: "remove",
|
|
105
|
+
label: "Remove from next prompt",
|
|
106
|
+
action: "remove"
|
|
107
|
+
},
|
|
108
|
+
hint: "back"
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
settings: ({ state }) => state.settingsInvalidReason ? {
|
|
112
|
+
kind: "detail",
|
|
113
|
+
title: "File Context Settings \xB7 Read only",
|
|
114
|
+
lines: [
|
|
115
|
+
`Invalid settings file. Fix ${safeTerminalText(state.settingsPath)} before saving.`,
|
|
116
|
+
safeTerminalText(state.settingsInvalidReason)
|
|
117
|
+
],
|
|
118
|
+
hint: "back"
|
|
119
|
+
} : {
|
|
120
|
+
kind: "settings",
|
|
121
|
+
title: "File Context Settings",
|
|
122
|
+
lines: [
|
|
123
|
+
`User settings \xB7 ${safeTerminalText(state.settingsPath)}`,
|
|
124
|
+
"Saving reloads Pi so the new shortcut becomes active."
|
|
125
|
+
],
|
|
126
|
+
items: [
|
|
127
|
+
{
|
|
128
|
+
id: "openShortcut",
|
|
129
|
+
label: "Open shortcut",
|
|
130
|
+
description: "Set the global shortcut used to open the file browser.",
|
|
131
|
+
currentValue: state.shortcut ?? "none",
|
|
132
|
+
action: "open-shortcut"
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
hint: "back"
|
|
136
|
+
},
|
|
137
|
+
shortcut: ({ state }) => ({
|
|
138
|
+
kind: "input",
|
|
139
|
+
title: "File Context shortcut",
|
|
140
|
+
lines: [
|
|
141
|
+
`Configured: ${state.shortcut ?? "none"}`,
|
|
142
|
+
"Use a Pi key identifier such as ctrl+shift+x or f8.",
|
|
143
|
+
"Submit an empty value to disable the shortcut."
|
|
144
|
+
],
|
|
145
|
+
placeholder: state.shortcut ?? "",
|
|
146
|
+
action: "set-shortcut",
|
|
147
|
+
hint: "back"
|
|
148
|
+
}),
|
|
149
|
+
status: ({ state }) => ({
|
|
150
|
+
kind: "detail",
|
|
151
|
+
title: "File Context Status",
|
|
152
|
+
lines: [
|
|
153
|
+
`Next prompt context: ${state.quotes.length}/${state.maximumQuotes} snippets`,
|
|
154
|
+
`Estimated context: ~${estimateTokens(state.totalBytes)} tokens \xB7 ${state.totalBytes}/${state.maximumBytes} bytes`,
|
|
155
|
+
`Open shortcut: ${state.shortcut ?? "none"}`,
|
|
156
|
+
`User settings: ${safeTerminalText(state.settingsPath)}`,
|
|
157
|
+
...state.settingsInvalidReason ? [`Settings warning: ${safeTerminalText(state.settingsInvalidReason)}`] : []
|
|
158
|
+
],
|
|
159
|
+
hint: "back"
|
|
160
|
+
}),
|
|
161
|
+
help: () => ({
|
|
162
|
+
kind: "detail",
|
|
163
|
+
title: "File Context help",
|
|
164
|
+
lines: [
|
|
165
|
+
"Add context snippet opens the project browser. Select lines and press Enter to add and close, or A to add and keep browsing.",
|
|
166
|
+
"Selected context is attached in order to your next prompt, then cleared together.",
|
|
167
|
+
"Review selected context opens each exact snapshot before offering removal.",
|
|
168
|
+
"The configured shortcut and /file-context browse open the browser directly.",
|
|
169
|
+
"Settings saves the shortcut and reloads Pi; Status shows active limits and configuration.",
|
|
170
|
+
"Escape goes back. Ctrl+C closes File Context. Cancelling never changes selected context."
|
|
171
|
+
],
|
|
172
|
+
hint: "back"
|
|
173
|
+
})
|
|
174
|
+
},
|
|
175
|
+
actions: {
|
|
176
|
+
add: () => {
|
|
177
|
+
addRequested = true;
|
|
178
|
+
return { kind: "close" };
|
|
179
|
+
},
|
|
180
|
+
review: ({ itemId }) => {
|
|
181
|
+
selectedQuoteId = itemId;
|
|
182
|
+
return { kind: "to", screen: "quote" };
|
|
183
|
+
},
|
|
184
|
+
"open-shortcut": async () => ({ kind: "to", screen: "shortcut" }),
|
|
185
|
+
"set-shortcut": async ({ ctx: actionCtx, value, signal }) => {
|
|
186
|
+
const raw = value?.trim() || null;
|
|
187
|
+
const normalized = raw ? normalizeKeyId(raw) : void 0;
|
|
188
|
+
if (raw && !normalized) {
|
|
189
|
+
actionCtx.ui.notify(
|
|
190
|
+
`Invalid key identifier: ${safeTerminalText(raw)}. Use a Pi key identifier like ctrl+shift+x.`,
|
|
191
|
+
"warning"
|
|
192
|
+
);
|
|
193
|
+
return { kind: "stay" };
|
|
194
|
+
}
|
|
195
|
+
const shortcut = normalized ?? null;
|
|
196
|
+
try {
|
|
197
|
+
await options.saveShortcut(shortcut, signal);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
if (!signal.aborted && options.isCurrent()) {
|
|
200
|
+
actionCtx.ui.notify(
|
|
201
|
+
`Could not save File Context settings; the previous shortcut remains: ${safeTerminalText(formatError(error))}`,
|
|
202
|
+
"error"
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
return { kind: "stay" };
|
|
206
|
+
}
|
|
207
|
+
if (signal.aborted || !options.isCurrent()) return { kind: "close" };
|
|
208
|
+
actionCtx.ui.notify(
|
|
209
|
+
shortcut ? `Saved File Context shortcut ${safeTerminalText(shortcut)}. Reloading Pi\u2026` : "Disabled the File Context shortcut. Reloading Pi\u2026",
|
|
210
|
+
"info"
|
|
211
|
+
);
|
|
212
|
+
try {
|
|
213
|
+
await actionCtx.reload();
|
|
214
|
+
return { kind: "close" };
|
|
215
|
+
} catch (error) {
|
|
216
|
+
if (!signal.aborted && options.isCurrent()) {
|
|
217
|
+
actionCtx.ui.notify(
|
|
218
|
+
`File Context settings were saved, but Pi could not reload; run /reload to apply them: ${safeTerminalText(formatError(error))}`,
|
|
219
|
+
"error"
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
return { kind: "close" };
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
remove: async ({ signal }) => {
|
|
226
|
+
const itemId = selectedQuoteId;
|
|
227
|
+
if (!itemId) return { kind: "back" };
|
|
228
|
+
const result = await options.removeQuote(itemId, signal);
|
|
229
|
+
if (signal.aborted || !options.isCurrent()) return { kind: "close" };
|
|
230
|
+
if (result.kind === "missing") {
|
|
231
|
+
ctx.ui.notify("That snippet is no longer selected. The list was refreshed.", "warning");
|
|
232
|
+
return { kind: "stay" };
|
|
233
|
+
}
|
|
234
|
+
ctx.ui.notify(
|
|
235
|
+
`Removed from next prompt context: ${safeTerminalText(result.quote.path)} \xB7 lines ${result.quote.startLine}-${result.quote.endLine}.`,
|
|
236
|
+
"info"
|
|
237
|
+
);
|
|
238
|
+
selectedQuoteId = void 0;
|
|
239
|
+
return { kind: "back" };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
while (options.isCurrent() && !options.signal.aborted) {
|
|
244
|
+
addRequested = false;
|
|
245
|
+
const result = await runMenu(ctx, menu, {
|
|
246
|
+
getState: () => options.getState(),
|
|
247
|
+
signal: options.signal,
|
|
248
|
+
isCurrent: options.isCurrent,
|
|
249
|
+
onError: (_menuContext, error) => {
|
|
250
|
+
ctx.ui.notify(
|
|
251
|
+
`File Context menu failed: ${safeTerminalText(formatError(error))}. Selected context was kept; try again.`,
|
|
252
|
+
"error"
|
|
253
|
+
);
|
|
254
|
+
},
|
|
255
|
+
onUnsupportedMode: (_menuContext, mode) => {
|
|
256
|
+
ctx.ui.notify(`File Context is unavailable in ${mode} mode.`, "warning");
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
if (!addRequested || result.kind !== "closed") return result;
|
|
260
|
+
const addResult = await options.addQuote(options.signal);
|
|
261
|
+
if (!options.isCurrent() || options.signal.aborted) return { kind: "stale" };
|
|
262
|
+
if (addResult === "close") return { kind: "closed", reason: "close" };
|
|
263
|
+
}
|
|
264
|
+
return { kind: "stale" };
|
|
265
|
+
}
|
|
266
|
+
function addDisabledReason(state) {
|
|
267
|
+
if (state.quotes.length >= state.maximumQuotes) {
|
|
268
|
+
return `The ${state.maximumQuotes}-snippet limit is reached; review selected context first`;
|
|
269
|
+
}
|
|
270
|
+
if (state.totalBytes >= state.maximumBytes) {
|
|
271
|
+
return `The ${formatBytes(state.maximumBytes)} context limit is reached; review selected context first`;
|
|
272
|
+
}
|
|
273
|
+
return void 0;
|
|
274
|
+
}
|
|
275
|
+
function formatShortcut(shortcut) {
|
|
276
|
+
return shortcut ? shortcut.toUpperCase() : "Disabled (use /file-context browse)";
|
|
277
|
+
}
|
|
278
|
+
function singleLinePreview(text) {
|
|
279
|
+
const normalized = text.replaceAll("\r\n", "\n").replaceAll("\r", "\n").split("\n").join(" \u21B5 ");
|
|
280
|
+
const characters = [...normalized];
|
|
281
|
+
if (characters.length === 0) return "(empty)";
|
|
282
|
+
return characters.length <= 200 ? normalized : `${characters.slice(0, 199).join("")}\u2026`;
|
|
283
|
+
}
|
|
284
|
+
function estimateTokens(bytes) {
|
|
285
|
+
return bytes === 0 ? 0 : Math.max(1, Math.ceil(bytes / 4));
|
|
286
|
+
}
|
|
287
|
+
function formatBytes(bytes) {
|
|
288
|
+
return bytes % 1e3 === 0 ? `${bytes / 1e3} KB` : `${bytes} bytes`;
|
|
289
|
+
}
|
|
290
|
+
function safeTerminalText(text) {
|
|
291
|
+
return [...text].map((character) => {
|
|
292
|
+
const code = character.charCodeAt(0);
|
|
293
|
+
return code <= 31 || code >= 127 && code <= 159 ? `\\x${code.toString(16).padStart(2, "0")}` : character;
|
|
294
|
+
}).join("");
|
|
295
|
+
}
|
|
296
|
+
function formatError(error) {
|
|
297
|
+
return error instanceof Error ? error.message : String(error);
|
|
298
|
+
}
|
|
299
|
+
export {
|
|
300
|
+
showFileContextMenu
|
|
301
|
+
};
|
|
302
|
+
//# sourceMappingURL=file-context-menu-VPLHUUQ6.ts.map
|