✨ feat(vscode): 代码阅读预览里跨几行写的列表按项拆开,列表里整项是调用的带着自己的实参表,一层层能往下套

This commit is contained in:
cruldra committed 2026-10-13 13:32:45 +11:00
1 parent 7d6e7592c9
commit 2c490cac2d
22 files changed
+848 -314

No files matched your search

@@ -122,9 +122,20 @@ function ItemHead({ id, cell, foldable, folding }: { id: string, cell: PreviewTe
)
}
/** 往右缩进一层、左边一条竖线:一行或一个子行下面的一层子行,列表的一项下面挂的实参表 */
function Nested({ children }: { children: ReactNode }): ReactElement {
return (
<div className="flex gap-2.5 pl-[5px]">
<div className="cr-guide w-px shrink-0" />
<div className="flex min-w-0 flex-1 flex-col gap-0.5">{children}</div>
</div>
)
}
/**
* 展开在一行或一个子行(parentId)下面的一层子行:左边一条竖线,每个子行几列对齐。
* 带下一层的子行(字典 / 对象的值又是字典 / 对象),下一层展开在它下面、再往右缩进一层,默认展开。
* 带下一层的子行(字典 / 对象、跨几行写的列表的各项),下一层展开在它下面、再往右缩进一层,默认展开,能折叠;
* 带实参表的子行(列表里整项是调用),表排在它下面、同样往右缩进一层,总是展开。
* 标差异时(marks)新加的子行淡绿底、左边 +,删掉的放回原来的位置、淡红底划掉、左边 −,改了的格子逐截标。
*/
function PropertyItems({ parentId, items, folding, marks }: { parentId: string, items: PropertyItem[], folding: Folding, marks?: ItemsDiff }): ReactElement {
@@ -133,6 +144,17 @@ function PropertyItems({ parentId, items, folding, marks }: { parentId: string,
const itemRow = (item: PropertyItem, id: string, change: 'add' | 'del' | undefined, mark: ItemDiff | undefined): ReactElement => {
const children = item.items ?? []
const folds = change === 'del' ? FIXED : folding
const open = children.length > 0 && !folds.collapsed.has(id)
const below = (
<>
{open && <PropertyItems parentId={id} items={children} folding={folds} marks={mark?.items} />}
{item.table && (
<Nested>
<PropertyTable parentId={tableId(id)} columns={item.table.columns} items={item.table.items} marks={mark?.table} folding={folds} />
</Nested>
)}
</>
)
return (
<>
<div
@@ -145,49 +167,43 @@ function PropertyItems({ parentId, items, folding, marks }: { parentId: string,
? <ItemHead key={i} id={id} cell={cell} foldable={children.length > 0 && change !== 'del'} folding={folds} />
: <CellBox key={i} cell={cell} parts={mark?.cells?.[i]} />)}
</div>
{children.length > 0 && !folds.collapsed.has(id) && (change === 'del'
? (
<div className="cr-diff-gone">
<PropertyItems parentId={id} items={children} folding={folds} />
</div>
)
: <PropertyItems parentId={id} items={children} folding={folds} marks={mark?.items} />)}
{(open || item.table) && (change === 'del' ? <div className="cr-diff-gone">{below}</div> : below)}
</>
)
}
const removed = (after: number): ReactElement[] => removedAt(marks?.removed, after)
.map(({ value, index }) => <Fragment key={`removed-${index}`}>{itemRow(value, `${parentId}/x${index}`, 'del', undefined)}</Fragment>)
return (
<div className="flex gap-2.5 pl-[5px]">
<div className="cr-guide w-px shrink-0" />
<div className="flex min-w-0 flex-1 flex-col gap-0.5">
{removed(-1)}
{items.map((item, index) => {
const mark = marks?.changed[index]
return (
<Fragment key={index}>
{itemRow(item, propertyItemId(parentId, index), mark?.added && 'add', mark)}
{removed(index)}
</Fragment>
)
})}
</div>
</div>
<Nested>
{removed(-1)}
{items.map((item, index) => {
const mark = marks?.changed[index]
return (
<Fragment key={index}>
{itemRow(item, propertyItemId(parentId, index), mark?.added && 'add', mark)}
{removed(index)}
</Fragment>
)
})}
</Nested>
)
}
/**
* 给了列名的子行(输入参数、数据表的字段)排成表格:第一行是表头(列名),下面每个子行一行;外框圆角,格子之间、行之间一条分隔线。
* 列宽按整列的内容定(见 tableTemplate),最后一列分剩下的,长了在格子里换行。一行译文下面摊开实参的表也用它;
* 行带 table(实参的值里跨几行写的调用)时,那张表排在最后一格里、文字下面,往右缩一点,一层层往下套。
* 行带 items(实参的值是跨几行写的列表)时各项排在最后一格里、文字下面,同属性行下面的子行(项下面的下一层按 folding 折叠);
* 行带 table(实参的值里跨几行写的调用)时那张表排在它们后面,往右缩一点。一层层往下套。
* 标差异时(marks)有加行、删行的表每行第一格前多一个记号位(+ / −,没变的空着),加的行淡绿底,删的行放回原来的位置、淡红底划掉。
* 讲某个子块的行(toggles,Rust 实现块的方法表)第一格是按钮,点它在表下面展开那一块,展开时这一行淡淡垫上那一块的种类色。
*/
export function PropertyTable({ parentId, columns, items, marks, toggles }: {
export function PropertyTable({ parentId, columns, items, marks, folding, toggles }: {
parentId: string
columns: string[]
items: PropertyItem[]
marks?: ItemsDiff
/** 格子里拆开的子行下面的下一层眼下折叠着没有 */
folding: Folding
/** 按子行下标:讲它的子块(点第一格展开,见 GridSlots) */
toggles?: ReadonlyMap<number, ItemToggle>
}): ReactElement {
@@ -196,6 +212,7 @@ export function PropertyTable({ parentId, columns, items, marks, toggles }: {
/** 一行:删掉的(change 是 del)不带 id,套着的表不再标;toggle 是这一行讲的子块,第一格成了展开它的按钮 */
const tableRow = (item: PropertyItem, id: string, change: 'add' | 'del' | undefined, mark: ItemDiff | undefined, toggle?: ItemToggle): ReactElement => {
const cells = tableCells(item, columns)
const listed = (item.items?.length ?? 0) > 0
const sign = (i: number): ReactNode => signed && i === 0 && <span className="cr-diff-sign" data-change={change} aria-hidden>{SIGNS[change ?? 'none']}</span>
/** 一格:讲子块的那一格是展开它的按钮(只放着色的词),别的照常(见 CellBox) */
const cellBox = (cell: PreviewText, i: number, className?: string): ReactElement => toggle && i === 0
@@ -213,11 +230,12 @@ export function PropertyTable({ parentId, columns, items, marks, toggles }: {
: {}
return (
<div className="cr-table-row" role="row" data-id={change === 'del' ? undefined : id} data-diff={change} data-open={toggle?.open ? '' : undefined} {...tint}>
{cells.map((cell, i) => item.table && i === cells.length - 1
{cells.map((cell, i) => (listed || item.table) && i === cells.length - 1
? (
<div key={i} className="cr-table-cell flex min-w-0 flex-col gap-[3px]" role="cell">
<CellBox cell={cell} parts={mark?.cells?.[i]} lead={sign(i)} />
<PropertyTable parentId={tableId(id)} columns={item.table.columns} items={item.table.items} marks={mark?.table} />
{listed && <PropertyItems parentId={id} items={item.items ?? []} folding={change === 'del' ? FIXED : folding} marks={mark?.items} />}
{item.table && <PropertyTable parentId={tableId(id)} columns={item.table.columns} items={item.table.items} marks={mark?.table} folding={change === 'del' ? FIXED : folding} />}
</div>
)
: <Fragment key={i}>{cellBox(cell, i, 'cr-table-cell')}</Fragment>)}
@@ -262,6 +280,7 @@ export function PropertyGrid({ blockId, rows, collapsed, onToggleFold, marks, sl
/** 挂在这张属性表子行上的子块(库规则的卡片),见 GridSlots */
slots?: GridSlots
}): ReactElement {
const folding: Folding = { collapsed, onToggleFold }
const removed = (after: number): ReactElement[] => removedAt(marks?.removed, after)
.map(({ value, index }) => <RemovedRow key={`removed-${index}`} id={`${blockId}/x${index}`} row={value} />)
return (
@@ -298,8 +317,8 @@ export function PropertyGrid({ blockId, rows, collapsed, onToggleFold, marks, sl
: <span className="cr-prop-label flex h-5 items-center">{row.label}</span>}
<RowValue row={row} mark={mark} />
</div>
{!folded && layout === 'table' && <PropertyTable parentId={id} columns={row.columns ?? []} items={row.items ?? []} marks={mark?.items} toggles={toggles} />}
{!folded && layout === 'list' && <PropertyItems parentId={id} items={row.items ?? []} folding={{ collapsed, onToggleFold }} marks={mark?.items} />}
{!folded && layout === 'table' && <PropertyTable parentId={id} columns={row.columns ?? []} items={row.items ?? []} marks={mark?.items} folding={folding} toggles={toggles} />}
{!folded && layout === 'list' && <PropertyItems parentId={id} items={row.items ?? []} folding={folding} marks={mark?.items} />}
{!folded && slots && shownBlocks.length > 0 && <div className="cr-slot">{slots.render(shownBlocks)}</div>}
{removed(index)}
</Fragment>
@@ -337,7 +356,7 @@ function RemovedRow({ id, row }: { id: string, row: PropertyRow }): ReactElement
{layout && (
<div className="cr-diff-gone">
{layout === 'table'
? <PropertyTable parentId={id} columns={row.columns ?? []} items={row.items ?? []} />
? <PropertyTable parentId={id} columns={row.columns ?? []} items={row.items ?? []} folding={FIXED} />
: <PropertyItems parentId={id} items={row.items ?? []} folding={FIXED} />}
</div>
)}