(word: string, width: number, tracker: AnsiCodeTracker)
| 840 | } |
| 841 | |
| 842 | function breakLongWord(word: string, width: number, tracker: AnsiCodeTracker): string[] { |
| 843 | const lines: string[] = []; |
| 844 | let currentLine = tracker.getActiveCodes(); |
| 845 | let currentWidth = 0; |
| 846 | |
| 847 | // First, separate ANSI codes from visible content |
| 848 | // We need to handle ANSI codes specially since they're not graphemes |
| 849 | let i = 0; |
| 850 | const segments: Array<{ type: "ansi" | "grapheme"; value: string }> = []; |
| 851 | |
| 852 | while (i < word.length) { |
| 853 | const ansiResult = extractAnsiCode(word, i); |
| 854 | if (ansiResult) { |
| 855 | segments.push({ type: "ansi", value: ansiResult.code }); |
| 856 | i += ansiResult.length; |
| 857 | } else { |
| 858 | // Find the next ANSI code or end of string |
| 859 | let end = i; |
| 860 | while (end < word.length) { |
| 861 | const nextAnsi = extractAnsiCode(word, end); |
| 862 | if (nextAnsi) break; |
| 863 | end++; |
| 864 | } |
| 865 | // Segment this non-ANSI portion into graphemes |
| 866 | const textPortion = word.slice(i, end); |
| 867 | for (const seg of graphemeSegmenter.segment(textPortion)) { |
| 868 | segments.push({ type: "grapheme", value: seg.segment }); |
| 869 | } |
| 870 | i = end; |
| 871 | } |
| 872 | } |
| 873 | |
| 874 | // Now process segments |
| 875 | for (const seg of segments) { |
| 876 | if (seg.type === "ansi") { |
| 877 | currentLine += seg.value; |
| 878 | tracker.process(seg.value); |
| 879 | continue; |
| 880 | } |
| 881 | |
| 882 | const grapheme = seg.value; |
| 883 | // Skip empty graphemes to avoid issues with string-width calculation |
| 884 | if (!grapheme) continue; |
| 885 | |
| 886 | const graphemeWidth = visibleWidth(grapheme); |
| 887 | |
| 888 | if (currentWidth + graphemeWidth > width) { |
| 889 | // Add specific reset for underline only (preserves background) |
| 890 | const lineEndReset = tracker.getLineEndReset(); |
| 891 | if (lineEndReset) { |
| 892 | currentLine += lineEndReset; |
| 893 | } |
| 894 | lines.push(currentLine); |
| 895 | currentLine = tracker.getActiveCodes(); |
| 896 | currentWidth = 0; |
| 897 | } |
| 898 | |
| 899 | currentLine += grapheme; |
no test coverage detected