🐛 fix(vscode): 代码阅读跳到参数、导入项、多变量声明里的一个时只闪属性表里那一行,按源码位置判断
This commit is contained in:
1 parent
5b4ca903c5
commit
3ac1c783fb
14 files changed
+367
-47
No files matched your search
@@ -1,12 +1,17 @@
|
||||
import type { BlockView, Segment } from './types'
|
||||
import { propertyRowId } from './viewState'
|
||||
import type { BlockView, Segment, SourceRange } from './types'
|
||||
import { propertyItemId, propertyRowId } from './viewState'
|
||||
|
||||
/** 跳到定义时要滚到的块,以及要展开的块和属性行:它们折叠着,目标就不在页面上。 */
|
||||
/** 跳到定义时要滚到的块,就是这处定义的属性行 / 子行(只闪它),以及要展开的块和属性行:它们折叠着,目标就不在页面上。 */
|
||||
export interface RevealPlan {
|
||||
id: string
|
||||
/** 属性行 id(propertyRowId)或子行 id(propertyItemId);没有时闪整块 */
|
||||
row?: string
|
||||
expand: string[]
|
||||
}
|
||||
|
||||
/** 目标在一块里的哪儿:row、expand 同 RevealPlan,expand 不含祖先块。 */
|
||||
type Spot = Omit<RevealPlan, 'id'>
|
||||
|
||||
interface Placed {
|
||||
block: BlockView
|
||||
/** 从顶层到父块的块 id */
|
||||
@@ -21,34 +26,53 @@ function* placed(blocks: BlockView[], ancestors: string[] = []): Generator<Place
|
||||
}
|
||||
}
|
||||
|
||||
function covers(range: SourceRange | undefined, offset: number): boolean {
|
||||
return range !== undefined && range.startIndex <= offset && offset < range.endIndex
|
||||
}
|
||||
|
||||
function shows(segments: Segment[], offset: number): boolean {
|
||||
return segments.some(segment => segment.offset === offset)
|
||||
}
|
||||
|
||||
/** 块里哪儿显示着 offset 处的名字:'value' 是一行译文或属性行的值,数字是带子行的属性行序号(名字在它展开的子行里),不在这块里是 undefined。 */
|
||||
function locate(block: BlockView, offset: number): 'value' | number | undefined {
|
||||
/**
|
||||
* 块里哪儿是 offset 处的定义,从具体到笼统:
|
||||
* ① 块自己的名字(函数名、只声明一个变量时的变量名)→ 整块;
|
||||
* ② 属性表里讲这个定义的一行 / 子行(defines 盖住 offset:参数、导入项、多变量声明里的一个)→ 只闪它,子行连它所在的行一起展开;
|
||||
* ③ 块里只是显示着这个名字(一行译文里的循环变量、没填 defines 的翻译插件)→ 整块,名字在子行里时展开那一行。
|
||||
* 不在这块里是 undefined。
|
||||
*/
|
||||
function locate(block: BlockView, offset: number): Spot | undefined {
|
||||
if (covers(block.defines, offset))
|
||||
return { expand: [] }
|
||||
if ('translation' in block)
|
||||
return shows(block.translation, offset) ? 'value' : undefined
|
||||
for (const [index, row] of block.properties.entries()) {
|
||||
return shows(block.translation, offset) ? { expand: [] } : undefined
|
||||
const rows = block.properties.map((row, index) => ({ row, id: propertyRowId(block.id, index) }))
|
||||
for (const { row, id } of rows) {
|
||||
if (covers(row.defines, offset))
|
||||
return { row: id, expand: [] }
|
||||
const item = row.items?.findIndex(entry => covers(entry.defines, offset)) ?? -1
|
||||
if (item >= 0)
|
||||
return { row: propertyItemId(id, item), expand: [id] }
|
||||
}
|
||||
for (const { row, id } of rows) {
|
||||
if (shows(row.value, offset))
|
||||
return 'value'
|
||||
return { expand: [] }
|
||||
if (row.items?.some(item => item.cells.some(cell => shows(cell, offset))))
|
||||
return index
|
||||
return { expand: [id] }
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳到定义:目标是显示着定义处那个名字的块,名字在属性行的子行里时连这一行一起展开;
|
||||
* 页面上找不到这个名字(例如定义是整个模块,落在文件开头)就取包含 line 的块,规则同 blockForLine。
|
||||
* 跳到定义:目标见 locate;页面上找不到这处定义(例如定义是整个模块,落在文件开头)就取包含 line 的块,规则同 blockForLine。
|
||||
* 目标的祖先块都要展开。
|
||||
*/
|
||||
export function revealPlan(blocks: BlockView[], line: number, definition: number): RevealPlan | undefined {
|
||||
let byLine: Placed | undefined
|
||||
for (const item of placed(blocks)) {
|
||||
const where = locate(item.block, definition)
|
||||
if (where !== undefined)
|
||||
return { id: item.block.id, expand: typeof where === 'number' ? [...item.ancestors, propertyRowId(item.block.id, where)] : item.ancestors }
|
||||
const spot = locate(item.block, definition)
|
||||
if (spot)
|
||||
return { id: item.block.id, ...spot, expand: [...item.ancestors, ...spot.expand] }
|
||||
if (item.block.startLine <= line && (!byLine || item.block.startLine > byLine.block.startLine))
|
||||
byLine = item
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user