✨ feat(vscode): 代码阅读预览里实参值、return 这类一行译文里跨几行写的字典 / 列表按项拆开,各项带自己的实参表
This commit is contained in:
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)
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user