import type { Inline, 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), ] } /** 着色的词拼成的文字(给折叠按钮的说明用);框写成框头加框里的文字。 */ export function inlineText(pieces: Inline[]): string { return pieces.map(piece => 'role' in piece ? piece.text : `${piece.label} ${inlineText(piece.segments)}`).join('') } /** 文字里有没有 offset 处的那个名字,框里的也算。 */ export function showsOffset(pieces: Inline[], offset: number): boolean { return pieces.some(piece => 'role' in piece ? piece.offset === offset : showsOffset(piece.segments, offset)) }