⚡ perf(vscode): 查到的定义落到名字上时只读定义那一段,不把目标文件整份取出来
This commit is contained in:
1 parent
0070933599
commit
6e2c541558
2 files changed
+51
-6
No files matched your search
@@ -1,10 +1,13 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { definitionOffset } from './definitions'
|
||||
import { commands, workspace } from 'vscode'
|
||||
import { definitionOffset, languageDefinitions } from './definitions'
|
||||
|
||||
vi.mock('vscode', () => ({
|
||||
commands: { executeCommand: vi.fn() },
|
||||
EventEmitter: class EventEmitter { event = vi.fn(); fire = vi.fn() },
|
||||
Range: class Range {},
|
||||
Range: class Range {
|
||||
constructor(readonly start: { offset: number }, readonly end: { offset: number }) {}
|
||||
},
|
||||
Uri: { parse: vi.fn() },
|
||||
window: { createOutputChannel: vi.fn(() => ({ appendLine: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() })) },
|
||||
workspace: { openTextDocument: vi.fn(), asRelativePath: vi.fn() },
|
||||
@@ -40,3 +43,39 @@ describe('定义范围的起点不在名字上时,用范围里那个名字', (
|
||||
expect(definitionOffset(text, { start: 0, end: text.length }, undefined, 'fetchAppDeployments')).toBe(text.lastIndexOf('fetchAppDeployments'))
|
||||
})
|
||||
})
|
||||
|
||||
/** 假的文档:位置就是下标;记下 getText 每次取了多长。 */
|
||||
function fakeDocument(uri: string, text: string): { reads: number[] } {
|
||||
const reads: number[] = []
|
||||
const at = (offset: number) => ({ offset })
|
||||
const document = {
|
||||
uri: { toString: () => uri },
|
||||
offsetAt: (position: { offset: number }) => position.offset,
|
||||
positionAt: (offset: number) => at(Math.max(0, Math.min(offset, text.length))),
|
||||
getText: (range?: { start: { offset: number }, end: { offset: number } }) => {
|
||||
const read = range ? text.slice(range.start.offset, range.end.offset) : text
|
||||
reads.push(read.length)
|
||||
return read
|
||||
},
|
||||
getWordRangeAtPosition: (position: { offset: number }) => {
|
||||
const start = text.slice(0, position.offset).search(/\w+$/)
|
||||
const end = position.offset + (/^\w*/.exec(text.slice(position.offset))?.[0].length ?? 0)
|
||||
return { start: at(start < 0 ? position.offset : start), end: at(end) }
|
||||
},
|
||||
}
|
||||
vi.mocked(workspace.openTextDocument).mockImplementation((async (target: { toString: () => string }) => target.toString() === uri ? document : undefined) as never)
|
||||
return { reads }
|
||||
}
|
||||
|
||||
describe('查到的定义落到名字上', () => {
|
||||
it('只读定义那一段(前后各多一个字认名字的边界),不把目标文件整份取出来', async () => {
|
||||
const text = `${'# 很长的文件\n'.repeat(2000)}def fetch_app(x):\n return fetch_app(x)\n`
|
||||
const { reads } = fakeDocument('file:///w/a.py', text)
|
||||
const call = text.lastIndexOf('fetch_app')
|
||||
const declaration = text.indexOf('def fetch_app')
|
||||
vi.mocked(commands.executeCommand).mockResolvedValue([{ uri: { toString: () => 'file:///w/a.py' }, range: { start: { offset: declaration }, end: { offset: text.indexOf(':', declaration) } } }] as never)
|
||||
const [found] = await languageDefinitions({ toString: () => 'file:///w/a.py' } as never, { offset: call } as never)
|
||||
expect((found.range.start as unknown as { offset: number }).offset).toBe(text.indexOf('fetch_app', declaration))
|
||||
expect(Math.max(...reads)).toBeLessThan(40)
|
||||
})
|
||||
})
|
||||
@@ -108,16 +108,22 @@ async function rangeOnName(uri: Uri, range: Range, selection: Range | undefined,
|
||||
return fallback
|
||||
try {
|
||||
const document = await workspace.openTextDocument(uri)
|
||||
const text = document.getText()
|
||||
const start = document.offsetAt(range.start)
|
||||
const end = document.offsetAt(range.end)
|
||||
const selected = selection && { start: document.offsetAt(selection.start), end: document.offsetAt(selection.end) }
|
||||
// 只取定义这一段,前后各多一个字(认名字的边界):目标文件可能很大,每处定义都整份取一遍太费
|
||||
const from = Math.max(0, Math.min(start, selected?.start ?? start) - 1)
|
||||
const to = Math.max(end, (selected?.start ?? start) + name.length) + 1
|
||||
const text = document.getText(new Range(document.positionAt(from), document.positionAt(to)))
|
||||
const offset = definitionOffset(
|
||||
text,
|
||||
{ start: document.offsetAt(range.start), end: document.offsetAt(range.end) },
|
||||
selection ? { start: document.offsetAt(selection.start), end: document.offsetAt(selection.end) } : undefined,
|
||||
{ start: start - from, end: end - from },
|
||||
selected && { start: selected.start - from, end: selected.end - from },
|
||||
name,
|
||||
)
|
||||
if (!onName(text, offset, name))
|
||||
return fallback
|
||||
return new Range(document.positionAt(offset), document.positionAt(offset + name.length))
|
||||
return new Range(document.positionAt(from + offset), document.positionAt(from + offset + name.length))
|
||||
}
|
||||
catch (err) {
|
||||
logger.add({ level: 'warn', source: 'codeReader', message: `读不到定义所在的 ${uri.toString()}:${err instanceof Error ? err.message : String(err)}` })
|
||||
|
||||
Reference in new issue
Block a user