✨ feat(vscode): 代码阅读预览按住 ⌘ / Ctrl 点名字跳到定义
This commit is contained in:
1 parent
e5db1a2e65
commit
4e146eb48f
20 files changed
+870
-60
No files matched your search
@@ -0,0 +1,65 @@
|
||||
import type { BlockView, Segment } from './types'
|
||||
import { propertyRowId } from './viewState'
|
||||
|
||||
/** 跳到定义时要滚到的块,以及要展开的块和属性行:它们折叠着,目标就不在页面上。 */
|
||||
export interface RevealPlan {
|
||||
id: string
|
||||
expand: string[]
|
||||
}
|
||||
|
||||
interface Placed {
|
||||
block: BlockView
|
||||
/** 从顶层到父块的块 id */
|
||||
ancestors: string[]
|
||||
}
|
||||
|
||||
/** 按页面上的先后(先父块、再子块)列出所有块。 */
|
||||
function* placed(blocks: BlockView[], ancestors: string[] = []): Generator<Placed> {
|
||||
for (const block of blocks) {
|
||||
yield { block, ancestors }
|
||||
yield* placed(block.children, [...ancestors, block.id])
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
if ('translation' in block)
|
||||
return shows(block.translation, offset) ? 'value' : undefined
|
||||
for (const [index, row] of block.properties.entries()) {
|
||||
if (shows(row.value, offset))
|
||||
return 'value'
|
||||
if (row.items?.some(item => item.cells.some(cell => shows(cell, offset))))
|
||||
return index
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳到定义:目标是显示着定义处那个名字的块,名字在属性行的子行里时连这一行一起展开;
|
||||
* 页面上找不到这个名字(例如定义是整个模块,落在文件开头)就取包含 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 }
|
||||
if (item.block.startLine <= line && (!byLine || item.block.startLine > byLine.block.startLine))
|
||||
byLine = item
|
||||
}
|
||||
const target = byLine ?? (blocks.length > 0 ? { block: blocks[0], ancestors: [] } : undefined)
|
||||
return target && { id: target.block.id, expand: target.ancestors }
|
||||
}
|
||||
|
||||
/** 让一块露出来要滚到的 scrollTop,和 VS Code 跳到定义一样:整块已经在视口里就不滚;否则放到视口正中,比视口还高就顶部对齐。 */
|
||||
export function scrollTopToShow(box: { top: number, bottom: number }, viewTop: number, viewHeight: number): number | undefined {
|
||||
if (box.top >= viewTop && box.bottom <= viewTop + viewHeight)
|
||||
return undefined
|
||||
const height = box.bottom - box.top
|
||||
return Math.max(0, height >= viewHeight ? box.top : box.top - (viewHeight - height) / 2)
|
||||
}
|
||||
Reference in new issue
Block a user