✨ feat(vscode): 定义卡片底部带上那块问过 AI 的问答,点问题展开回答
This commit is contained in:
1 parent
fdf7a35b18
commit
b99659ea68
10 files changed
+336
-46
No files matched your search
@@ -1,11 +1,12 @@
|
||||
import type { CustomTextEditorProvider, Disposable, TextDocument, TextDocumentShowOptions, WebviewPanel } from 'vscode'
|
||||
import type { ClaudeImage } from '../../cc/spawnClaude'
|
||||
import type { BlockView } from '../blockView'
|
||||
import type { CommentEdit, CommentJob, WriteResult } from '../commentRewrite'
|
||||
import type { BlockKind, LocalSymbol, RuleLocation, RuleReference, SourceRange } from '../contract'
|
||||
import type { OpenedFrom, PreviewDiffBases } from '../diff/diffBase'
|
||||
import type { OldDocument, SentDocument } from '../diff/previewDiff'
|
||||
import type { WorkspaceEntries } from '../entries/workspaceEntries'
|
||||
import type { DefinitionStart, IndexedName, NameSources } from '../nameResolution'
|
||||
import type { DefinitionStart, IndexedName, NameSources, ShownName } from '../nameResolution'
|
||||
import type { CodeQa, TopRequest } from '../qa/codeQa'
|
||||
import type { CodeReaderRegistry } from '../registry'
|
||||
import type { LookupSources } from '../ruleLookups'
|
||||
@@ -196,14 +197,13 @@ export class PreviewEditorProvider implements CustomTextEditorProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* 预览页面能读的本地目录:页面自己的脚本和样式;问答带的图片所在的目录(工作区文件夹的 .spx/code-qa/),历史里才画得出缩略图;
|
||||
* 注释、回答里的仓库图片所在的各个根(见 [linkBaseOf]),根的真实位置和这个路径不一样时两个都放,读不到真实位置就只放这个路径。
|
||||
* 预览页面能读的本地目录:页面自己的脚本和样式;问答带的图片所在的目录(各工作区文件夹的 `.spx/code-qa/`,见 [CodeQa.imageRoots]),
|
||||
* 历史和定义卡片里才画得出缩略图;注释、回答里的仓库图片所在的各个根(见 [linkBaseOf]),根的真实位置和这个路径不一样时两个都放,读不到真实位置就只放这个路径。
|
||||
*/
|
||||
private async readableRoots(uri: Uri): Promise<Uri[]> {
|
||||
const imageRoot = this.qa.imageRoot(topSubjectOf(uri).uri)
|
||||
const { roots } = await linkBaseOf(uri)
|
||||
const repoRoots = await Promise.all(roots.map(async root => [root, await realpath(root).catch(() => root)]))
|
||||
return [webviewUiRoot(this.extensionUri), ...(imageRoot ? [imageRoot] : []), ...[...new Set(repoRoots.flat())].map(root => Uri.file(root))]
|
||||
return [webviewUiRoot(this.extensionUri), ...this.qa.imageRoots(), ...[...new Set(repoRoots.flat())].map(root => Uri.file(root))]
|
||||
}
|
||||
|
||||
/** 「跳到下一处 / 上一处高亮」:发给能跳的那个预览,从命令面板运行时发给活动的预览。 */
|
||||
@@ -659,7 +659,12 @@ class Preview {
|
||||
if (!this.ready)
|
||||
return
|
||||
const subject = this.subject()
|
||||
this.post(this.owner.qa.view(subject.uri, file => this.panel.webview.asWebviewUri(file).toString(), subject.kind))
|
||||
this.post(this.owner.qa.view(subject.uri, file => this.webviewUrl(file), subject.kind))
|
||||
}
|
||||
|
||||
/** 本地文件 `file` 在这个预览页面里能直接用的地址(`webview.asWebviewUri`)。 */
|
||||
private webviewUrl(file: Uri): string {
|
||||
return this.panel.webview.asWebviewUri(file).toString()
|
||||
}
|
||||
|
||||
/** 这一页顶部问的是什么(见 topSubjectOf)。 */
|
||||
@@ -926,18 +931,16 @@ class Preview {
|
||||
try {
|
||||
const target = await workspace.openTextDocument(uri)
|
||||
const line = target.positionAt(offset).line
|
||||
const path = workspace.asRelativePath(uri)
|
||||
const file = uri.toString()
|
||||
if (file === this.document.uri.toString()) {
|
||||
if (uri.toString() === this.document.uri.toString()) {
|
||||
const { sent } = this
|
||||
if (sent?.version !== target.version)
|
||||
return undefined
|
||||
const block = peekBlock(sent.blocks, offset, line)
|
||||
return block && { path, uri: file, line, block: pagePeekBlock(block, sent.source), names: namesOnCard(block, this.names.known(target.version)) }
|
||||
return block && this.peekCard(uri, line, block, sent.source, namesOnCard(block, this.names.known(target.version)))
|
||||
}
|
||||
const { message, displayNames } = await this.owner.readElsewhere(target)
|
||||
const block = message.error === undefined ? peekBlock(message.blocks, offset, line) : undefined
|
||||
return block && { path, uri: file, line, block: pagePeekBlock(block, message.source), names: namesOnCard(block, definitionSiteNames(displayNames)) }
|
||||
return block && this.peekCard(uri, line, block, message.source, namesOnCard(block, definitionSiteNames(displayNames)))
|
||||
}
|
||||
catch (err) {
|
||||
logger.add({ level: 'warn', source: 'codeReader', message: `没能读出 ${uri.toString()} 里定义的那块:${err instanceof Error ? err.message : String(err)}` })
|
||||
@@ -945,6 +948,15 @@ class Preview {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* `uri` 第 `line` 行的定义所在那块 `block`(`source` 是那份文件的源码)发给页面的卡片,带上 `names` 和这块自己下面问过 AI 的各次。
|
||||
* 问答按那份文件和这块在那份文件块树里的记号(`block.anchor`,同那个文件的预览挂对话用的)找,子块上问的记号不同,不带。
|
||||
*/
|
||||
private peekCard(uri: Uri, line: number, block: BlockView, source: string, names: ShownName[]): DefinitionPeek {
|
||||
const qa = this.owner.qa.blockThreads(uri, file => this.webviewUrl(file)).find(thread => thread.anchor === block.anchor)?.entries
|
||||
return { path: workspace.asRelativePath(uri), uri: uri.toString(), line, block: pagePeekBlock(block, source), names, ...(qa && { qa }) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 在预览所在的编辑器组打开别的文件,和普通编辑器里 ⌘ + 点击一样:语言有代码阅读的用预览打开(新开的不比,已经开着的照旧),给了 spot 就滚过去、闪这处;
|
||||
* 其余用 VS Code 默认的打开方式,给了 spot 就选中它(见 openingFor)。目标是否按「预览标签」打开听 VS Code 的设置,
|
||||
@@ -1002,7 +1014,7 @@ class Preview {
|
||||
const entry = await resolveRepoEntry(place.root, place.rel)
|
||||
if (!entry || entry.isDirectory)
|
||||
return { path: rel }
|
||||
const src = this.panel.webview.asWebviewUri(Uri.file(entry.fsPath)).toString()
|
||||
const src = this.webviewUrl(Uri.file(entry.fsPath))
|
||||
return { path: rel, src }
|
||||
}))
|
||||
this.post({ type: 'repoImagesChecked', id, images })
|
||||
|
||||
Reference in new issue
Block a user