✨ feat(vscode): 代码阅读预览标出新增 / 修改 / 删除的卡片(左侧改动色条、新增淡绿底挂小标、删掉的块原位收成一行可展开),筛选栏第二行写对比基准和改动统计,新文件顶部横幅
This commit is contained in:
1 parent
2a5806c6b5
commit
3b7ce69842
10 files changed
+491
-20
No files matched your search
@@ -0,0 +1,70 @@
|
||||
import type { BlockView, ChangedBlock, DiffStats, DocumentDiff, RemovedView } from './types'
|
||||
import { inlineText } from './segments'
|
||||
|
||||
/** 页面上怎么标差异:按块 id 取改动,按层取删掉的块。基准里没有这个文件(整份新增)时不逐块标,没有它。 */
|
||||
export interface DiffTree {
|
||||
/** 按块 id:新增、修改的块 */
|
||||
changes: ReadonlyMap<string, ChangedBlock>
|
||||
/** 按父块 id(顶层 ''):这一层删掉的块,照差异里的先后 */
|
||||
removed: ReadonlyMap<string, PlacedRemoved[]>
|
||||
/** 页面上正是差异算的那一版:卡片里的标记按下标认,只在这时画 */
|
||||
current: boolean
|
||||
}
|
||||
|
||||
/** 放在页面上的一块删掉的块:id 是页面上认它用的(`removed-<序号>`,不会和块 id、属性行 id 撞上),after 是排在哪块(id)后面,最前面时没有。 */
|
||||
export interface PlacedRemoved {
|
||||
id: string
|
||||
after?: string
|
||||
removed: RemovedView
|
||||
}
|
||||
|
||||
function* allBlocks(blocks: readonly BlockView[]): Generator<BlockView> {
|
||||
for (const block of blocks) {
|
||||
yield block
|
||||
yield* allBlocks(block.children)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 差异(块按记号认)→ 页面上的块 id:记号在页面上找不到的(文档刚改、差异还没重算)不标;删掉的块挂的父块、排在后面的那块找不到的也不画。
|
||||
* shown 挑删掉的块画不画(被筛选藏掉的种类不画)。
|
||||
*/
|
||||
export function diffTree(blocks: readonly BlockView[], diff: DocumentDiff | null, version: number, shown: (removed: RemovedView) => boolean): DiffTree | undefined {
|
||||
if (!diff || diff.newFile !== undefined)
|
||||
return undefined
|
||||
const ids = new Map([...allBlocks(blocks)].map(block => [block.anchor, block.id]))
|
||||
const changes = new Map<string, ChangedBlock>()
|
||||
for (const [anchor, change] of Object.entries(diff.blocks)) {
|
||||
const id = ids.get(anchor)
|
||||
if (id !== undefined)
|
||||
changes.set(id, change)
|
||||
}
|
||||
const removed = new Map<string, PlacedRemoved[]>()
|
||||
diff.removed.forEach((item, index) => {
|
||||
const parent = item.parent === '' ? '' : ids.get(item.parent)
|
||||
const after = item.after === undefined ? undefined : ids.get(item.after)
|
||||
if (parent === undefined || (item.after !== undefined && after === undefined) || !shown(item))
|
||||
return
|
||||
removed.set(parent, [...removed.get(parent) ?? [], { id: `removed-${index}`, ...(after !== undefined && { after }), removed: item }])
|
||||
})
|
||||
return { changes, removed, current: diff.version === version }
|
||||
}
|
||||
|
||||
/** 标了改动的块默认展开(函数、类本来默认收起子块):改了什么一眼能看到。 */
|
||||
export function openedByDiff(tree: DiffTree | undefined): ReadonlySet<string> {
|
||||
return new Set(tree?.changes.keys())
|
||||
}
|
||||
|
||||
/** 「新增 2 · 修改 3 · 删除 1」的各段:没有的那种不写。 */
|
||||
export function statsParts(stats: DiffStats): { change: keyof DiffStats, text: string }[] {
|
||||
const labels: Record<keyof DiffStats, string> = { add: '新增', mod: '修改', del: '删除' }
|
||||
return (['add', 'mod', 'del'] as const).filter(change => stats[change] > 0).map(change => ({ change, text: `${labels[change]} ${stats[change]}` }))
|
||||
}
|
||||
|
||||
/** 删掉的块收起时写的名字:属性表是第一行的值(函数名、变量名、导入的来源),一行译文是译文;只取第一行。 */
|
||||
export function removedTitle(block: BlockView): string {
|
||||
const text = 'properties' in block
|
||||
? block.properties[0] && ('markdown' in block.properties[0].value ? block.properties[0].value.markdown : inlineText(block.properties[0].value))
|
||||
: 'markdown' in block.translation ? block.translation.markdown : inlineText(block.translation)
|
||||
return (text ?? '').split('\n', 1)[0].trim()
|
||||
}
|
||||
Reference in new issue
Block a user