✨ feat(vscode): 代码阅读预览问 AI 的回答里代码位置写成链接、点了能跳:提示词要求写 [名字](路径#符号) 或 [文件名:起-止](路径#L起-L止) 并给出仓库根,仓库链接认 #L 行号(注释里同一套),旧回答里整段是「路径:行」的行内代码也当链接,带行号的在预览里展开、闪包住那几行的块,不支持预览的用文本编辑器选中

This commit is contained in:
cruldra committed 2026-10-14 06:30:30 +11:00
1 parent ceeaad91a7
commit e401e4aec3
22 files changed
+516 -90

No files matched your search

+21 -13
View File
@@ -15,7 +15,7 @@ import type { ThemeColors } from '../theme/codeColors'
import type { IndexFind } from '../workspaceIndex'
import type { BlockFilter } from './blockFilter'
import type { FoundLocation } from './definitions'
import type { ChatKind, DefinitionPeek, ExtensionToWebview, Occurrence, Reveal, SymbolReference, WebviewToExtension } from './messages'
import type { ChatKind, DefinitionPeek, ExtensionToWebview, LineRange, Occurrence, Reveal, SymbolReference, WebviewToExtension } from './messages'
import type { TargetSpot } from './openTarget'
import type { TopSubject } from './pathPreview'
import { realpath } from 'node:fs/promises'
@@ -47,7 +47,7 @@ import { documentSymbolNodes } from './documentSymbols'
import { FIND_CONTEXT } from './findCommands'
import { NavigationContext, OCCURRENCES_CONTEXT } from './occurrenceNavigation'
import { occurrencesOf } from './occurrences'
import { languageOf, openingFor } from './openTarget'
import { languageOf, linesSpot, openingFor, revealOf } from './openTarget'
import { PATH_PREVIEW_SCHEME, topSubjectOf } from './pathPreview'
import { findRepoSymbol, isRepoImagePath, repoRootOf, resolveRepoEntry } from './repoPath'
@@ -650,7 +650,8 @@ class Preview {
return
}
const at = locateQa(subject.uri)
const block = at && this.sent && { path: at.promptPath, languageId: this.document.languageId, blocks: this.sent.blocks, source: this.sent.source, anchor }
const repoRoot = await repoRootOf(this.document.uri.fsPath)
const block = at && this.sent && { path: at.promptPath, languageId: this.document.languageId, blocks: this.sent.blocks, source: this.sent.source, anchor, ...(repoRoot !== undefined && { repoRoot }) }
const prompt = block && askPrompt(block, question)
const followUp = block && followUpPrompt(block, question)
const refused = prompt === undefined || followUp === undefined
@@ -754,7 +755,7 @@ class Preview {
await this.findOccurrences(msg.id, msg.version, msg.offset)
return
case 'openRepoLink':
await this.openRepoLink(msg.path, msg.symbol, msg.block)
await this.openRepoLink(msg.path, msg.symbol, msg.block, msg.lines)
return
case 'checkRepoLinks':
await this.checkRepoLinks(msg.id, msg.paths, msg.references)
@@ -985,10 +986,11 @@ class Preview {
}
/**
* 打开注释里的仓库链接:目录在代码阅读侧栏的树上定位,文件用编辑器打开。
* 带了符号就按文档符号的名字跳过去;文件或符号没有就不打开。没有路径的是不带路径的引用,按这份文件、从它写在的那块(block)找(见 resolveSymbolLink)。
* 打开注释、问 AI 的回答里的仓库链接:目录在代码阅读侧栏的树上定位,文件用编辑器打开。
* 带了符号就按文档符号的名字跳过去,带了几行(`lines`)就跳到这几行(见 [linesSpot]);文件或符号没有就不打开。
* 没有路径的是不带路径的引用,按这份文件、从它写在的那块(`block`)找(见 [resolveSymbolLink])。
*/
private async openRepoLink(rel: string | undefined, symbol?: string, block?: string): Promise<void> {
private async openRepoLink(rel: string | undefined, symbol?: string, block?: string, lines?: LineRange): Promise<void> {
const link = rel ?? `[${symbol}]`
try {
if (symbol !== undefined) {
@@ -1016,7 +1018,8 @@ class Preview {
this.markRepoLinkOpened(rel)
return
}
await this.openElsewhere(uri)
const spot = lines && await linesSpot(uri, lines)
await (spot ? this.showSpot(uri, spot) : this.openElsewhere(uri))
this.markRepoLinkOpened(rel)
}
catch (err) {
@@ -1071,14 +1074,19 @@ class Preview {
}
}
/** 跳到链接指的符号:在这份文件里就在本预览里滚过去、闪一下;别的文件同 ⌘ + 点击跳到定义(见 openElsewhere)。 */
/** 跳到链接指的符号:名字那段是要选中的范围,起点下标是预览要闪的定义处(见 [showSpot])。 */
private async showLinkTarget({ uri, selection }: LinkTarget): Promise<void> {
if (uri === this.document.uri.toString()) {
this.reveal({ line: this.document.positionAt(selection.startIndex).line, definition: selection.startIndex })
const doc = uri === this.document.uri.toString() ? this.document : await workspace.openTextDocument(Uri.parse(uri))
await this.showSpot(doc.uri, { range: new Range(doc.positionAt(selection.startIndex), doc.positionAt(selection.endIndex)), offset: selection.startIndex })
}
/** 跳到链接指的一处(符号或几行):在这份文件里就在本预览里滚过去、闪一下;别的文件同 ⌘ + 点击跳到定义(见 [openElsewhere])。 */
private async showSpot(uri: Uri, spot: TargetSpot): Promise<void> {
if (uri.toString() === this.document.uri.toString()) {
this.reveal(revealOf(spot))
return
}
const doc = await workspace.openTextDocument(Uri.parse(uri))
await this.openElsewhere(doc.uri, { range: new Range(doc.positionAt(selection.startIndex), doc.positionAt(selection.endIndex)), offset: selection.startIndex })
await this.openElsewhere(uri, spot)
}
private markRepoLinkBroken(path: string | undefined, symbol?: string, block?: string): void {