44 lines
1.2 KiB
TypeScript
44 lines
1.2 KiB
TypeScript
export interface TextHighlight {
|
|
text: string;
|
|
color: string;
|
|
}
|
|
|
|
export interface HighlightedTextSegment {
|
|
text: string;
|
|
color: string | null;
|
|
}
|
|
|
|
export function highlightTextSegments(
|
|
value: string,
|
|
highlights: readonly TextHighlight[],
|
|
): HighlightedTextSegment[] {
|
|
const rules = highlights
|
|
.filter((highlight) => highlight.text.length > 0)
|
|
.toSorted((left, right) => right.text.length - left.text.length);
|
|
if (!rules.length) return [{ text: value, color: null }];
|
|
|
|
const segments: HighlightedTextSegment[] = [];
|
|
let cursor = 0;
|
|
while (cursor < value.length) {
|
|
let matchIndex = -1;
|
|
let match: TextHighlight | undefined;
|
|
for (const rule of rules) {
|
|
const index = value.indexOf(rule.text, cursor);
|
|
if (index !== -1 && (matchIndex === -1 || index < matchIndex)) {
|
|
matchIndex = index;
|
|
match = rule;
|
|
}
|
|
}
|
|
if (!match || matchIndex === -1) {
|
|
segments.push({ text: value.slice(cursor), color: null });
|
|
break;
|
|
}
|
|
if (matchIndex > cursor) {
|
|
segments.push({ text: value.slice(cursor, matchIndex), color: null });
|
|
}
|
|
segments.push({ text: match.text, color: match.color });
|
|
cursor = matchIndex + match.text.length;
|
|
}
|
|
return segments;
|
|
}
|