✨ feat(vscode): 代码阅读预览里实参值、return 这类一行译文里跨几行写的字典 / 列表按项拆开,各项带自己的实参表

This commit is contained in:
cruldra committed 2026-10-13 13:57:22 +11:00
1 parent b2c5309d1f
commit 907c4092c8
18 files changed
+515 -102

No files matched your search

@@ -1,3 +1,5 @@
// @vitest-environment happy-dom
import type { BlockTreeState, RewriteTree } from './BlockTree'
import type { Ask, ChatState } from './qa'
import type { BlockView, KindBadge } from './types'
@@ -240,3 +242,85 @@ describe('「注释」一行和「重写注释」按钮', () => {
expect(html(view('4', 'statement', 'save()'))).not.toContain('按注释规范')
})
})
describe('一行译文下面拆开的各项', () => {
/** 一段 Python 里函数体的第一块(return)经过宿主转成的视图数据;Filter 的定义是类。 */
async function returned(source: string): Promise<BlockView> {
const language = createPythonAdapter(WASM_DIR)
const views = await withBlocks(language, 'python', source, blocks => toBlockViews(blocks, { source, language, markers: [], calleeKind: call => call.callee.text === 'Filter' ? 'class' : undefined }, pythonZhTranslator))
return views[0].children[0]
}
const SOURCE = [
'def list_filters(archived, current_user):',
' return [',
' Filter(field="user_id", value=current_user.id),',
' Filter(',
' field="archived_at",',
' value=None,',
' ),',
' {"k": v},',
' ]',
].join('\n')
/** 画成页面(只画这一块),collapsed 是折叠着的 id */
function page(block: BlockView, collapsed: ReadonlySet<string> = new Set(), diff?: BlockTreeState['diff']): HTMLElement {
const root = document.createElement('div')
root.innerHTML = renderToStaticMarkup(<BlockLevel blocks={[block]} tree={{ ...state(collapsed), ...(diff && { diff }) }} />)
return root
}
function byId(root: HTMLElement, id: string): HTMLElement {
const found = root.querySelector<HTMLElement>(`[data-id="${id}"]`)
if (!found)
throw new Error(`页面上没有 ${id}`)
return found
}
/** a 在页面上排在 b 前面 */
function before(a: Element, b: Element): boolean {
return (a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0
}
it('各项排在译文下面、往右缩一层、左边一条竖线,和变量初始值的各项一样;项下面挂着它的实参表,排在下一项上面', async () => {
const block = await returned(SOURCE)
const root = page(block)
const line = root.querySelector('.cr-code')
expect(line?.textContent).toBe('返回 列表 3 项')
const first = byId(root, `${block.id}/i/0`)
const second = byId(root, `${block.id}/i/1`)
expect(first.textContent).toBe('第 1 项新建 Filter · 2 个参数')
expect(second.textContent).toBe('第 2 项新建 Filter · 2 个参数')
const cell = byId(root, `${block.id}/i/1/t/0`)
expect(cell.textContent).toBe('field"archived_at"')
expect(before(line!, first) && before(second, cell) && before(cell, byId(root, `${block.id}/i/2`))).toBe(true)
expect(first.closest('.cr-table')).toBeNull()
let level = first.parentElement
while (level && !level.firstElementChild?.classList.contains('cr-guide'))
level = level.parentElement
expect(level?.contains(second)).toBe(true)
expect(level?.contains(line)).toBe(false)
})
it('项下面的下一层(字典)能折叠,折着时只收起那一层;实参表总是展开的', async () => {
const block = await returned(SOURCE)
const map = `${block.id}/i/2`
const open = page(block)
expect(byId(open, map).querySelector('button')?.getAttribute('aria-expanded')).toBe('true')
expect(byId(open, `${map}/0`).textContent).toBe('"k"v')
const folded = page(block, new Set([map]))
expect(folded.querySelector(`[data-id="${map}/0"]`)).toBeNull()
expect(folded.querySelector(`[data-id="${block.id}/i/0/t/0"]`)).not.toBeNull()
})
it('标差异:新加的项淡绿底,删掉的项放回原来的位置、划掉', async () => {
const block = await returned(SOURCE)
const gone = { cells: [[{ text: '第 3 项', role: 'hint' as const }], [{ text: 'old', role: 'variable' as const }]] }
const changes = new Map([[block.id, { change: 'mod' as const, own: true as const, marks: { items: { changed: { 2: { added: true as const } }, removed: [{ after: 1, value: gone }] } } }]])
const root = page(block, new Set(), { changes, removed: new Map(), current: true })
expect(byId(root, `${block.id}/i/2`).dataset.diff).toBe('add')
const removed = root.querySelector<HTMLElement>('[data-diff="del"]')
expect(removed?.textContent).toBe('第 3 项old')
expect(before(byId(root, `${block.id}/i/1`), removed!) && before(removed!, byId(root, `${block.id}/i/2`))).toBe(true)
})
})