Files
superwork/vscode/src/codeReader/editor/pathPreview.ts
T
cruldra 880bf7fc57 ✨ feat(vscode): 新增「了解一块代码」:AI 找功能代码占一栏,对话里接着改
主栏标题栏的放大镜问要了解哪一块,占一个栏位建一栏(和收藏共用 30 个栏位,视图改名 slot1..30,按 slotKindN 分收藏 / 功能挂标题栏按钮),同时开对话页让 Claude 只读地在全部工作区文件夹里找,按 --json-schema 交回环节 → 文件 + 符号 + 一句话。
对话复用预览顶部的聊天(CodeQa.askTop:会话续接、进行中的一轮、记录存 workspaceState);结构不合格算这一轮没答成、留着能再画出来。
条目每次画、点时按眼下的代码找:有语言插件的解析成代码块按「类名.方法名」找,没有的问 VS Code 文档符号;找不到画成灰的。
2026-10-12 15:48:54 +11:00

83 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 文件夹、以及代码阅读不认识的文件,用这个协议打开代码阅读预览:
* 文档是空的,页面上没有代码块,只在顶部聊天。源码文件直接开它自己的预览。
* 「了解一块代码」找的功能的对话页也用这个协议,只是对的不是路径,是功能。
*/
import type { WorkspaceFolder } from 'vscode'
import * as path from 'node:path'
import { Uri, workspace } from 'vscode'
import { featureQaKey, pathQaKey, relativeQaKey } from '../qa/pathQa'
export const PATH_PREVIEW_SCHEME = 'code-reader-path'
export type PathSubject = 'file' | 'folder'
/** 预览顶部的聊天问的是什么:文件、文件夹,或「了解一块代码」找的一个功能 */
export type TopSubject = PathSubject | 'feature'
/** 功能对话页的查询串:后面跟着功能的 id */
const FEATURE_QUERY = 'feature='
/** 「了解一块代码」一个功能的对话页:路径是问的那句话(标签页上显示它,`/` 换成全角的免得被当成目录),查询串带着功能的 id。 */
export function featurePageUri(id: string, question: string): Uri {
return Uri.from({ scheme: PATH_PREVIEW_SCHEME, path: `/${question.replaceAll('/', '/')}`, query: `${FEATURE_QUERY}${id}` })
}
/** 一个功能的问答按这个 Uri 记、按它对事件:对话页标签上叫什么都是它。 */
export function featureSubjectUri(id: string): Uri {
return Uri.from({ scheme: PATH_PREVIEW_SCHEME, path: '/', query: `${FEATURE_QUERY}${id}` })
}
/** 功能对话页(或 featureSubjectUri)对的功能 id;别的 Uri 没有。 */
export function featureIdOf(uri: Uri): string | undefined {
return uri.scheme === PATH_PREVIEW_SCHEME && uri.query.startsWith(FEATURE_QUERY) ? uri.query.slice(FEATURE_QUERY.length) : undefined
}
export function pathPreviewUri(target: Uri, kind: PathSubject): Uri {
return target.with({ scheme: PATH_PREVIEW_SCHEME, query: kind, fragment: '' })
}
/** 预览文档是路径页时,还原成真实文件或文件夹;普通源码预览不是。 */
export function pathPreviewOf(uri: Uri): { uri: Uri, kind: PathSubject } | undefined {
if (uri.scheme !== PATH_PREVIEW_SCHEME)
return undefined
if (uri.query !== 'file' && uri.query !== 'folder')
return undefined
return { uri: uri.with({ scheme: 'file', query: '', fragment: '' }), kind: uri.query }
}
/** 预览这一页顶部问的是什么:功能对话页是那个功能(featureSubjectUri),路径页还原成真实文件或文件夹,源码预览就是文档自己。 */
export function topSubjectOf(uri: Uri): { uri: Uri, kind: TopSubject } {
const feature = featureIdOf(uri)
if (feature !== undefined)
return { uri: featureSubjectUri(feature), kind: 'feature' }
return pathPreviewOf(uri) ?? { uri, kind: 'file' }
}
/**
* 这条路径在哪个工作区文件夹、相对路径是什么。
* 工作区根本身的相对路径是空字符串(locate 不认根,顶部问答要认)。
*/
export function pathQaLocation(uri: Uri): { folder: WorkspaceFolder, key: string } | undefined {
const folder = workspace.getWorkspaceFolder(uri)
if (!folder)
return undefined
const key = relativeQaKey(path.posix.normalize(folder.uri.path), path.posix.normalize(uri.path))
return key === undefined ? undefined : { folder, key }
}
/**
* 顶部问答记在哪:在哪个工作区文件夹(claude 在它里面跑,带的图片存在它的 `.spx/code-qa/`)、记录表里的键(见 pathQa.ts)。
* 文件、文件夹按「工作区文件夹 + 相对路径」;功能对话页按功能的 id,记在第一个工作区文件夹。不在工作区里、没打开文件夹时没有。
*/
export function topQaLocation(uri: Uri): { folder: WorkspaceFolder, key: string } | undefined {
const feature = featureIdOf(uri)
if (feature !== undefined) {
const folder = workspace.workspaceFolders?.[0]
return folder && { folder, key: featureQaKey(feature) }
}
const at = pathQaLocation(uri)
return at && { folder: at.folder, key: pathQaKey(at.folder.uri.toString(), at.key) }
}