✨ feat(vscode): 代码阅读库规则卡片不再吞掉字段中间的方法,编辑时收起子块

This commit is contained in:
cruldra committed 2026-09-26 19:58:43 +08:00
1 parent c803fd457f
commit 2251e67ef8
15 files changed
+280 -54

No files matched your search

@@ -0,0 +1,63 @@
import type { BlockView } from './types'
import { describe, expect, it } from 'vitest'
import { coveredByEditing, startEditing } from './editing'
import { revealPlan, uncoveredPlan } from './reveal'
function block(id: string, kind: string, [startLine, endLine]: [number, number], children: BlockView[] = []): BlockView {
return { id, kind, startLine, endLine, code: '', codeTokens: [], attributes: { kind }, children, properties: [] }
}
/**
* 库规则的卡片(1)编辑范围是整个类(2–12 行),两个字段中间写着的方法(1.0)和它的主体(1.0.0)、类末尾的方法(1.1)都在这段里;
* 普通的类(2)只编辑头部,方法(2.0)不在头部里;一行写完的 if(3)和它的返回(3.0)在同一行。
*/
const BLOCKS = [
block('0', 'import', [0, 0]),
block('1', 'sqlalchemy.table', [2, 12], [
block('1.0', 'function', [5, 5], [block('1.0.0', 'return', [6, 6])]),
block('1.1', 'function', [11, 12]),
]),
block('2', 'class', [14, 14], [block('2.0', 'function', [15, 16])]),
block('3', 'if', [18, 18], [block('3.0', 'return', [18, 18])]),
]
describe('同一行不会同时在两处能改', () => {
it('卡片编辑时,它留下的子块(字段中间的方法连同主体)不画,跳到它们时改闪卡片', () => {
expect(coveredByEditing(BLOCKS, new Set(['1']))).toEqual(new Map([['1.0', '1'], ['1.0.0', '1'], ['1.1', '1']]))
})
it('只编辑头部的块不盖住子块;一行写完的块编辑时盖住同一行的子块', () => {
expect(coveredByEditing(BLOCKS, new Set(['2', '2.0']))).toEqual(new Map())
expect(coveredByEditing(BLOCKS, new Set(['3']))).toEqual(new Map([['3.0', '3']]))
})
it('没在编辑的卡片不盖住子块:子块照常画、照常能单独编辑', () => {
expect(coveredByEditing(BLOCKS, new Set(['1.0']))).toEqual(new Map())
})
it('点「编辑」:编辑范围和它重叠的别的块退出编辑,不重叠的留着', () => {
expect(startEditing(BLOCKS, ['1.0', '1.1', '2'], '1')).toEqual(['2', '1'])
expect(startEditing(BLOCKS, ['1', '2'], '1.0')).toEqual(['2', '1.0'])
expect(startEditing(BLOCKS, ['2'], '2.0')).toEqual(['2', '2.0'])
})
it('任何时候正在编辑、画出来的几块,编辑范围两两不重叠', () => {
const all = (list: BlockView[]): BlockView[] => list.flatMap(item => [item, ...all(item.children)])
let editing: string[] = []
for (const id of ['1.0', '1.0.0', '2', '2.0', '1', '3.0', '3', '1.1'])
editing = startEditing(BLOCKS, editing, id)
const covered = coveredByEditing(BLOCKS, new Set(editing))
const shown = all(BLOCKS).filter(item => editing.includes(item.id) && !covered.has(item.id))
for (const a of shown) {
for (const b of shown.filter(other => other !== a))
expect(a.startLine > b.endLine || b.startLine > a.endLine, `${a.id} / ${b.id}`).toBe(true)
}
})
it('跳到定义的目标被盖住:闪盖住它的那块,展开那块的祖先', () => {
const covered = coveredByEditing(BLOCKS, new Set(['1']))
expect(uncoveredPlan({ id: '1.0.0', expand: ['1', '1.0'] }, covered)).toEqual({ id: '1', expand: [] })
const plain = revealPlan(BLOCKS, 15, 999)
expect(plain && uncoveredPlan(plain, covered)).toEqual(plain)
})
})