⚡ 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 { describe, expect, it, vi } from 'vitest'
|
||||||
import { definitionOffset } from './definitions'
|
import { commands, workspace } from 'vscode'
|
||||||
|
import { definitionOffset, languageDefinitions } from './definitions'
|
||||||
|
|
||||||
vi.mock('vscode', () => ({
|
vi.mock('vscode', () => ({
|
||||||
commands: { executeCommand: vi.fn() },
|
commands: { executeCommand: vi.fn() },
|
||||||
EventEmitter: class EventEmitter { event = vi.fn(); fire = 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() },
|
Uri: { parse: vi.fn() },
|
||||||
window: { createOutputChannel: vi.fn(() => ({ appendLine: vi.fn(), info: vi.fn(), warn: vi.fn(), error: 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() },
|
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'))
|
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
|
return fallback
|
||||||
try {
|
try {
|
||||||
const document = await workspace.openTextDocument(uri)
|
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(
|
const offset = definitionOffset(
|
||||||
text,
|
text,
|
||||||
{ start: document.offsetAt(range.start), end: document.offsetAt(range.end) },
|
{ start: start - from, end: end - from },
|
||||||
selection ? { start: document.offsetAt(selection.start), end: document.offsetAt(selection.end) } : undefined,
|
selected && { start: selected.start - from, end: selected.end - from },
|
||||||
name,
|
name,
|
||||||
)
|
)
|
||||||
if (!onName(text, offset, name))
|
if (!onName(text, offset, name))
|
||||||
return fallback
|
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) {
|
catch (err) {
|
||||||
logger.add({ level: 'warn', source: 'codeReader', message: `读不到定义所在的 ${uri.toString()}:${err instanceof Error ? err.message : String(err)}` })
|
logger.add({ level: 'warn', source: 'codeReader', message: `读不到定义所在的 ${uri.toString()}:${err instanceof Error ? err.message : String(err)}` })
|
||||||
|
|||||||
Reference in new issue
Block a user