@elizaos/tui 2.0.0-alpha.10
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.
- package/README.md +761 -0
- package/dist/autocomplete.d.ts +48 -0
- package/dist/autocomplete.d.ts.map +1 -0
- package/dist/autocomplete.js +555 -0
- package/dist/components/box.d.ts +22 -0
- package/dist/components/box.d.ts.map +1 -0
- package/dist/components/box.js +103 -0
- package/dist/components/cancellable-loader.d.ts +22 -0
- package/dist/components/cancellable-loader.d.ts.map +1 -0
- package/dist/components/cancellable-loader.js +34 -0
- package/dist/components/editor/history.d.ts +38 -0
- package/dist/components/editor/history.d.ts.map +1 -0
- package/dist/components/editor/history.js +76 -0
- package/dist/components/editor/index.d.ts +18 -0
- package/dist/components/editor/index.d.ts.map +1 -0
- package/dist/components/editor/index.js +21 -0
- package/dist/components/editor/kill-ring.d.ts +41 -0
- package/dist/components/editor/kill-ring.d.ts.map +1 -0
- package/dist/components/editor/kill-ring.js +81 -0
- package/dist/components/editor/layout.d.ts +40 -0
- package/dist/components/editor/layout.d.ts.map +1 -0
- package/dist/components/editor/layout.js +205 -0
- package/dist/components/editor/types.d.ts +68 -0
- package/dist/components/editor/types.d.ts.map +1 -0
- package/dist/components/editor/types.js +4 -0
- package/dist/components/editor/undo.d.ts +46 -0
- package/dist/components/editor/undo.d.ts.map +1 -0
- package/dist/components/editor/undo.js +58 -0
- package/dist/components/editor.d.ts +196 -0
- package/dist/components/editor.d.ts.map +1 -0
- package/dist/components/editor.js +1707 -0
- package/dist/components/image.d.ts +28 -0
- package/dist/components/image.d.ts.map +1 -0
- package/dist/components/image.js +68 -0
- package/dist/components/input.d.ts +19 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.js +195 -0
- package/dist/components/loader.d.ts +21 -0
- package/dist/components/loader.d.ts.map +1 -0
- package/dist/components/loader.js +49 -0
- package/dist/components/markdown/index.d.ts +13 -0
- package/dist/components/markdown/index.d.ts.map +1 -0
- package/dist/components/markdown/index.js +9 -0
- package/dist/components/markdown/inline-renderer.d.ts +22 -0
- package/dist/components/markdown/inline-renderer.d.ts.map +1 -0
- package/dist/components/markdown/inline-renderer.js +88 -0
- package/dist/components/markdown/list-renderer.d.ts +33 -0
- package/dist/components/markdown/list-renderer.d.ts.map +1 -0
- package/dist/components/markdown/list-renderer.js +110 -0
- package/dist/components/markdown/table-renderer.d.ts +43 -0
- package/dist/components/markdown/table-renderer.d.ts.map +1 -0
- package/dist/components/markdown/table-renderer.js +184 -0
- package/dist/components/markdown/types.d.ts +57 -0
- package/dist/components/markdown/types.d.ts.map +1 -0
- package/dist/components/markdown/types.js +13 -0
- package/dist/components/markdown.d.ts +44 -0
- package/dist/components/markdown.d.ts.map +1 -0
- package/dist/components/markdown.js +319 -0
- package/dist/components/progress-bar.d.ts +67 -0
- package/dist/components/progress-bar.d.ts.map +1 -0
- package/dist/components/progress-bar.js +124 -0
- package/dist/components/select-list.d.ts +32 -0
- package/dist/components/select-list.d.ts.map +1 -0
- package/dist/components/select-list.js +151 -0
- package/dist/components/settings-list.d.ts +50 -0
- package/dist/components/settings-list.d.ts.map +1 -0
- package/dist/components/settings-list.js +184 -0
- package/dist/components/spacer.d.ts +12 -0
- package/dist/components/spacer.d.ts.map +1 -0
- package/dist/components/spacer.js +22 -0
- package/dist/components/text.d.ts +19 -0
- package/dist/components/text.d.ts.map +1 -0
- package/dist/components/text.js +88 -0
- package/dist/components/toast.d.ts +73 -0
- package/dist/components/toast.d.ts.map +1 -0
- package/dist/components/toast.js +119 -0
- package/dist/components/truncated-text.d.ts +13 -0
- package/dist/components/truncated-text.d.ts.map +1 -0
- package/dist/components/truncated-text.js +50 -0
- package/dist/constants.d.ts +97 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +126 -0
- package/dist/core/container.d.ts +32 -0
- package/dist/core/container.d.ts.map +1 -0
- package/dist/core/container.js +49 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +10 -0
- package/dist/core/overlay.d.ts +44 -0
- package/dist/core/overlay.d.ts.map +1 -0
- package/dist/core/overlay.js +171 -0
- package/dist/core/types.d.ts +116 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +14 -0
- package/dist/editor-component.d.ts +37 -0
- package/dist/editor-component.d.ts.map +1 -0
- package/dist/editor-component.js +1 -0
- package/dist/fuzzy.d.ts +16 -0
- package/dist/fuzzy.d.ts.map +1 -0
- package/dist/fuzzy.js +108 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/keybindings.d.ts +39 -0
- package/dist/keybindings.d.ts.map +1 -0
- package/dist/keybindings.js +113 -0
- package/dist/keys.d.ts +153 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +951 -0
- package/dist/stdin-buffer.d.ts +48 -0
- package/dist/stdin-buffer.d.ts.map +1 -0
- package/dist/stdin-buffer.js +316 -0
- package/dist/terminal-image.d.ts +68 -0
- package/dist/terminal-image.d.ts.map +1 -0
- package/dist/terminal-image.js +287 -0
- package/dist/terminal.d.ts +71 -0
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +216 -0
- package/dist/themes/index.d.ts +103 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/index.js +161 -0
- package/dist/tui.d.ts +90 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +745 -0
- package/dist/types/marked-tokens.d.ts +57 -0
- package/dist/types/marked-tokens.d.ts.map +1 -0
- package/dist/types/marked-tokens.js +17 -0
- package/dist/utils/cursor-movement.d.ts +127 -0
- package/dist/utils/cursor-movement.d.ts.map +1 -0
- package/dist/utils/cursor-movement.js +251 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/paste-handler.d.ts +86 -0
- package/dist/utils/paste-handler.d.ts.map +1 -0
- package/dist/utils/paste-handler.js +121 -0
- package/dist/utils.d.ts +75 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +796 -0
- package/package.json +53 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List rendering utilities for Markdown component.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Render a list with proper nesting support.
|
|
6
|
+
*
|
|
7
|
+
* @param token - The list token to render
|
|
8
|
+
* @param depth - Current nesting depth (0 for top-level)
|
|
9
|
+
* @param context - Rendering context with theme and inline renderer
|
|
10
|
+
* @returns Array of rendered lines
|
|
11
|
+
*/
|
|
12
|
+
export function renderList(token, depth, context) {
|
|
13
|
+
const lines = [];
|
|
14
|
+
const indent = " ".repeat(depth);
|
|
15
|
+
// Use the list's start property (defaults to 1 for ordered lists)
|
|
16
|
+
const startNumber = typeof token.start === "number" ? token.start : 1;
|
|
17
|
+
for (let i = 0; i < token.items.length; i++) {
|
|
18
|
+
const item = token.items[i];
|
|
19
|
+
const bullet = token.ordered ? `${startNumber + i}. ` : "- ";
|
|
20
|
+
// Process item tokens to handle nested lists
|
|
21
|
+
const itemLines = renderListItem(item.tokens || [], depth, context);
|
|
22
|
+
if (itemLines.length > 0) {
|
|
23
|
+
// First line - check if it's a nested list
|
|
24
|
+
// A nested list will start with indent (spaces) followed by cyan bullet
|
|
25
|
+
const firstLine = itemLines[0];
|
|
26
|
+
const isNestedList = /^\s+\x1b\[36m[-\d]/.test(firstLine); // starts with spaces + cyan + bullet char
|
|
27
|
+
if (isNestedList) {
|
|
28
|
+
// This is a nested list, just add it as-is (already has full indent)
|
|
29
|
+
lines.push(firstLine);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// Regular text content - add indent and bullet
|
|
33
|
+
lines.push(indent + context.theme.listBullet(bullet) + firstLine);
|
|
34
|
+
}
|
|
35
|
+
// Rest of the lines
|
|
36
|
+
for (let j = 1; j < itemLines.length; j++) {
|
|
37
|
+
const line = itemLines[j];
|
|
38
|
+
const isNestedListLine = /^\s+\x1b\[36m[-\d]/.test(line); // starts with spaces + cyan + bullet char
|
|
39
|
+
if (isNestedListLine) {
|
|
40
|
+
// Nested list line - already has full indent
|
|
41
|
+
lines.push(line);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Regular content - add parent indent + 2 spaces for continuation
|
|
45
|
+
lines.push(`${indent} ${line}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
lines.push(indent + context.theme.listBullet(bullet));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return lines;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Render list item tokens, handling nested lists.
|
|
57
|
+
* Returns lines WITHOUT the parent indent (renderList will add it).
|
|
58
|
+
*
|
|
59
|
+
* @param tokens - Tokens from the list item
|
|
60
|
+
* @param parentDepth - Depth of the parent list
|
|
61
|
+
* @param context - Rendering context with theme and inline renderer
|
|
62
|
+
* @returns Array of rendered lines
|
|
63
|
+
*/
|
|
64
|
+
export function renderListItem(tokens, parentDepth, context) {
|
|
65
|
+
const lines = [];
|
|
66
|
+
for (const token of tokens) {
|
|
67
|
+
if (token.type === "list") {
|
|
68
|
+
// Nested list - render with one additional indent level
|
|
69
|
+
// These lines will have their own indent, so we just add them as-is
|
|
70
|
+
const nestedLines = renderList(token, parentDepth + 1, context);
|
|
71
|
+
lines.push(...nestedLines);
|
|
72
|
+
}
|
|
73
|
+
else if (token.type === "text") {
|
|
74
|
+
// Text content (may have inline tokens)
|
|
75
|
+
const text = token.tokens && token.tokens.length > 0 ? context.renderInlineTokens(token.tokens) : token.text || "";
|
|
76
|
+
lines.push(text);
|
|
77
|
+
}
|
|
78
|
+
else if (token.type === "paragraph") {
|
|
79
|
+
// Paragraph in list item
|
|
80
|
+
const text = context.renderInlineTokens(token.tokens || []);
|
|
81
|
+
lines.push(text);
|
|
82
|
+
}
|
|
83
|
+
else if (token.type === "code") {
|
|
84
|
+
// Code block in list item
|
|
85
|
+
const indent = context.theme.codeBlockIndent ?? " ";
|
|
86
|
+
lines.push(context.theme.codeBlockBorder(`\`\`\`${token.lang || ""}`));
|
|
87
|
+
if (context.theme.highlightCode) {
|
|
88
|
+
const highlightedLines = context.theme.highlightCode(token.text, token.lang);
|
|
89
|
+
for (const hlLine of highlightedLines) {
|
|
90
|
+
lines.push(`${indent}${hlLine}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const codeLines = token.text.split("\n");
|
|
95
|
+
for (const codeLine of codeLines) {
|
|
96
|
+
lines.push(`${indent}${context.theme.codeBlock(codeLine)}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
lines.push(context.theme.codeBlockBorder("```"));
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// Other token types - try to render as inline
|
|
103
|
+
const text = context.renderInlineTokens([token]);
|
|
104
|
+
if (text) {
|
|
105
|
+
lines.push(text);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return lines;
|
|
110
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table rendering utilities for Markdown component.
|
|
3
|
+
*/
|
|
4
|
+
import type { Token } from "marked";
|
|
5
|
+
import type { TableToken } from "../../types/marked-tokens.js";
|
|
6
|
+
import type { InlineStyleContext, MarkdownTheme } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Context for table rendering operations.
|
|
9
|
+
*/
|
|
10
|
+
export interface TableRenderContext {
|
|
11
|
+
theme: MarkdownTheme;
|
|
12
|
+
renderInlineTokens: (tokens: Token[], styleContext?: InlineStyleContext) => string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get the visible width of the longest word in a string.
|
|
16
|
+
*
|
|
17
|
+
* @param text - Text to analyze
|
|
18
|
+
* @param maxWidth - Optional maximum width to cap the result
|
|
19
|
+
* @returns Width of the longest word (or maxWidth if exceeded)
|
|
20
|
+
*/
|
|
21
|
+
export declare function getLongestWordWidth(text: string, maxWidth?: number): number;
|
|
22
|
+
/**
|
|
23
|
+
* Wrap a table cell to fit into a column.
|
|
24
|
+
*
|
|
25
|
+
* Delegates to wrapTextWithAnsi() so ANSI codes + long tokens are handled
|
|
26
|
+
* consistently with the rest of the renderer.
|
|
27
|
+
*
|
|
28
|
+
* @param text - Cell text to wrap
|
|
29
|
+
* @param maxWidth - Maximum width for wrapping
|
|
30
|
+
* @returns Array of wrapped lines
|
|
31
|
+
*/
|
|
32
|
+
export declare function wrapCellText(text: string, maxWidth: number): string[];
|
|
33
|
+
/**
|
|
34
|
+
* Render a table with width-aware cell wrapping.
|
|
35
|
+
* Cells that don't fit are wrapped to multiple lines.
|
|
36
|
+
*
|
|
37
|
+
* @param token - The table token to render
|
|
38
|
+
* @param availableWidth - Available width for the table
|
|
39
|
+
* @param context - Rendering context with theme and inline renderer
|
|
40
|
+
* @returns Array of rendered lines
|
|
41
|
+
*/
|
|
42
|
+
export declare function renderTable(token: TableToken, availableWidth: number, context: TableRenderContext): string[];
|
|
43
|
+
//# sourceMappingURL=table-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table-renderer.d.ts","sourceRoot":"","sources":["../../../src/components/markdown/table-renderer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,aAAa,CAAC;IACrB,kBAAkB,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,YAAY,CAAC,EAAE,kBAAkB,KAAK,MAAM,CAAC;CACnF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAU3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAErE;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAgK5G"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table rendering utilities for Markdown component.
|
|
3
|
+
*/
|
|
4
|
+
import { visibleWidth, wrapTextWithAnsi } from "../../utils.js";
|
|
5
|
+
/**
|
|
6
|
+
* Get the visible width of the longest word in a string.
|
|
7
|
+
*
|
|
8
|
+
* @param text - Text to analyze
|
|
9
|
+
* @param maxWidth - Optional maximum width to cap the result
|
|
10
|
+
* @returns Width of the longest word (or maxWidth if exceeded)
|
|
11
|
+
*/
|
|
12
|
+
export function getLongestWordWidth(text, maxWidth) {
|
|
13
|
+
const words = text.split(/\s+/).filter((word) => word.length > 0);
|
|
14
|
+
let longest = 0;
|
|
15
|
+
for (const word of words) {
|
|
16
|
+
longest = Math.max(longest, visibleWidth(word));
|
|
17
|
+
}
|
|
18
|
+
if (maxWidth === undefined) {
|
|
19
|
+
return longest;
|
|
20
|
+
}
|
|
21
|
+
return Math.min(longest, maxWidth);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Wrap a table cell to fit into a column.
|
|
25
|
+
*
|
|
26
|
+
* Delegates to wrapTextWithAnsi() so ANSI codes + long tokens are handled
|
|
27
|
+
* consistently with the rest of the renderer.
|
|
28
|
+
*
|
|
29
|
+
* @param text - Cell text to wrap
|
|
30
|
+
* @param maxWidth - Maximum width for wrapping
|
|
31
|
+
* @returns Array of wrapped lines
|
|
32
|
+
*/
|
|
33
|
+
export function wrapCellText(text, maxWidth) {
|
|
34
|
+
return wrapTextWithAnsi(text, Math.max(1, maxWidth));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Render a table with width-aware cell wrapping.
|
|
38
|
+
* Cells that don't fit are wrapped to multiple lines.
|
|
39
|
+
*
|
|
40
|
+
* @param token - The table token to render
|
|
41
|
+
* @param availableWidth - Available width for the table
|
|
42
|
+
* @param context - Rendering context with theme and inline renderer
|
|
43
|
+
* @returns Array of rendered lines
|
|
44
|
+
*/
|
|
45
|
+
export function renderTable(token, availableWidth, context) {
|
|
46
|
+
const lines = [];
|
|
47
|
+
const numCols = token.header.length;
|
|
48
|
+
if (numCols === 0) {
|
|
49
|
+
return lines;
|
|
50
|
+
}
|
|
51
|
+
// Calculate border overhead: "│ " + (n-1) * " │ " + " │"
|
|
52
|
+
// = 2 + (n-1) * 3 + 2 = 3n + 1
|
|
53
|
+
const borderOverhead = 3 * numCols + 1;
|
|
54
|
+
const availableForCells = availableWidth - borderOverhead;
|
|
55
|
+
if (availableForCells < numCols) {
|
|
56
|
+
// Too narrow to render a stable table. Fall back to raw markdown.
|
|
57
|
+
const fallbackLines = token.raw ? wrapTextWithAnsi(token.raw, availableWidth) : [];
|
|
58
|
+
fallbackLines.push("");
|
|
59
|
+
return fallbackLines;
|
|
60
|
+
}
|
|
61
|
+
const maxUnbrokenWordWidth = 30;
|
|
62
|
+
// Calculate natural column widths (what each column needs without constraints)
|
|
63
|
+
const naturalWidths = [];
|
|
64
|
+
const minWordWidths = [];
|
|
65
|
+
for (let i = 0; i < numCols; i++) {
|
|
66
|
+
const headerText = context.renderInlineTokens(token.header[i].tokens || []);
|
|
67
|
+
naturalWidths[i] = visibleWidth(headerText);
|
|
68
|
+
minWordWidths[i] = Math.max(1, getLongestWordWidth(headerText, maxUnbrokenWordWidth));
|
|
69
|
+
}
|
|
70
|
+
for (const row of token.rows) {
|
|
71
|
+
for (let i = 0; i < row.length; i++) {
|
|
72
|
+
const cellText = context.renderInlineTokens(row[i].tokens || []);
|
|
73
|
+
naturalWidths[i] = Math.max(naturalWidths[i] || 0, visibleWidth(cellText));
|
|
74
|
+
minWordWidths[i] = Math.max(minWordWidths[i] || 1, getLongestWordWidth(cellText, maxUnbrokenWordWidth));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
let minColumnWidths = minWordWidths;
|
|
78
|
+
let minCellsWidth = minColumnWidths.reduce((a, b) => a + b, 0);
|
|
79
|
+
if (minCellsWidth > availableForCells) {
|
|
80
|
+
minColumnWidths = new Array(numCols).fill(1);
|
|
81
|
+
const remaining = availableForCells - numCols;
|
|
82
|
+
if (remaining > 0) {
|
|
83
|
+
const totalWeight = minWordWidths.reduce((total, width) => total + Math.max(0, width - 1), 0);
|
|
84
|
+
const growth = minWordWidths.map((width) => {
|
|
85
|
+
const weight = Math.max(0, width - 1);
|
|
86
|
+
return totalWeight > 0 ? Math.floor((weight / totalWeight) * remaining) : 0;
|
|
87
|
+
});
|
|
88
|
+
for (let i = 0; i < numCols; i++) {
|
|
89
|
+
minColumnWidths[i] += growth[i];
|
|
90
|
+
}
|
|
91
|
+
const allocated = growth.reduce((total, width) => total + width, 0);
|
|
92
|
+
let leftover = remaining - allocated;
|
|
93
|
+
for (let i = 0; leftover > 0 && i < numCols; i++) {
|
|
94
|
+
minColumnWidths[i]++;
|
|
95
|
+
leftover--;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
minCellsWidth = minColumnWidths.reduce((a, b) => a + b, 0);
|
|
99
|
+
}
|
|
100
|
+
// Calculate column widths that fit within available width
|
|
101
|
+
const totalNaturalWidth = naturalWidths.reduce((a, b) => a + b, 0) + borderOverhead;
|
|
102
|
+
let columnWidths;
|
|
103
|
+
if (totalNaturalWidth <= availableWidth) {
|
|
104
|
+
// Everything fits naturally
|
|
105
|
+
columnWidths = naturalWidths.map((width, index) => Math.max(width, minColumnWidths[index]));
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
// Need to shrink columns to fit
|
|
109
|
+
const totalGrowPotential = naturalWidths.reduce((total, width, index) => {
|
|
110
|
+
return total + Math.max(0, width - minColumnWidths[index]);
|
|
111
|
+
}, 0);
|
|
112
|
+
const extraWidth = Math.max(0, availableForCells - minCellsWidth);
|
|
113
|
+
columnWidths = minColumnWidths.map((minWidth, index) => {
|
|
114
|
+
const naturalWidth = naturalWidths[index];
|
|
115
|
+
const minWidthDelta = Math.max(0, naturalWidth - minWidth);
|
|
116
|
+
let grow = 0;
|
|
117
|
+
if (totalGrowPotential > 0) {
|
|
118
|
+
grow = Math.floor((minWidthDelta / totalGrowPotential) * extraWidth);
|
|
119
|
+
}
|
|
120
|
+
return minWidth + grow;
|
|
121
|
+
});
|
|
122
|
+
// Adjust for rounding errors - distribute remaining space
|
|
123
|
+
const allocated = columnWidths.reduce((a, b) => a + b, 0);
|
|
124
|
+
let remaining = availableForCells - allocated;
|
|
125
|
+
while (remaining > 0) {
|
|
126
|
+
let grew = false;
|
|
127
|
+
for (let i = 0; i < numCols && remaining > 0; i++) {
|
|
128
|
+
if (columnWidths[i] < naturalWidths[i]) {
|
|
129
|
+
columnWidths[i]++;
|
|
130
|
+
remaining--;
|
|
131
|
+
grew = true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (!grew) {
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Render top border
|
|
140
|
+
const topBorderCells = columnWidths.map((w) => "─".repeat(w));
|
|
141
|
+
lines.push(`┌─${topBorderCells.join("─┬─")}─┐`);
|
|
142
|
+
// Render header with wrapping
|
|
143
|
+
const headerCellLines = token.header.map((cell, i) => {
|
|
144
|
+
const text = context.renderInlineTokens(cell.tokens || []);
|
|
145
|
+
return wrapCellText(text, columnWidths[i]);
|
|
146
|
+
});
|
|
147
|
+
const headerLineCount = Math.max(...headerCellLines.map((c) => c.length));
|
|
148
|
+
for (let lineIdx = 0; lineIdx < headerLineCount; lineIdx++) {
|
|
149
|
+
const rowParts = headerCellLines.map((cellLines, colIdx) => {
|
|
150
|
+
const text = cellLines[lineIdx] || "";
|
|
151
|
+
const padded = text + " ".repeat(Math.max(0, columnWidths[colIdx] - visibleWidth(text)));
|
|
152
|
+
return context.theme.bold(padded);
|
|
153
|
+
});
|
|
154
|
+
lines.push(`│ ${rowParts.join(" │ ")} │`);
|
|
155
|
+
}
|
|
156
|
+
// Render separator
|
|
157
|
+
const separatorCells = columnWidths.map((w) => "─".repeat(w));
|
|
158
|
+
const separatorLine = `├─${separatorCells.join("─┼─")}─┤`;
|
|
159
|
+
lines.push(separatorLine);
|
|
160
|
+
// Render rows with wrapping
|
|
161
|
+
for (let rowIndex = 0; rowIndex < token.rows.length; rowIndex++) {
|
|
162
|
+
const row = token.rows[rowIndex];
|
|
163
|
+
const rowCellLines = row.map((cell, i) => {
|
|
164
|
+
const text = context.renderInlineTokens(cell.tokens || []);
|
|
165
|
+
return wrapCellText(text, columnWidths[i]);
|
|
166
|
+
});
|
|
167
|
+
const rowLineCount = Math.max(...rowCellLines.map((c) => c.length));
|
|
168
|
+
for (let lineIdx = 0; lineIdx < rowLineCount; lineIdx++) {
|
|
169
|
+
const rowParts = rowCellLines.map((cellLines, colIdx) => {
|
|
170
|
+
const text = cellLines[lineIdx] || "";
|
|
171
|
+
return text + " ".repeat(Math.max(0, columnWidths[colIdx] - visibleWidth(text)));
|
|
172
|
+
});
|
|
173
|
+
lines.push(`│ ${rowParts.join(" │ ")} │`);
|
|
174
|
+
}
|
|
175
|
+
if (rowIndex < token.rows.length - 1) {
|
|
176
|
+
lines.push(separatorLine);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Render bottom border
|
|
180
|
+
const bottomBorderCells = columnWidths.map((w) => "─".repeat(w));
|
|
181
|
+
lines.push(`└─${bottomBorderCells.join("─┴─")}─┘`);
|
|
182
|
+
lines.push(""); // Add spacing after table
|
|
183
|
+
return lines;
|
|
184
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the Markdown component.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Default text styling for markdown content.
|
|
6
|
+
* Applied to all text unless overridden by markdown formatting.
|
|
7
|
+
*/
|
|
8
|
+
export interface DefaultTextStyle {
|
|
9
|
+
/** Foreground color function */
|
|
10
|
+
color?: (text: string) => string;
|
|
11
|
+
/** Background color function */
|
|
12
|
+
bgColor?: (text: string) => string;
|
|
13
|
+
/** Bold text */
|
|
14
|
+
bold?: boolean;
|
|
15
|
+
/** Italic text */
|
|
16
|
+
italic?: boolean;
|
|
17
|
+
/** Strikethrough text */
|
|
18
|
+
strikethrough?: boolean;
|
|
19
|
+
/** Underline text */
|
|
20
|
+
underline?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Theme functions for markdown elements.
|
|
24
|
+
* Each function takes text and returns styled text with ANSI codes.
|
|
25
|
+
*/
|
|
26
|
+
export interface MarkdownTheme {
|
|
27
|
+
heading: (text: string) => string;
|
|
28
|
+
link: (text: string) => string;
|
|
29
|
+
linkUrl: (text: string) => string;
|
|
30
|
+
code: (text: string) => string;
|
|
31
|
+
codeBlock: (text: string) => string;
|
|
32
|
+
codeBlockBorder: (text: string) => string;
|
|
33
|
+
quote: (text: string) => string;
|
|
34
|
+
quoteBorder: (text: string) => string;
|
|
35
|
+
hr: (text: string) => string;
|
|
36
|
+
listBullet: (text: string) => string;
|
|
37
|
+
bold: (text: string) => string;
|
|
38
|
+
italic: (text: string) => string;
|
|
39
|
+
strikethrough: (text: string) => string;
|
|
40
|
+
underline: (text: string) => string;
|
|
41
|
+
highlightCode?: (code: string, lang?: string) => string[];
|
|
42
|
+
/** Prefix applied to each rendered code block line (default: " ") */
|
|
43
|
+
codeBlockIndent?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Context for inline token rendering, carrying style functions and prefixes.
|
|
47
|
+
*/
|
|
48
|
+
export interface InlineStyleContext {
|
|
49
|
+
applyText: (text: string) => string;
|
|
50
|
+
stylePrefix: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get the style prefix from a styling function.
|
|
54
|
+
* Uses a sentinel character to extract the ANSI prefix codes.
|
|
55
|
+
*/
|
|
56
|
+
export declare function getStylePrefix(styleFn: (text: string) => string): string;
|
|
57
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/markdown/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,gCAAgC;IAChC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,gCAAgC;IAChC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC,gBAAgB;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,kBAAkB;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yBAAyB;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAClC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAClC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/B,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAChC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7B,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IAC1D,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,CAKxE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the Markdown component.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Get the style prefix from a styling function.
|
|
6
|
+
* Uses a sentinel character to extract the ANSI prefix codes.
|
|
7
|
+
*/
|
|
8
|
+
export function getStylePrefix(styleFn) {
|
|
9
|
+
const sentinel = "\u0000";
|
|
10
|
+
const styled = styleFn(sentinel);
|
|
11
|
+
const sentinelIndex = styled.indexOf(sentinel);
|
|
12
|
+
return sentinelIndex >= 0 ? styled.slice(0, sentinelIndex) : "";
|
|
13
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Component } from "../tui.js";
|
|
2
|
+
export type { DefaultTextStyle, InlineStyleContext, MarkdownTheme } from "./markdown/types.js";
|
|
3
|
+
import type { DefaultTextStyle, MarkdownTheme } from "./markdown/types.js";
|
|
4
|
+
export declare class Markdown implements Component {
|
|
5
|
+
private text;
|
|
6
|
+
private paddingX;
|
|
7
|
+
private paddingY;
|
|
8
|
+
private defaultTextStyle?;
|
|
9
|
+
private theme;
|
|
10
|
+
private defaultStylePrefix?;
|
|
11
|
+
private cachedText?;
|
|
12
|
+
private cachedWidth?;
|
|
13
|
+
private cachedLines?;
|
|
14
|
+
constructor(text: string, paddingX: number, paddingY: number, theme: MarkdownTheme, defaultTextStyle?: DefaultTextStyle);
|
|
15
|
+
setText(text: string): void;
|
|
16
|
+
invalidate(): void;
|
|
17
|
+
render(width: number): string[];
|
|
18
|
+
/**
|
|
19
|
+
* Apply default text style to a string.
|
|
20
|
+
* This is the base styling applied to all text content.
|
|
21
|
+
* NOTE: Background color is NOT applied here - it's applied at the padding stage
|
|
22
|
+
* to ensure it extends to the full line width.
|
|
23
|
+
*/
|
|
24
|
+
private applyDefaultStyle;
|
|
25
|
+
private getDefaultStylePrefix;
|
|
26
|
+
private getDefaultInlineStyleContext;
|
|
27
|
+
private renderToken;
|
|
28
|
+
/**
|
|
29
|
+
* Render inline tokens to styled text.
|
|
30
|
+
* Delegates to the extracted inline-renderer utility.
|
|
31
|
+
*/
|
|
32
|
+
private renderInlineTokens;
|
|
33
|
+
/**
|
|
34
|
+
* Render a list with proper nesting support.
|
|
35
|
+
* Delegates to the extracted list-renderer utility.
|
|
36
|
+
*/
|
|
37
|
+
private renderList;
|
|
38
|
+
/**
|
|
39
|
+
* Render a table with width-aware cell wrapping.
|
|
40
|
+
* Delegates to the extracted table-renderer utility.
|
|
41
|
+
*/
|
|
42
|
+
private renderTable;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/components/markdown.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAe3C,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAG/F,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE3E,qBAAa,QAAS,YAAW,SAAS;IACzC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAC5C,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,kBAAkB,CAAC,CAAS;IAGpC,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAC,CAAW;gBAG9B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,aAAa,EACpB,gBAAgB,CAAC,EAAE,gBAAgB;IASpC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK3B,UAAU,IAAI,IAAI;IAMlB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAwF/B;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IA6BzB,OAAO,CAAC,qBAAqB;IAoC7B,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,WAAW;IA2HnB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAQ1B;;;OAGG;IACH,OAAO,CAAC,UAAU;IAQlB;;;OAGG;IACH,OAAO,CAAC,WAAW;CAOnB"}
|