Files
superwork/vscode/webview-ui/src/codeReader/editing.ts
T

52 lines
2.1 KiB
TypeScript

import type { BlockView } from './types'
/**
* 同一时刻能编辑的几段源码不重叠,同一行不会同时在两处能改:
* ① 块编辑时,编辑范围和它重叠的子孙块不画(库规则的卡片编辑整个类,留下的方法也在这段里;
* 一行写完的 `if x: return 1`,子块和头部在同一行),它们下面的子孙也跟着不画;
* ② 点「编辑」时,编辑范围和这块重叠的别的块退出编辑。
*/
type Lines = Pick<BlockView, 'startLine' | 'endLine'>
function overlaps(a: Lines, b: Lines): boolean {
return a.startLine <= b.endLine && b.startLine <= a.endLine
}
/** 正在编辑的块盖住、不画的块 → 盖住它的那块(页面上画着的、正在编辑的祖先):跳到定义落在被盖住的块上时改闪它。 */
export function coveredByEditing(blocks: readonly BlockView[], editing: ReadonlySet<string>): Map<string, string> {
const covered = new Map<string, string>()
const visit = (list: readonly BlockView[], editors: readonly BlockView[], owner: string | undefined): void => {
for (const block of list) {
const by = owner ?? editors.find(editor => overlaps(editor, block))?.id
if (by !== undefined) {
covered.set(block.id, by)
visit(block.children, editors, by)
}
else {
visit(block.children, editing.has(block.id) ? [...editors, block] : editors, undefined)
}
}
}
visit(blocks, [], undefined)
return covered
}
function* allBlocks(blocks: readonly BlockView[]): Generator<BlockView> {
for (const block of blocks) {
yield block
yield* allBlocks(block.children)
}
}
/** 点了 id 这块的「编辑」之后正在编辑的块:加上它,编辑范围和它重叠的别的块退出编辑。 */
export function startEditing(blocks: readonly BlockView[], editing: readonly string[], id: string): string[] {
const byId = new Map([...allBlocks(blocks)].map(block => [block.id, block]))
const target = byId.get(id)
const others = editing.filter((other) => {
const block = byId.get(other)
return other !== id && !(target && block && overlaps(target, block))
})
return [...others, id]
}