@logtape/pretty 1.0.0-dev.231

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,99 @@
1
+ import { getDisplayWidth, stripAnsi } from "./wcwidth.js";
2
+
3
+ //#region wordwrap.ts
4
+ /**
5
+ * Wrap text at specified width with proper indentation for continuation lines.
6
+ * Automatically detects the message start position from the first line.
7
+ *
8
+ * @param text The text to wrap (may contain ANSI escape codes)
9
+ * @param maxWidth Maximum width in terminal columns
10
+ * @param messageContent The plain message content (used to find message start)
11
+ * @returns Wrapped text with proper indentation
12
+ */
13
+ function wrapText(text, maxWidth, messageContent) {
14
+ if (maxWidth <= 0) return text;
15
+ const displayWidth = getDisplayWidth(text);
16
+ if (displayWidth <= maxWidth && !text.includes("\n")) return text;
17
+ const firstLineWords = messageContent.split(" ");
18
+ const firstWord = firstLineWords[0];
19
+ const plainText = stripAnsi(text);
20
+ const messageStartIndex = plainText.indexOf(firstWord);
21
+ let indentWidth = 0;
22
+ if (messageStartIndex >= 0) {
23
+ const prefixText = plainText.slice(0, messageStartIndex);
24
+ indentWidth = getDisplayWidth(prefixText);
25
+ }
26
+ const indent = " ".repeat(Math.max(0, indentWidth));
27
+ if (text.includes("\n")) {
28
+ const lines = text.split("\n");
29
+ const wrappedLines = [];
30
+ for (let i = 0; i < lines.length; i++) {
31
+ const line = lines[i];
32
+ const lineDisplayWidth = getDisplayWidth(line);
33
+ if (lineDisplayWidth <= maxWidth) if (i === 0) wrappedLines.push(line);
34
+ else wrappedLines.push(indent + line);
35
+ else {
36
+ const wrappedLine = wrapSingleLine(line, maxWidth, indent);
37
+ if (i === 0) wrappedLines.push(wrappedLine);
38
+ else {
39
+ const subLines = wrappedLine.split("\n");
40
+ for (let j = 0; j < subLines.length; j++) if (j === 0) wrappedLines.push(indent + subLines[j]);
41
+ else wrappedLines.push(subLines[j]);
42
+ }
43
+ }
44
+ }
45
+ return wrappedLines.join("\n");
46
+ }
47
+ return wrapSingleLine(text, maxWidth, indent);
48
+ }
49
+ /**
50
+ * Wrap a single line of text (without existing newlines) at word boundaries.
51
+ * Preserves ANSI escape codes and handles Unicode character widths correctly.
52
+ *
53
+ * @param text The text to wrap (single line, may contain ANSI codes)
54
+ * @param maxWidth Maximum width in terminal columns
55
+ * @param indent Indentation string for continuation lines
56
+ * @returns Wrapped text with newlines and proper indentation
57
+ */
58
+ function wrapSingleLine(text, maxWidth, indent) {
59
+ const lines = [];
60
+ let currentLine = "";
61
+ let currentDisplayWidth = 0;
62
+ let i = 0;
63
+ while (i < text.length) {
64
+ if (text[i] === "\x1B" && text[i + 1] === "[") {
65
+ let j = i + 2;
66
+ while (j < text.length && text[j] !== "m") j++;
67
+ if (j < text.length) {
68
+ j++;
69
+ currentLine += text.slice(i, j);
70
+ i = j;
71
+ continue;
72
+ }
73
+ }
74
+ const char = text[i];
75
+ if (currentDisplayWidth >= maxWidth && char !== " ") {
76
+ const breakPoint = currentLine.lastIndexOf(" ");
77
+ if (breakPoint > 0) {
78
+ lines.push(currentLine.slice(0, breakPoint));
79
+ currentLine = indent + currentLine.slice(breakPoint + 1) + char;
80
+ currentDisplayWidth = getDisplayWidth(currentLine);
81
+ } else {
82
+ lines.push(currentLine);
83
+ currentLine = indent + char;
84
+ currentDisplayWidth = getDisplayWidth(currentLine);
85
+ }
86
+ } else {
87
+ currentLine += char;
88
+ currentDisplayWidth = getDisplayWidth(currentLine);
89
+ }
90
+ i++;
91
+ }
92
+ if (currentLine.trim()) lines.push(currentLine);
93
+ const filteredLines = lines.filter((line) => line.trim().length > 0);
94
+ return filteredLines.join("\n");
95
+ }
96
+
97
+ //#endregion
98
+ export { wrapText };
99
+ //# sourceMappingURL=wordwrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wordwrap.js","names":["text: string","maxWidth: number","messageContent: string","wrappedLines: string[]","indent: string","lines: string[]"],"sources":["../wordwrap.ts"],"sourcesContent":["/**\n * @fileoverview\n * Word wrapping utilities for terminal output\n *\n * This module provides functions for wrapping text at specified widths\n * while preserving proper indentation and handling Unicode characters\n * correctly.\n */\n\nimport { getDisplayWidth, stripAnsi } from \"./wcwidth.ts\";\n\n/**\n * Wrap text at specified width with proper indentation for continuation lines.\n * Automatically detects the message start position from the first line.\n *\n * @param text The text to wrap (may contain ANSI escape codes)\n * @param maxWidth Maximum width in terminal columns\n * @param messageContent The plain message content (used to find message start)\n * @returns Wrapped text with proper indentation\n */\nexport function wrapText(\n text: string,\n maxWidth: number,\n messageContent: string,\n): string {\n if (maxWidth <= 0) return text;\n\n const displayWidth = getDisplayWidth(text);\n // If text has newlines (multiline interpolated values), always process it\n // even if it fits within the width\n if (displayWidth <= maxWidth && !text.includes(\"\\n\")) return text;\n\n // Find where the message content starts in the first line\n const firstLineWords = messageContent.split(\" \");\n const firstWord = firstLineWords[0];\n const plainText = stripAnsi(text);\n const messageStartIndex = plainText.indexOf(firstWord);\n\n // Calculate the display width of the text up to the message start\n // This is crucial for proper alignment when emojis are present\n let indentWidth = 0;\n if (messageStartIndex >= 0) {\n const prefixText = plainText.slice(0, messageStartIndex);\n indentWidth = getDisplayWidth(prefixText);\n }\n const indent = \" \".repeat(Math.max(0, indentWidth));\n\n // Check if text contains newlines (from interpolated values like Error objects)\n if (text.includes(\"\\n\")) {\n // Split by existing newlines and process each line\n const lines = text.split(\"\\n\");\n const wrappedLines: string[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const lineDisplayWidth = getDisplayWidth(line);\n\n if (lineDisplayWidth <= maxWidth) {\n // Line doesn't need wrapping, but add indentation if it's not the first line\n if (i === 0) {\n wrappedLines.push(line);\n } else {\n wrappedLines.push(indent + line);\n }\n } else {\n // Line needs wrapping\n const wrappedLine = wrapSingleLine(line, maxWidth, indent);\n if (i === 0) {\n wrappedLines.push(wrappedLine);\n } else {\n // For continuation lines from interpolated values, add proper indentation\n const subLines = wrappedLine.split(\"\\n\");\n for (let j = 0; j < subLines.length; j++) {\n if (j === 0) {\n wrappedLines.push(indent + subLines[j]);\n } else {\n wrappedLines.push(subLines[j]);\n }\n }\n }\n }\n }\n\n return wrappedLines.join(\"\\n\");\n }\n\n // Process as a single line since log records should not have newlines in the formatted output\n return wrapSingleLine(text, maxWidth, indent);\n}\n\n/**\n * Wrap a single line of text (without existing newlines) at word boundaries.\n * Preserves ANSI escape codes and handles Unicode character widths correctly.\n *\n * @param text The text to wrap (single line, may contain ANSI codes)\n * @param maxWidth Maximum width in terminal columns\n * @param indent Indentation string for continuation lines\n * @returns Wrapped text with newlines and proper indentation\n */\nexport function wrapSingleLine(\n text: string,\n maxWidth: number,\n indent: string,\n): string {\n // Split text into chunks while preserving ANSI codes\n const lines: string[] = [];\n let currentLine = \"\";\n let currentDisplayWidth = 0;\n let i = 0;\n\n while (i < text.length) {\n // Check for ANSI escape sequence\n if (text[i] === \"\\x1b\" && text[i + 1] === \"[\") {\n // Find the end of the ANSI sequence\n let j = i + 2;\n while (j < text.length && text[j] !== \"m\") {\n j++;\n }\n if (j < text.length) {\n j++; // Include the 'm'\n currentLine += text.slice(i, j);\n i = j;\n continue;\n }\n }\n\n const char = text[i];\n\n // Check if adding this character would exceed the width\n if (currentDisplayWidth >= maxWidth && char !== \" \") {\n // Try to find a good break point (space) before the current position\n const breakPoint = currentLine.lastIndexOf(\" \");\n if (breakPoint > 0) {\n // Break at the space\n lines.push(currentLine.slice(0, breakPoint));\n currentLine = indent + currentLine.slice(breakPoint + 1) + char;\n currentDisplayWidth = getDisplayWidth(currentLine);\n } else {\n // No space found, hard break\n lines.push(currentLine);\n currentLine = indent + char;\n currentDisplayWidth = getDisplayWidth(currentLine);\n }\n } else {\n currentLine += char;\n // Recalculate display width properly for Unicode characters\n currentDisplayWidth = getDisplayWidth(currentLine);\n }\n\n i++;\n }\n\n if (currentLine.trim()) {\n lines.push(currentLine);\n }\n\n // Filter out empty lines (lines with only indentation/spaces)\n const filteredLines = lines.filter((line) => line.trim().length > 0);\n\n return filteredLines.join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;;AAoBA,SAAgB,SACdA,MACAC,UACAC,gBACQ;AACR,KAAI,YAAY,EAAG,QAAO;CAE1B,MAAM,eAAe,gBAAgB,KAAK;AAG1C,KAAI,gBAAgB,aAAa,KAAK,SAAS,KAAK,CAAE,QAAO;CAG7D,MAAM,iBAAiB,eAAe,MAAM,IAAI;CAChD,MAAM,YAAY,eAAe;CACjC,MAAM,YAAY,UAAU,KAAK;CACjC,MAAM,oBAAoB,UAAU,QAAQ,UAAU;CAItD,IAAI,cAAc;AAClB,KAAI,qBAAqB,GAAG;EAC1B,MAAM,aAAa,UAAU,MAAM,GAAG,kBAAkB;AACxD,gBAAc,gBAAgB,WAAW;CAC1C;CACD,MAAM,SAAS,IAAI,OAAO,KAAK,IAAI,GAAG,YAAY,CAAC;AAGnD,KAAI,KAAK,SAAS,KAAK,EAAE;EAEvB,MAAM,QAAQ,KAAK,MAAM,KAAK;EAC9B,MAAMC,eAAyB,CAAE;AAEjC,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,OAAO,MAAM;GACnB,MAAM,mBAAmB,gBAAgB,KAAK;AAE9C,OAAI,oBAAoB,SAEtB,KAAI,MAAM,EACR,cAAa,KAAK,KAAK;OAEvB,cAAa,KAAK,SAAS,KAAK;QAE7B;IAEL,MAAM,cAAc,eAAe,MAAM,UAAU,OAAO;AAC1D,QAAI,MAAM,EACR,cAAa,KAAK,YAAY;SACzB;KAEL,MAAM,WAAW,YAAY,MAAM,KAAK;AACxC,UAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,IACnC,KAAI,MAAM,EACR,cAAa,KAAK,SAAS,SAAS,GAAG;SAEvC,cAAa,KAAK,SAAS,GAAG;IAGnC;GACF;EACF;AAED,SAAO,aAAa,KAAK,KAAK;CAC/B;AAGD,QAAO,eAAe,MAAM,UAAU,OAAO;AAC9C;;;;;;;;;;AAWD,SAAgB,eACdH,MACAC,UACAG,QACQ;CAER,MAAMC,QAAkB,CAAE;CAC1B,IAAI,cAAc;CAClB,IAAI,sBAAsB;CAC1B,IAAI,IAAI;AAER,QAAO,IAAI,KAAK,QAAQ;AAEtB,MAAI,KAAK,OAAO,UAAU,KAAK,IAAI,OAAO,KAAK;GAE7C,IAAI,IAAI,IAAI;AACZ,UAAO,IAAI,KAAK,UAAU,KAAK,OAAO,IACpC;AAEF,OAAI,IAAI,KAAK,QAAQ;AACnB;AACA,mBAAe,KAAK,MAAM,GAAG,EAAE;AAC/B,QAAI;AACJ;GACD;EACF;EAED,MAAM,OAAO,KAAK;AAGlB,MAAI,uBAAuB,YAAY,SAAS,KAAK;GAEnD,MAAM,aAAa,YAAY,YAAY,IAAI;AAC/C,OAAI,aAAa,GAAG;AAElB,UAAM,KAAK,YAAY,MAAM,GAAG,WAAW,CAAC;AAC5C,kBAAc,SAAS,YAAY,MAAM,aAAa,EAAE,GAAG;AAC3D,0BAAsB,gBAAgB,YAAY;GACnD,OAAM;AAEL,UAAM,KAAK,YAAY;AACvB,kBAAc,SAAS;AACvB,0BAAsB,gBAAgB,YAAY;GACnD;EACF,OAAM;AACL,kBAAe;AAEf,yBAAsB,gBAAgB,YAAY;EACnD;AAED;CACD;AAED,KAAI,YAAY,MAAM,CACpB,OAAM,KAAK,YAAY;CAIzB,MAAM,gBAAgB,MAAM,OAAO,CAAC,SAAS,KAAK,MAAM,CAAC,SAAS,EAAE;AAEpE,QAAO,cAAc,KAAK,KAAK;AAChC"}