✨ feat(vscode): 代码阅读预览界面

Vite 加 code-reader.html 第二入口;代码块树(层级竖线、折叠、种类标签配色)、译文 / 源码按词性着色、块内直接编辑(防抖回写整行、Esc 回预览)、翻译下拉、解析失败提示;看板与代码阅读共用带类型的 acquireVsCodeApi 包装和 ErrorBoundary。
This commit is contained in:
cruldra committed 2026-09-24 21:01:34 +08:00
1 parent cab5ac0ebc
commit af56985d9a
16 files changed
+775 -74

No files matched your search

@@ -0,0 +1,39 @@
import type { Segment } from './types'
/** 取 segments 拼起来的文字里 [from, to) 这一段,每个字保留原来的词性。 */
export function sliceSegments(segments: Segment[], from: number, to: number): Segment[] {
const out: Segment[] = []
let offset = 0
for (const segment of segments) {
const start = Math.max(from, offset)
const end = Math.min(to, offset + segment.text.length)
if (start < end)
out.push({ text: segment.text.slice(start - offset, end - offset), role: segment.role })
offset += segment.text.length
if (offset >= to)
break
}
return out
}
/**
* 给输入框里改过的文字上色:`tokens` 是 `code` 的着色,和 `code` 相同的开头、结尾沿用原来的词性,
* 中间改动的部分先不着色,等扩展端按新代码着色的文档到了再换成准确的。
*/
export function recolor(tokens: Segment[], code: string, text: string): Segment[] {
if (text === code)
return tokens
const shorter = Math.min(code.length, text.length)
let head = 0
while (head < shorter && code[head] === text[head])
head++
let tail = 0
while (tail < shorter - head && code[code.length - 1 - tail] === text[text.length - 1 - tail])
tail++
const changed = text.slice(head, text.length - tail)
return [
...sliceSegments(tokens, 0, head),
...(changed ? [{ text: changed, role: 'plain' as const }] : []),
...sliceSegments(tokens, code.length - tail, code.length),
]
}