✨ feat(vscode): 代码阅读的链式调用卡片:语言插件读链、翻译模板排成起点和步骤

契约加 LanguageAdapter.chain、Translator.chain、RuleContext.chain、PropertyRow.chain、TextTranslation.rows;跨行写或实参里有闭包的链排成卡片,连着同名调用合成一步列出每次实参,注释挂在步骤上,闭包收起、子块挂到那一步(BlockView.step);Rust 插件读链、标准库常见方法写中文名;挤成一行时另起一行的 . 贴着前面
This commit is contained in:
cruldra committed 2026-10-15 20:54:59 +11:00
1 parent 80eda7c18e
commit ee595f3da9
16 files changed
+1041 -72

No files matched your search

+2 -1
View File
@@ -4,7 +4,7 @@
import type { ClaudeImage } from '../../cc/spawnClaude'
import type { FileAttribute } from '../attributes'
import type { BlockSlot, CallTreeTarget, CommentTarget, SourceColors } from '../blockView'
import type { BlockSlot, CallTreeTarget, ChainSlot, CommentTarget, SourceColors } from '../blockView'
import type { ContractMiss } from '../callTree/endpoint'
import type { CallTree } from '../callTree/model'
import type { BlockAttributes, BlockConcept, KindBadge, Markdown, PreviewTable, PreviewText, PropertyItem, PropertyRow, SourceRange } from '../contract'
@@ -85,6 +85,7 @@ interface PageCardBase {
commentTarget?: CommentTarget['kind']
badge?: KindBadge
slot?: BlockSlot
step?: ChainSlot
callTree?: CallTreeTarget
}
@@ -3,8 +3,10 @@ import type { PageBlock } from './messages'
import { describe, expect, it } from 'vitest'
import { toBlockViews } from '../blockView'
import { createPythonAdapter } from '../languages/python'
import { createRustAdapter } from '../languages/rust'
import { WASM_DIR, withBlocks } from '../testSupport'
import { pythonZhTranslator } from '../translators/pythonZh'
import { rustZhTranslator } from '../translators/rustZh'
import { pageBlocks } from './pageBlocks'
const py = createPythonAdapter(WASM_DIR)
@@ -67,3 +69,22 @@ describe('发给页面的块带内容指纹:连子块、在源码里占的地
expect(changed(before, hashes(await page(SOURCE.replace('os.getenv(key)', 'os.getenv(name)'))))).toEqual(['2', '2.0', '2.0.0', '2.0.0.0'])
})
})
describe('链式调用卡片发给页面', () => {
const rust = createRustAdapter(WASM_DIR)
it('起点、各步的叫法和范围里的下标也从块的开头算,挂在链某一步下面的子块带着 step', async () => {
const source = 'fn f() {\n rows.iter()\n .for_each(|r| {\n show(r);\n });\n}\n'
const views = await withBlocks(rust, 'rust', source, blocks => toBlockViews(blocks, { source, language: rust, markers: [] }, rustZhTranslator))
const [fn] = pageBlocks(views, source)
const [statement] = fn?.children ?? []
const base = source.indexOf(' rows')
const rows = statement && 'translation' in statement ? statement.rows ?? [] : []
expect(rows[0]?.value).toEqual([{ text: 'rows', role: 'variable', offset: source.indexOf('rows') - base }])
const [, forEach] = rows[1]?.chain ?? []
const [label] = forEach?.name ?? []
expect(label && 'role' in label ? label.refers : undefined).toEqual({ startIndex: source.indexOf('for_each') - base, endIndex: source.indexOf('for_each') + 'for_each'.length - base })
expect(forEach?.range).toEqual({ startIndex: source.indexOf('.for_each') - base, endIndex: source.indexOf(';\n}') - base })
expect(statement?.children[0]?.step).toEqual({ row: 1, step: 1 })
})
})
+15 -1
View File
@@ -1,5 +1,5 @@
import type { BlockView } from '../blockView'
import type { Inline, PreviewTable, PreviewText, PropertyItem, PropertyRow, Segment, SourceRange } from '../contract'
import type { ChainStep, Inline, PreviewTable, PreviewText, PropertyItem, PropertyRow, Segment, SourceRange } from '../contract'
import type { BlockMarks, ItemDiff, ItemsDiff, RowDiff, RowsDiff, TextDiff } from '../diff/viewDiff'
import type { BlockSpan, PageBlock, PageCard } from './messages'
import { createHash } from 'node:crypto'
@@ -70,6 +70,19 @@ function shiftRow(row: PropertyRow, base: number): PropertyRow {
value: shiftText(row.value, base),
...(row.defines && { defines: shiftRange(row.defines, base) }),
...(row.items && { items: row.items.map(item => shiftItem(item, base)) }),
...(row.chain && { chain: row.chain.map(step => shiftStep(step, base)) }),
}
}
function shiftStep(step: ChainStep, base: number): ChainStep {
return {
...step,
name: shiftInline(step.name, base),
value: shiftInline(step.value, base),
...(step.lines && { lines: step.lines.map(line => shiftInline(line, base)) }),
...(step.rows && { rows: step.rows.map(row => shiftRow(row, base)) }),
...(step.table && { table: shiftTable(step.table, base) }),
range: shiftRange(step.range, base),
}
}
@@ -85,6 +98,7 @@ export function pageCard(block: BlockView, base: number): PageCard {
...(block.commentTarget && { commentTarget: block.commentTarget.kind }),
...(block.badge && { badge: block.badge }),
...(block.slot && { slot: block.slot }),
...(block.step && { step: block.step }),
...(block.callTree && { callTree: block.callTree }),
}
if ('properties' in block)