| 650 | * breaking for words that exceed the column width. |
| 651 | */ |
| 652 | const wrapText = (text: string, maxWidth: number): string[] => { |
| 653 | if (maxWidth < 1) return [''] |
| 654 | if (!text) return [''] |
| 655 | const textWidth = stringWidth(text) |
| 656 | if (textWidth <= maxWidth) return [text] |
| 657 | |
| 658 | const lines: string[] = [] |
| 659 | let currentLine = '' |
| 660 | let currentWidth = 0 |
| 661 | const tokens = text.split(/(\s+)/) |
| 662 | |
| 663 | for (const token of tokens) { |
| 664 | if (!token) continue |
| 665 | const tokenWidth = stringWidth(token) |
| 666 | const isWhitespace = /^\s+$/.test(token) |
| 667 | |
| 668 | // Skip leading whitespace on new lines |
| 669 | if (isWhitespace && currentWidth === 0) continue |
| 670 | |
| 671 | if (tokenWidth > maxWidth && !isWhitespace) { |
| 672 | // Break long words character by character |
| 673 | for (const char of token) { |
| 674 | const charWidth = stringWidth(char) |
| 675 | if (currentWidth + charWidth > maxWidth) { |
| 676 | if (currentLine) lines.push(currentLine) |
| 677 | currentLine = char |
| 678 | currentWidth = charWidth |
| 679 | } else { |
| 680 | currentLine += char |
| 681 | currentWidth += charWidth |
| 682 | } |
| 683 | } |
| 684 | } else if (currentWidth + tokenWidth > maxWidth) { |
| 685 | if (currentLine) lines.push(currentLine.trimEnd()) |
| 686 | currentLine = isWhitespace ? '' : token |
| 687 | currentWidth = isWhitespace ? 0 : tokenWidth |
| 688 | } else { |
| 689 | currentLine += token |
| 690 | currentWidth += tokenWidth |
| 691 | } |
| 692 | } |
| 693 | |
| 694 | if (currentLine) lines.push(currentLine.trimEnd()) |
| 695 | return lines.length > 0 ? lines : [''] |
| 696 | } |
| 697 | |
| 698 | /** |
| 699 | * Pads text to reach exact width using spaces. |