⚡ perf(vscode): 代码阅读预览注释里的引用解析过就记着:标坏链接、悬停、点击同一个引用只问一次 Pylance,同时问的等同一个结果,文档版本或块树、导入、用到的名字换了才作废,指到的别的文件改过再问,找不到和语言自带的不留;悬停看别的文件里的定义时读成的文档各预览共用,同一版不再重新解析,留最近 8 份,注册的插件变了全部重读

This commit is contained in:
cruldra committed 2026-10-14 19:57:20 +11:00
1 parent 3983032356
commit cfde0fedf5
9 files changed
+595 -70

No files matched your search

@@ -6,7 +6,8 @@ import type { SymbolNode } from '../symbolLinks'
import type { CodeColors } from '../theme/codeColors'
import type { ExtensionToWebview, WebviewToExtension } from './messages'
import { describe, expect, it, vi } from 'vitest'
import { commands, window, workspace } from 'vscode'
import { commands, Range, Uri, window, workspace } from 'vscode'
import { languageDefinitions } from './definitions'
import { documentMessage } from './documentMessage'
import { documentSymbolNodes } from './documentSymbols'
import { FIND_CONTEXT } from './findCommands'
@@ -22,6 +23,8 @@ vi.mock('vscode', () => ({
getConfiguration: () => ({ get: (_key: string, fallback: unknown) => fallback }),
openTextDocument: vi.fn(),
applyEdit: vi.fn(async () => true),
textDocuments: [],
asRelativePath: (uri: { fsPath: string }) => uri.fsPath,
},
/** 记下换了哪儿、换成什么 */
WorkspaceEdit: class {
@@ -33,7 +36,10 @@ vi.mock('vscode', () => ({
get start() { return { line: this.startLine, character: this.startCharacter } }
get end() { return { line: this.endLine, character: this.endCharacter } }
},
Uri: { file: (fsPath: string) => ({ fsPath, scheme: 'file', toString: () => `file://${fsPath}` }) },
Uri: {
file: (fsPath: string) => ({ fsPath, scheme: 'file', toString: () => `file://${fsPath}` }),
parse: (value: string) => ({ fsPath: value.replace('file://', ''), scheme: 'file', toString: () => value }),
},
EndOfLine: { LF: 1, CRLF: 2 },
}))
vi.mock('../../logging/logger', () => ({ logger: { add: vi.fn() } }))
@@ -55,6 +61,11 @@ vi.mock('./documentMessage', async importOriginal => ({
}))
/** 文档符号由各个测试给 */
vi.mock('./documentSymbols', () => ({ documentSymbolNodes: vi.fn(async () => []) }))
/** 语言扩展答的定义由各个测试给,默认没答 */
vi.mock('./definitions', async importOriginal => ({
...await importOriginal<typeof import('./definitions')>(),
languageDefinitions: vi.fn(async () => []),
}))
/** 仓库在 /workspace,里面只有这几个文件 */
vi.mock('./repoPath', async importOriginal => ({
...await importOriginal<typeof import('./repoPath')>(),
@@ -74,7 +85,7 @@ function preview(rewrite: (uri: unknown, request: RewriteRequest) => Promise<str
const qa = { imageRoot: () => undefined, onDidChange: subscribe, onDidAnswer: subscribe, onDidRewrite: subscribe, profiles: { ask: { subscribe }, rewrite: { subscribe } }, rewrite: vi.fn(rewrite) }
const provider = new PreviewEditorProvider(...[
{},
{},
{ onDidChange: subscribe },
{},
{ subscribe },
{ subscribe },
@@ -211,7 +222,7 @@ function opening(profiles = { ask: profileSet(''), rewrite: profileSet('') }, co
}
const provider = new PreviewEditorProvider(...[
{},
{ selectedTranslator: () => undefined, languageFor },
{ selectedTranslator: () => undefined, languageFor, onDidChange: subscribe },
{},
{ subscribe, current: { excluded: {}, onlyChanges: false } },
colors,
@@ -587,6 +598,50 @@ describe('注释里不带路径的引用按它写在哪块的注释里找', () =
expect(page.posted()).toContainEqual({ type: 'repoLinkBuiltin', symbol: 'Error', block: HELPER })
expect(page.posted()).not.toContainEqual(expect.objectContaining({ type: 'repoLinkBroken' }))
})
it('检查过的引用再悬停、再点:文档符号、定义都只问一次;悬停两次,定义所在的别的文件也只读一次', async () => {
const BUILTINS = '/typeshed/builtins.pyi'
const builtins = { uri: Uri.file(BUILTINS), version: 1, languageId: 'python', fileName: BUILTINS, getText: () => 'class RuntimeError: ...', positionAt: () => ({ line: 0, character: 6 }), offsetAt: () => 6 }
vi.mocked(documentMessage).mockImplementationOnce(async input => ({
message: { type: 'document', version: input.version, languageId: input.languageId, blocks: [declared(HELPER, 950)], source: '', colors: { roles: [], runs: [] }, attributes: [], translators: [], translatorId: '', names: [] },
displayNames: [],
symbols: [],
imports: [{ name: 'RuntimeError', offset: 7, range: { startIndex: 0, endIndex: 20 } }],
kinds: [],
bindings: [],
}) as never)
vi.mocked(documentSymbolNodes).mockReset().mockResolvedValue([symbol('helper', 950, 990)])
vi.mocked(languageDefinitions).mockClear().mockResolvedValue([{ uri: builtins.uri, range: new Range(0, 6, 0, 18) }] as never)
const { provider, document } = opening()
Object.assign(document, { positionAt: (offset: number) => ({ line: 0, character: offset }) })
Object.assign(workspace, { textDocuments: [document, builtins] })
vi.mocked(workspace.openTextDocument).mockImplementation((async (uri: { toString: () => string }) => uri.toString() === builtins.uri.toString() ? builtins : document) as never)
try {
const page = tab()
provider.resolveCustomTextEditor(document as never, page.panel)
await page.send({ type: 'ready' })
await vi.waitFor(() => expect(page.posted()).toContainEqual(expect.objectContaining({ type: 'document' })))
vi.mocked(documentMessage).mockClear()
const reference = { symbol: 'RuntimeError', block: HELPER }
await page.send({ type: 'checkRepoLinks', id: 1, paths: [], references: [reference] })
expect(page.posted()).toContainEqual({ type: 'repoLinksChecked', id: 1, missing: [], unresolved: [], builtin: [] })
await page.send({ type: 'peekLink', id: 2, ...reference })
await page.send({ type: 'peekLink', id: 3, ...reference })
await page.send({ type: 'openRepoLink', ...reference })
expect(page.posted()).toContainEqual(expect.objectContaining({ type: 'repoLinkOpened', ...reference }))
expect(commands.executeCommand).toHaveBeenCalledWith('vscode.open', expect.objectContaining({ fsPath: BUILTINS }), expect.anything())
expect(documentSymbolNodes).toHaveBeenCalledTimes(1)
expect(languageDefinitions).toHaveBeenCalledTimes(1)
expect(documentMessage).toHaveBeenCalledTimes(1)
expect(documentMessage).toHaveBeenCalledWith(expect.objectContaining({ fileName: BUILTINS }), expect.anything(), expect.anything(), expect.any(Function))
}
finally {
Object.assign(workspace, { textDocuments: [] })
vi.mocked(workspace.openTextDocument).mockReset()
}
})
})
describe('点了带几行的仓库链接', () => {