Spaces:
Paused
Paused
| import { note as clackNote } from "@clack/prompts"; | |
| import { visibleWidth } from "./ansi.js"; | |
| import { stylePromptTitle } from "./prompt-style.js"; | |
| function splitLongWord(word: string, maxLen: number): string[] { | |
| if (maxLen <= 0) { | |
| return [word]; | |
| } | |
| const chars = Array.from(word); | |
| const parts: string[] = []; | |
| for (let i = 0; i < chars.length; i += maxLen) { | |
| parts.push(chars.slice(i, i + maxLen).join("")); | |
| } | |
| return parts.length > 0 ? parts : [word]; | |
| } | |
| function wrapLine(line: string, maxWidth: number): string[] { | |
| if (line.trim().length === 0) { | |
| return [line]; | |
| } | |
| const match = line.match(/^(\s*)([-*\u2022]\s+)?(.*)$/); | |
| const indent = match?.[1] ?? ""; | |
| const bullet = match?.[2] ?? ""; | |
| const content = match?.[3] ?? ""; | |
| const firstPrefix = `${indent}${bullet}`; | |
| const nextPrefix = `${indent}${bullet ? " ".repeat(bullet.length) : ""}`; | |
| const firstWidth = Math.max(10, maxWidth - visibleWidth(firstPrefix)); | |
| const nextWidth = Math.max(10, maxWidth - visibleWidth(nextPrefix)); | |
| const words = content.split(/\s+/).filter(Boolean); | |
| const lines: string[] = []; | |
| let current = ""; | |
| let prefix = firstPrefix; | |
| let available = firstWidth; | |
| for (const word of words) { | |
| if (!current) { | |
| if (visibleWidth(word) > available) { | |
| const parts = splitLongWord(word, available); | |
| const first = parts.shift() ?? ""; | |
| lines.push(prefix + first); | |
| prefix = nextPrefix; | |
| available = nextWidth; | |
| for (const part of parts) { | |
| lines.push(prefix + part); | |
| } | |
| continue; | |
| } | |
| current = word; | |
| continue; | |
| } | |
| const candidate = `${current} ${word}`; | |
| if (visibleWidth(candidate) <= available) { | |
| current = candidate; | |
| continue; | |
| } | |
| lines.push(prefix + current); | |
| prefix = nextPrefix; | |
| available = nextWidth; | |
| if (visibleWidth(word) > available) { | |
| const parts = splitLongWord(word, available); | |
| const first = parts.shift() ?? ""; | |
| lines.push(prefix + first); | |
| for (const part of parts) { | |
| lines.push(prefix + part); | |
| } | |
| current = ""; | |
| continue; | |
| } | |
| current = word; | |
| } | |
| if (current || words.length === 0) { | |
| lines.push(prefix + current); | |
| } | |
| return lines; | |
| } | |
| export function wrapNoteMessage( | |
| message: string, | |
| options: { maxWidth?: number; columns?: number } = {}, | |
| ): string { | |
| const columns = options.columns ?? process.stdout.columns ?? 80; | |
| const maxWidth = options.maxWidth ?? Math.max(40, Math.min(88, columns - 10)); | |
| return message | |
| .split("\n") | |
| .flatMap((line) => wrapLine(line, maxWidth)) | |
| .join("\n"); | |
| } | |
| export function note(message: string, title?: string) { | |
| clackNote(wrapNoteMessage(message), stylePromptTitle(title)); | |
| } | |