✨ feat(vscode): 代码阅读把说明里的 @param / @return / @throws 拆到参数表、输出、异常表
This commit is contained in:
1 parent
c2982537d7
commit
0958506681
43 files changed
+1300
-323
No files matched your search
@@ -1,7 +1,8 @@
|
||||
import type { CSSProperties, ReactElement, ReactNode } from 'react'
|
||||
import type { BlockView, Inline, InlinePart, ItemDiff, ItemsDiff, KindBadge, PropertyItem, PropertyRow, Removed, RowsDiff } from './types'
|
||||
import type { BlockView, ItemDiff, ItemsDiff, KindBadge, PreviewText, PropertyItem, PropertyRow, Removed, RowDiff, RowsDiff, TextDiff } from './types'
|
||||
import { ChevronDown, ChevronRight } from 'lucide-react'
|
||||
import { Fragment } from 'react'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { DiffInline, DiffText } from './DiffText'
|
||||
import { inlineText } from './segments'
|
||||
import { SegmentText } from './SegmentText'
|
||||
@@ -51,23 +52,51 @@ function removedAt<T>(removed: readonly Removed<T>[] | undefined, after: number)
|
||||
return (removed ?? []).flatMap((entry, index) => entry.after === after ? [{ value: entry.value, index }] : [])
|
||||
}
|
||||
|
||||
/** 一格的字:这一格的值改了就逐截标(DiffInline),否则照常。 */
|
||||
function CellText({ cell, parts }: { cell: Inline[], parts: InlinePart[] | undefined }): ReactElement {
|
||||
return parts ? <DiffInline parts={parts} /> : <SegmentText segments={cell} />
|
||||
/** 一格是不是成块排的 Markdown 说明(参数的说明、异常的触发条件):它不能放进 .cr-code 的段落里。 */
|
||||
function isBlock(cell: PreviewText, parts: TextDiff | undefined): boolean {
|
||||
return 'markdown' in cell || (parts !== undefined && 'markdown' in parts)
|
||||
}
|
||||
|
||||
/** 一格的字:着色的词照常,改了的逐截标(DiffInline);Markdown 说明照常排版,改了的逐词标(DiffText)。 */
|
||||
function CellText({ cell, parts }: { cell: PreviewText, parts: TextDiff | undefined }): ReactElement {
|
||||
if (parts)
|
||||
return 'inline' in parts ? <DiffInline parts={parts.inline} /> : <DiffText diff={parts} className="min-w-0" />
|
||||
return 'markdown' in cell ? <TextPreview text={cell} className="min-w-0" /> : <SegmentText segments={cell} />
|
||||
}
|
||||
|
||||
/** 一格连外面那层:着色的词排在 .cr-code 的段落里,Markdown 说明是块,lead(差异记号、展开按钮)排在它左边。 */
|
||||
function CellBox({ cell, parts, className, lead, ...attrs }: { cell: PreviewText, parts: TextDiff | undefined, className?: string, lead?: ReactNode, role?: string }): ReactElement {
|
||||
if (isBlock(cell, parts)) {
|
||||
return (
|
||||
<div className={cn('flex min-w-0 items-start gap-1', className)} {...attrs}>
|
||||
{lead}
|
||||
<CellText cell={cell} parts={parts} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<p className={cn('cr-code min-w-0', className)} {...attrs}>
|
||||
{lead}
|
||||
<CellText cell={cell} parts={parts} />
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
/** 格子写成一串字(读屏念的展开 / 折叠按钮名):着色的词拼起来,Markdown 取原文。 */
|
||||
function cellLabel(cell: PreviewText): string {
|
||||
return 'markdown' in cell ? cell.markdown : inlineText(cell)
|
||||
}
|
||||
|
||||
/**
|
||||
* 子行的第一列(字典的键):带下一层的子行前面是折叠箭头(图标、大小、颜色同属性行的),点箭头或这一列切换;
|
||||
* 同一层里不带下一层的子行在同样的位置留空,第一列才对得齐。
|
||||
*/
|
||||
function ItemHead({ id, cell, foldable, folding }: { id: string, cell: Inline[], foldable: boolean, folding: Folding }): ReactElement {
|
||||
function ItemHead({ id, cell, foldable, folding }: { id: string, cell: PreviewText, foldable: boolean, folding: Folding }): ReactElement {
|
||||
if (!foldable) {
|
||||
return (
|
||||
<div className="flex min-w-0 gap-1">
|
||||
<span className="w-3.5 shrink-0" />
|
||||
<p className="cr-code min-w-0">
|
||||
<SegmentText segments={cell} />
|
||||
</p>
|
||||
<CellBox cell={cell} parts={undefined} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -80,15 +109,15 @@ function ItemHead({ id, cell, foldable, folding }: { id: string, cell: Inline[],
|
||||
<button
|
||||
type="button"
|
||||
className="flex h-5 w-3.5 shrink-0 items-center rounded-sm"
|
||||
aria-label={`${folded ? '展开' : '折叠'}${inlineText(cell)}`}
|
||||
aria-label={`${folded ? '展开' : '折叠'}${cellLabel(cell)}`}
|
||||
aria-expanded={!folded}
|
||||
onClick={toggle}
|
||||
>
|
||||
<Chevron size={14} strokeWidth={1.8} className="text-[var(--vscode-descriptionForeground)] group-hover:text-[var(--vscode-foreground)]" />
|
||||
</button>
|
||||
<p className="cr-code min-w-0 cursor-pointer" onClick={toggle}>
|
||||
<SegmentText segments={cell} />
|
||||
</p>
|
||||
<div className="min-w-0 cursor-pointer" onClick={toggle}>
|
||||
<CellBox cell={cell} parts={undefined} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -114,11 +143,7 @@ function PropertyItems({ parentId, items, folding, marks }: { parentId: string,
|
||||
>
|
||||
{item.cells.map((cell, i) => i === 0 && nested
|
||||
? <ItemHead key={i} id={id} cell={cell} foldable={children.length > 0 && change !== 'del'} folding={folds} />
|
||||
: (
|
||||
<p key={i} className="cr-code min-w-0">
|
||||
<CellText cell={cell} parts={mark?.cells?.[i]} />
|
||||
</p>
|
||||
))}
|
||||
: <CellBox key={i} cell={cell} parts={mark?.cells?.[i]} />)}
|
||||
</div>
|
||||
{children.length > 0 && !folds.collapsed.has(id) && (change === 'del'
|
||||
? (
|
||||
@@ -171,18 +196,18 @@ 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 text = (cell: Inline[], i: number): ReactElement => (
|
||||
<>
|
||||
{signed && i === 0 && <span className="cr-diff-sign" data-change={change} aria-hidden>{SIGNS[change ?? 'none']}</span>}
|
||||
{toggle && i === 0
|
||||
? (
|
||||
<button type="button" className="cr-item-toggle" aria-expanded={toggle.open} aria-label={`${toggle.open ? '收起' : '展开'}${inlineText(cell)}`} onClick={toggle.onToggle}>
|
||||
<CellText cell={cell} parts={mark?.cells?.[i]} />
|
||||
</button>
|
||||
)
|
||||
: <CellText cell={cell} parts={mark?.cells?.[i]} />}
|
||||
</>
|
||||
)
|
||||
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
|
||||
? (
|
||||
<p className={cn('cr-code min-w-0', className)} role="cell">
|
||||
{sign(i)}
|
||||
<button type="button" className="cr-item-toggle" aria-expanded={toggle.open} aria-label={`${toggle.open ? '收起' : '展开'}${cellLabel(cell)}`} onClick={toggle.onToggle}>
|
||||
<CellText cell={cell} parts={mark?.cells?.[i]} />
|
||||
</button>
|
||||
</p>
|
||||
)
|
||||
: <CellBox cell={cell} parts={mark?.cells?.[i]} className={className} lead={sign(i)} role="cell" />
|
||||
const tint = toggle?.open && toggle.badge
|
||||
? { 'data-badge': '', 'style': { '--kind-dark': toggle.badge.color.dark, '--kind-light': toggle.badge.color.light } as CSSProperties }
|
||||
: {}
|
||||
@@ -191,11 +216,11 @@ export function PropertyTable({ parentId, columns, items, marks, toggles }: {
|
||||
{cells.map((cell, i) => item.table && i === cells.length - 1
|
||||
? (
|
||||
<div key={i} className="cr-table-cell flex min-w-0 flex-col gap-[3px]" role="cell">
|
||||
<p className="cr-code">{text(cell, i)}</p>
|
||||
<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} />
|
||||
</div>
|
||||
)
|
||||
: <p key={i} className="cr-table-cell cr-code min-w-0" role="cell">{text(cell, i)}</p>)}
|
||||
: <Fragment key={i}>{cellBox(cell, i, 'cr-table-cell')}</Fragment>)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -271,7 +296,7 @@ export function PropertyGrid({ blockId, rows, collapsed, onToggleFold, marks, sl
|
||||
</button>
|
||||
)
|
||||
: <span className="cr-prop-label flex h-5 items-center">{row.label}</span>}
|
||||
{mark?.value ? <DiffText diff={mark.value} className="min-w-0" /> : <TextPreview text={row.value} className="min-w-0" />}
|
||||
<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} />}
|
||||
@@ -284,6 +309,22 @@ export function PropertyGrid({ blockId, rows, collapsed, onToggleFold, marks, sl
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 一行的值:着色的词或 Markdown(改了的逐截 / 逐词标);跟着说明(PropertyRow.note,输出参数的 `@return`)时说明接在值后面,
|
||||
* 同一行放得下就并排,剩的地方不到 12 个字宽时换到下一行。
|
||||
*/
|
||||
function RowValue({ row, mark }: { row: PropertyRow, mark: RowDiff | undefined }): ReactElement {
|
||||
const value = mark?.value ? <DiffText diff={mark.value} className="min-w-0" /> : <TextPreview text={row.value} className="min-w-0" />
|
||||
if (!row.note)
|
||||
return value
|
||||
return (
|
||||
<div className="flex min-w-0 flex-wrap items-baseline gap-x-2">
|
||||
{value}
|
||||
{mark?.note ? <DiffText diff={mark.note} className="min-w-0 flex-[1_1_12em]" /> : <TextPreview text={row.note} className="min-w-0 flex-[1_1_12em]" />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/** 属性表里删掉的一行:整行淡红底、划掉,左边 −;它下面的子行照样摊开、划掉。 */
|
||||
function RemovedRow({ id, row }: { id: string, row: PropertyRow }): ReactElement {
|
||||
const layout = subRowsLayout(row)
|
||||
@@ -291,7 +332,7 @@ function RemovedRow({ id, row }: { id: string, row: PropertyRow }): ReactElement
|
||||
<>
|
||||
<div className="cr-prop-row grid grid-cols-subgrid" data-diff="del">
|
||||
<span className="cr-prop-label flex h-5 items-center">{row.label}</span>
|
||||
<TextPreview text={row.value} className="min-w-0" />
|
||||
<RowValue row={row} mark={undefined} />
|
||||
</div>
|
||||
{layout && (
|
||||
<div className="cr-diff-gone">
|
||||
|
||||
Reference in new issue
Block a user