✨ feat(vscode): FastAPI 接口卡片的调用树带上前端调用它的地方

This commit is contained in:
cruldra committed 2026-10-12 12:22:51 +11:00
1 parent d4459e93b3
commit 29cedcb751
30 files changed
+1316 -130

No files matched your search

+21 -7
View File
@@ -1,8 +1,9 @@
import type { CustomTextEditorProvider, Disposable, DocumentSymbol, Event, TextDocument, TextDocumentShowOptions, WebviewPanel } from 'vscode'
import type { ClaudeProfile } from '../../cc/profiles'
import type { ClaudeImage } from '../../cc/spawnClaude'
import type { IndexFind } from '../callTree/endpoint'
import type { CommentEdit, RewriteOutcome, WriteResult } from '../commentRewrite'
import type { BlockKind, LocalSymbol, RuleLocation, RuleReference, SourceRange, WorkspaceIndex } from '../contract'
import type { BlockKind, LocalSymbol, RuleLocation, RuleReference, SourceRange } from '../contract'
import type { DiffBase } from '../diff/diffBase'
import type { OldDocument, SentDocument } from '../diff/previewDiff'
import type { WorkspaceEntries } from '../entries/workspaceEntries'
@@ -12,7 +13,6 @@ import type { CodeReaderRegistry } from '../registry'
import type { LookupSources } from '../ruleLookups'
import type { TreeSitterRuntime } from '../runtime'
import type { ImportedName, LinkTarget, SymbolNode } from '../symbolLinks'
import type { IndexedEntry } from '../workspaceIndex'
import type { BlockFilter } from './blockFilter'
import type { FoundLocation } from './definitions'
import type { DefinitionPeek, ExtensionToWebview, Occurrence, Reveal, WebviewToExtension } from './messages'
@@ -23,7 +23,7 @@ import { commands, EndOfLine, Position, Range, Uri, window, workspace, Workspace
import { logger } from '../../logging/logger'
import { webviewHtml, webviewUiRoot } from '../../webview/html'
import { DocumentCallees } from '../calleeKinds'
import { loadCallEdges } from '../callTree/query'
import { loadBlockCalls } from '../callTree/query'
import { CallTreeSession } from '../callTree/session'
import { findBlock, rewriteBlockComment } from '../commentRewrite'
import { PreviewDiff } from '../diff/previewDiff'
@@ -82,8 +82,8 @@ export class PreviewEditorProvider implements CustomTextEditorProvider {
readonly qa: CodeQa,
/** 工作区里别的文件定义的、原名叫 name 的中文名(languageId 是查的这份文档的语言) */
readonly indexedNames: (languageId: string, name: string) => Promise<IndexedName[]>,
/** 库规则的工作区索引里键是 key 的各项(规则查名字的定义时用,见 ruleLookups.ts) */
readonly indexed: (index: WorkspaceIndex, key: string) => Promise<IndexedEntry[]>,
/** 工作区索引里键是 key 的各项(规则查名字的定义时用,见 ruleLookups.ts;接口的调用树查契约和前端请求时用) */
readonly indexed: IndexFind,
/** 预览标差异时对比什么 */
readonly diffBases: DiffBases,
/** 哪些文件是项目写明的入口、预览里哪些名字的块标成入口 */
@@ -189,7 +189,7 @@ class Preview {
private readonly rewriteStops = new Map<string, AbortController>()
/** 最近一次发出去的文档(版本、块树、源码):问 AI 时按块的记号在里面找那块代码,对比基准变了时拿它重新比 */
private sent: SentDocument | undefined
/** 函数、类落在几棵调用树里。文档发出去之后再数,不挡住第一次预览 */
/** 能看调用树的块(函数、类、接口卡片)落在几棵调用树里。文档发出去之后再数,不挡住第一次预览 */
private readonly callTrees = new CallTreeSession(
message => this.post(message),
() => {
@@ -198,7 +198,7 @@ class Preview {
return {
version: this.sent.version,
blocks: this.sent.blocks,
load: (offset, cancelled) => loadCallEdges(this.document, offset, cancelled),
load: (block, cancelled) => loadBlockCalls(this.document, block, this.owner.indexed, cancelled),
}
},
)
@@ -630,6 +630,9 @@ class Preview {
case 'openCallTree':
this.callTrees.open(msg.version, msg.anchor)
return
case 'goToCallNode':
await this.goToCallNode(Uri.parse(msg.uri), new Position(msg.line, msg.character))
return
case 'occurrenceNavigation':
this.owner.navigation.update(this, msg.available)
}
@@ -777,6 +780,17 @@ class Preview {
await open()
}
/** 点了调用树上的一个节点:打开它在的文件,滚到这一处(同 ⌘ + 点击跳到别的文件)。 */
private async goToCallNode(uri: Uri, position: Position): Promise<void> {
try {
const target = await workspace.openTextDocument(uri)
await this.openElsewhere(uri, { range: new Range(position, position), offset: target.offsetAt(position) })
}
catch (err) {
logger.add({ level: 'warn', source: 'codeReader', message: `调用树里的 ${uri.toString()} 打不开:${err instanceof Error ? err.message : String(err)}` })
}
}
/** 预览里这批仓库路径,哪些文件或目录不在;这批不带路径的引用,哪些找不到。 */
private async checkRepoLinks(id: number, paths: string[], symbols: string[]): Promise<void> {
const root = await repoRootOf(this.document.uri.fsPath)