@nicomatt69/streamtty 0.0.1 → 0.0.3
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/dist/ai-sdk-adapter.d.ts +1 -1
- package/dist/ai-sdk-adapter.d.ts.map +1 -1
- package/dist/ai-sdk-adapter.js +5 -9
- package/dist/ai-sdk-adapter.js.map +1 -1
- package/dist/cli.js +5 -46
- package/dist/cli.js.map +1 -1
- package/dist/errors.js +11 -25
- package/dist/errors.js.map +1 -1
- package/dist/events.js +9 -17
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +27 -40
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -127
- package/dist/index.js.map +1 -1
- package/dist/parser/streaming-parser.js +4 -8
- package/dist/parser/streaming-parser.js.map +1 -1
- package/dist/performance.js +9 -15
- package/dist/performance.js.map +1 -1
- package/dist/plugins/index.d.ts +1 -1
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +1 -17
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/plugin-system-inline.js +24 -29
- package/dist/plugins/plugin-system-inline.js.map +1 -1
- package/dist/plugins/plugin-system.js +2 -6
- package/dist/plugins/plugin-system.js.map +1 -1
- package/dist/plugins/rehype/harden.js +3 -6
- package/dist/plugins/rehype/harden.js.map +1 -1
- package/dist/plugins/rehype/index.d.ts +1 -1
- package/dist/plugins/rehype/index.d.ts.map +1 -1
- package/dist/plugins/rehype/index.js +1 -17
- package/dist/plugins/rehype/index.js.map +1 -1
- package/dist/plugins/remark/index.d.ts +2 -2
- package/dist/plugins/remark/index.d.ts.map +1 -1
- package/dist/plugins/remark/index.js +2 -18
- package/dist/plugins/remark/index.js.map +1 -1
- package/dist/plugins/remark/math.js +1 -4
- package/dist/plugins/remark/math.js.map +1 -1
- package/dist/plugins/remark/mermaid.js +1 -4
- package/dist/plugins/remark/mermaid.js.map +1 -1
- package/dist/plugins/types.js +1 -2
- package/dist/renderer/{blessed-renderer.d.ts → ansi-renderer.d.ts} +20 -36
- package/dist/renderer/ansi-renderer.d.ts.map +1 -0
- package/dist/renderer/ansi-renderer.js +391 -0
- package/dist/renderer/ansi-renderer.js.map +1 -0
- package/dist/renderers/index.d.ts +3 -3
- package/dist/renderers/index.d.ts.map +1 -1
- package/dist/renderers/index.js +3 -17
- package/dist/renderers/index.js.map +1 -1
- package/dist/renderers/math-renderer.js +4 -11
- package/dist/renderers/math-renderer.js.map +1 -1
- package/dist/renderers/mermaid-ascii.js +2 -6
- package/dist/renderers/mermaid-ascii.js.map +1 -1
- package/dist/renderers/mermaid-renderer.js +6 -11
- package/dist/renderers/mermaid-renderer.js.map +1 -1
- package/dist/renderers/shiki-ansi.js +4 -8
- package/dist/renderers/shiki-ansi.js.map +1 -1
- package/dist/renderers/table-ascii.js +4 -10
- package/dist/renderers/table-ascii.js.map +1 -1
- package/dist/renderers/unicode-math.js +5 -12
- package/dist/renderers/unicode-math.js.map +1 -1
- package/dist/security/ansi-sanitizer.js +8 -18
- package/dist/security/ansi-sanitizer.js.map +1 -1
- package/dist/security/chunk-processor.js +14 -30
- package/dist/security/chunk-processor.js.map +1 -1
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +1 -17
- package/dist/security/index.js.map +1 -1
- package/dist/security/input-validator.js +8 -13
- package/dist/security/input-validator.js.map +1 -1
- package/dist/stream-protocol.js +1 -5
- package/dist/stream-protocol.js.map +1 -1
- package/dist/streamdown-compat.d.ts +5 -8
- package/dist/streamdown-compat.d.ts.map +1 -1
- package/dist/streamdown-compat.js +13 -26
- package/dist/streamdown-compat.js.map +1 -1
- package/dist/streaming/stream-stats.js +2 -7
- package/dist/streaming/stream-stats.js.map +1 -1
- package/dist/streaming-integration.js +22 -34
- package/dist/streaming-integration.js.map +1 -1
- package/dist/themes/index.js +9 -14
- package/dist/themes/index.js.map +1 -1
- package/dist/types/index.d.ts +27 -81
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -2
- package/dist/types/plugin-types.js +1 -2
- package/dist/types/plugin-types.js.map +1 -1
- package/dist/types/stream-events.js +1 -2
- package/dist/types/stream-events.js.map +1 -1
- package/dist/utils/blessed-syntax-highlighter.js +66 -92
- package/dist/utils/blessed-syntax-highlighter.js.map +1 -1
- package/dist/utils/enhanced-table-renderer.js +8 -52
- package/dist/utils/enhanced-table-renderer.js.map +1 -1
- package/dist/utils/formatting.js +17 -33
- package/dist/utils/formatting.js.map +1 -1
- package/dist/utils/index.d.ts +4 -4
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -20
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/math-unicode-renderer.js +6 -14
- package/dist/utils/math-unicode-renderer.js.map +1 -1
- package/dist/utils/mermaid-ascii-renderer.js +3 -8
- package/dist/utils/mermaid-ascii-renderer.js.map +1 -1
- package/dist/utils/mermaid-ascii.js +17 -23
- package/dist/utils/mermaid-ascii.js.map +1 -1
- package/dist/utils/shiki-ansi-renderer.js +7 -14
- package/dist/utils/shiki-ansi-renderer.js.map +1 -1
- package/dist/utils/syntax-highlighter.js +27 -44
- package/dist/utils/syntax-highlighter.js.map +1 -1
- package/dist/utils/table-formatter-inline.js +5 -12
- package/dist/utils/table-formatter-inline.js.map +1 -1
- package/dist/utils/table.js +9 -15
- package/dist/utils/table.js.map +1 -1
- package/dist/widgets/stream-indicator.js +6 -15
- package/dist/widgets/stream-indicator.js.map +1 -1
- package/package.json +12 -14
- package/dist/renderer/blessed-renderer.d.ts.map +0 -1
- package/dist/renderer/blessed-renderer.js +0 -610
- package/dist/renderer/blessed-renderer.js.map +0 -1
- package/dist/renderers/table-renderer.d.ts +0 -49
- package/dist/renderers/table-renderer.d.ts.map +0 -1
- package/dist/renderers/table-renderer.js +0 -224
- package/dist/renderers/table-renderer.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nicomatt69/streamtty",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "A drop-in replacement for markdown rendering in TTY, designed for AI-powered streaming
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "A drop-in replacement for markdown rendering in TTY, designed for AI-powered streaming",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"types": "dist/index.d.ts",
|
|
7
8
|
"bin": {
|
|
@@ -16,24 +17,24 @@
|
|
|
16
17
|
"url": "https://github.com/nikomatt69/streamtty/issues"
|
|
17
18
|
},
|
|
18
19
|
"scripts": {
|
|
19
|
-
"build": "tsc",
|
|
20
|
+
"build": "bun build src/index.ts --outdir dist --target node && tsc",
|
|
20
21
|
"dev": "tsc --watch",
|
|
21
22
|
"clean": "rm -rf dist",
|
|
22
|
-
"prepublishOnly": "
|
|
23
|
+
"prepublishOnly": "bun run clean && bun run build",
|
|
23
24
|
"test": "echo \"Warning: no tests specified\"",
|
|
24
|
-
"example:basic": "
|
|
25
|
-
"example:streaming": "
|
|
26
|
-
"example:interactive": "
|
|
27
|
-
"example:chat": "
|
|
25
|
+
"example:basic": "bun examples/basic.ts",
|
|
26
|
+
"example:streaming": "bun examples/streaming.ts",
|
|
27
|
+
"example:interactive": "bun examples/enhanced-streaming-test.ts",
|
|
28
|
+
"example:chat": "bun examples/chat.ts"
|
|
28
29
|
},
|
|
29
30
|
"keywords": [
|
|
30
31
|
"markdown",
|
|
31
32
|
"tty",
|
|
32
33
|
"terminal",
|
|
33
|
-
"
|
|
34
|
+
"ansi",
|
|
34
35
|
"streaming",
|
|
35
36
|
"ai",
|
|
36
|
-
"
|
|
37
|
+
"cli"
|
|
37
38
|
],
|
|
38
39
|
"author": "Nicomatt69 <nicola.mattioli.95@gmail.com>",
|
|
39
40
|
"license": "MIT",
|
|
@@ -49,8 +50,6 @@
|
|
|
49
50
|
"dependencies": {
|
|
50
51
|
"ansi-regex": "^6.0.1",
|
|
51
52
|
"asciichart": "^1.5.25",
|
|
52
|
-
"blessed": "^0.1.81",
|
|
53
|
-
"blessed-contrib": "^4.11.0",
|
|
54
53
|
"chalk": "^4.1.2",
|
|
55
54
|
"cli-highlight": "^2.1.11",
|
|
56
55
|
"katex": "^0.16.9",
|
|
@@ -64,12 +63,11 @@
|
|
|
64
63
|
"tty-table": "^4.2.3"
|
|
65
64
|
},
|
|
66
65
|
"devDependencies": {
|
|
67
|
-
"@types/blessed": "^0.1.25",
|
|
68
66
|
"@types/node": "^20.19.20",
|
|
69
67
|
"tsx": "^4.20.6",
|
|
70
68
|
"typescript": "^5.9.3"
|
|
71
69
|
},
|
|
72
70
|
"engines": {
|
|
73
|
-
"
|
|
71
|
+
"bun": ">=1.0.0"
|
|
74
72
|
}
|
|
75
73
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"blessed-renderer.d.ts","sourceRoot":"","sources":["../../src/renderer/blessed-renderer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAgC,MAAM,UAAU,CAAC;AAIpF,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,aAAa,CAAiB;gBAE1B,OAAO,EAAE,aAAa;IAKlC;;OAEG;IACU,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA0CzD;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAwCxB;;OAEG;YACW,WAAW;IA+CzB;;OAEG;IACH,OAAO,CAAC,aAAa;IAmBrB;;OAEG;IACH,OAAO,CAAC,UAAU;IAqBlB;;OAEG;IACH,OAAO,CAAC,YAAY;IAiBpB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAkBhB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAiBxB;;OAEG;IACH,OAAO,CAAC,UAAU;IAiBlB;;OAEG;IACH,OAAO,CAAC,SAAS;IAkBjB;;OAEG;IACH,OAAO,CAAC,eAAe;IAiCvB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA+BxB;;OAEG;IACH,OAAO,CAAC,cAAc;IAoCtB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAc5B;;OAEG;IACH,OAAO,CAAC,WAAW;IA4DnB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA2B1B;;OAEG;IACH,OAAO,CAAC,aAAa;IAyBrB;;OAEG;IACH,OAAO,CAAC,eAAe;IAavB;;OAEG;IACH,OAAO,CAAC,cAAc;IAkDtB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAuBxB;;OAEG;YACW,aAAa;CAsC5B"}
|
|
@@ -1,610 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.BlessedRenderer = void 0;
|
|
7
|
-
const blessed_1 = __importDefault(require("blessed"));
|
|
8
|
-
const mermaid_renderer_1 = require("../renderers/mermaid-renderer");
|
|
9
|
-
const enhanced_table_renderer_1 = require("../utils/enhanced-table-renderer");
|
|
10
|
-
class BlessedRenderer {
|
|
11
|
-
context;
|
|
12
|
-
defaultStyles;
|
|
13
|
-
constructor(context) {
|
|
14
|
-
this.context = context;
|
|
15
|
-
this.defaultStyles = this.getDefaultStyles();
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Render tokens to blessed components
|
|
19
|
-
*/
|
|
20
|
-
async render(tokens) {
|
|
21
|
-
// Clear existing content
|
|
22
|
-
this.context.container.children.forEach(child => child.destroy());
|
|
23
|
-
let yOffset = 0;
|
|
24
|
-
let currentLineTokens = [];
|
|
25
|
-
for (let i = 0; i < tokens.length; i++) {
|
|
26
|
-
const token = tokens[i];
|
|
27
|
-
// If it's an inline token, add to current line
|
|
28
|
-
if (['strong', 'em', 'code', 'link', 'del', 'text'].includes(token.type)) {
|
|
29
|
-
currentLineTokens.push(token);
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
// Render current line if we have content
|
|
33
|
-
if (currentLineTokens.length > 0) {
|
|
34
|
-
this.renderInlineLine(currentLineTokens, yOffset);
|
|
35
|
-
yOffset += 1;
|
|
36
|
-
currentLineTokens = [];
|
|
37
|
-
}
|
|
38
|
-
// Render the block token
|
|
39
|
-
const element = await this.renderToken(token, yOffset);
|
|
40
|
-
if (element) {
|
|
41
|
-
yOffset += this.getTokenHeight(token);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
// Render any remaining inline content
|
|
46
|
-
if (currentLineTokens.length > 0) {
|
|
47
|
-
this.renderInlineLine(currentLineTokens, yOffset);
|
|
48
|
-
}
|
|
49
|
-
// Auto-scroll if enabled
|
|
50
|
-
if (this.context.options.autoScroll) {
|
|
51
|
-
this.context.container.setScrollPerc(100);
|
|
52
|
-
}
|
|
53
|
-
this.context.screen.render();
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Render a line of inline tokens
|
|
57
|
-
*/
|
|
58
|
-
renderInlineLine(tokens, yOffset) {
|
|
59
|
-
let content = '';
|
|
60
|
-
for (const token of tokens) {
|
|
61
|
-
switch (token.type) {
|
|
62
|
-
case 'strong':
|
|
63
|
-
content += `{bold}${token.content}{/bold}`;
|
|
64
|
-
break;
|
|
65
|
-
case 'em':
|
|
66
|
-
// Use underline instead of italic for better terminal compatibility
|
|
67
|
-
content += `{underline}${token.content}{/underline}`;
|
|
68
|
-
break;
|
|
69
|
-
case 'code':
|
|
70
|
-
content += `{cyan-fg}${token.content}{/cyan-fg}`;
|
|
71
|
-
break;
|
|
72
|
-
case 'link':
|
|
73
|
-
content += `{blue-fg}{underline}${token.content}{/underline}{/blue-fg}`;
|
|
74
|
-
break;
|
|
75
|
-
case 'del':
|
|
76
|
-
// Blessed doesn't support strikethrough, use a visual alternative
|
|
77
|
-
content += `{gray-fg}~~${token.content}~~{/gray-fg}`;
|
|
78
|
-
break;
|
|
79
|
-
default:
|
|
80
|
-
content += token.content;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
blessed_1.default.box({
|
|
84
|
-
parent: this.context.container,
|
|
85
|
-
top: yOffset,
|
|
86
|
-
left: 0,
|
|
87
|
-
width: '100%',
|
|
88
|
-
height: 'shrink',
|
|
89
|
-
content,
|
|
90
|
-
tags: true,
|
|
91
|
-
style: this.defaultStyles.paragraph,
|
|
92
|
-
wrap: true,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Render a single token
|
|
97
|
-
*/
|
|
98
|
-
async renderToken(token, yOffset) {
|
|
99
|
-
switch (token.type) {
|
|
100
|
-
case 'heading':
|
|
101
|
-
return this.renderHeading(token, yOffset);
|
|
102
|
-
case 'paragraph':
|
|
103
|
-
case 'text':
|
|
104
|
-
return this.renderText(token, yOffset);
|
|
105
|
-
case 'strong':
|
|
106
|
-
return this.renderStrong(token, yOffset);
|
|
107
|
-
case 'em':
|
|
108
|
-
return this.renderEm(token, yOffset);
|
|
109
|
-
case 'code':
|
|
110
|
-
return this.renderInlineCode(token, yOffset);
|
|
111
|
-
case 'link':
|
|
112
|
-
return this.renderLink(token, yOffset);
|
|
113
|
-
case 'del':
|
|
114
|
-
return this.renderDel(token, yOffset);
|
|
115
|
-
case 'codeblock':
|
|
116
|
-
return this.renderCodeBlock(token, yOffset);
|
|
117
|
-
case 'blockquote':
|
|
118
|
-
return this.renderBlockquote(token, yOffset);
|
|
119
|
-
case 'listitem':
|
|
120
|
-
return this.renderListItem(token, yOffset);
|
|
121
|
-
case 'hr':
|
|
122
|
-
return this.renderHorizontalRule(token, yOffset);
|
|
123
|
-
case 'table':
|
|
124
|
-
return this.renderTable(token, yOffset);
|
|
125
|
-
case 'mermaid':
|
|
126
|
-
return await this.renderMermaid(token, yOffset);
|
|
127
|
-
default:
|
|
128
|
-
return this.renderText(token, yOffset);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Render heading
|
|
133
|
-
*/
|
|
134
|
-
renderHeading(token, yOffset) {
|
|
135
|
-
const depth = token.depth || 1;
|
|
136
|
-
const style = this.getHeadingStyle(depth);
|
|
137
|
-
const prefix = token.incomplete ? '# ' : '';
|
|
138
|
-
const content = prefix + token.content;
|
|
139
|
-
return blessed_1.default.box({
|
|
140
|
-
parent: this.context.container,
|
|
141
|
-
top: yOffset,
|
|
142
|
-
left: 0,
|
|
143
|
-
width: '100%',
|
|
144
|
-
height: 'shrink',
|
|
145
|
-
content,
|
|
146
|
-
tags: true,
|
|
147
|
-
style: style,
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Render text/paragraph
|
|
152
|
-
*/
|
|
153
|
-
renderText(token, yOffset) {
|
|
154
|
-
const style = this.defaultStyles.paragraph;
|
|
155
|
-
let content = this.formatInlineStyles(token.content);
|
|
156
|
-
if (token.incomplete) {
|
|
157
|
-
content += '{yellow-fg}...{/yellow-fg}';
|
|
158
|
-
}
|
|
159
|
-
return blessed_1.default.box({
|
|
160
|
-
parent: this.context.container,
|
|
161
|
-
top: yOffset,
|
|
162
|
-
left: 0,
|
|
163
|
-
width: '100%',
|
|
164
|
-
height: 'shrink',
|
|
165
|
-
content,
|
|
166
|
-
tags: true,
|
|
167
|
-
style: style,
|
|
168
|
-
wrap: true,
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Render strong/bold text
|
|
173
|
-
*/
|
|
174
|
-
renderStrong(token, yOffset) {
|
|
175
|
-
const style = this.defaultStyles.strong;
|
|
176
|
-
const content = `{bold}${token.content}{/bold}`;
|
|
177
|
-
return blessed_1.default.box({
|
|
178
|
-
parent: this.context.container,
|
|
179
|
-
top: yOffset,
|
|
180
|
-
left: 0,
|
|
181
|
-
width: '100%',
|
|
182
|
-
height: 'shrink',
|
|
183
|
-
content,
|
|
184
|
-
tags: true,
|
|
185
|
-
style: style,
|
|
186
|
-
wrap: true,
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Render emphasis/italic text
|
|
191
|
-
*/
|
|
192
|
-
renderEm(token, yOffset) {
|
|
193
|
-
const style = this.defaultStyles.em;
|
|
194
|
-
// Use underline instead of italic for better terminal compatibility
|
|
195
|
-
const content = `{underline}${token.content}{/underline}`;
|
|
196
|
-
return blessed_1.default.box({
|
|
197
|
-
parent: this.context.container,
|
|
198
|
-
top: yOffset,
|
|
199
|
-
left: 0,
|
|
200
|
-
width: '100%',
|
|
201
|
-
height: 'shrink',
|
|
202
|
-
content,
|
|
203
|
-
tags: true,
|
|
204
|
-
style: style,
|
|
205
|
-
wrap: true,
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Render inline code
|
|
210
|
-
*/
|
|
211
|
-
renderInlineCode(token, yOffset) {
|
|
212
|
-
const style = this.defaultStyles.code;
|
|
213
|
-
const content = `{cyan-fg}{bold}${token.content}{/bold}{/cyan-fg}`;
|
|
214
|
-
return blessed_1.default.box({
|
|
215
|
-
parent: this.context.container,
|
|
216
|
-
top: yOffset,
|
|
217
|
-
left: 0,
|
|
218
|
-
width: '100%',
|
|
219
|
-
height: 'shrink',
|
|
220
|
-
content,
|
|
221
|
-
tags: true,
|
|
222
|
-
style: style,
|
|
223
|
-
wrap: true,
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Render link
|
|
228
|
-
*/
|
|
229
|
-
renderLink(token, yOffset) {
|
|
230
|
-
const style = this.defaultStyles.link;
|
|
231
|
-
const content = `{blue-fg}{underline}${token.content}{/underline}{/blue-fg}`;
|
|
232
|
-
return blessed_1.default.box({
|
|
233
|
-
parent: this.context.container,
|
|
234
|
-
top: yOffset,
|
|
235
|
-
left: 0,
|
|
236
|
-
width: '100%',
|
|
237
|
-
height: 'shrink',
|
|
238
|
-
content,
|
|
239
|
-
tags: true,
|
|
240
|
-
style: style,
|
|
241
|
-
wrap: true,
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Render strikethrough text
|
|
246
|
-
*/
|
|
247
|
-
renderDel(token, yOffset) {
|
|
248
|
-
const style = this.defaultStyles.paragraph;
|
|
249
|
-
// Blessed doesn't support strikethrough, use visual alternative
|
|
250
|
-
const content = `{gray-fg}~~${token.content}~~{/gray-fg}`;
|
|
251
|
-
return blessed_1.default.box({
|
|
252
|
-
parent: this.context.container,
|
|
253
|
-
top: yOffset,
|
|
254
|
-
left: 0,
|
|
255
|
-
width: '100%',
|
|
256
|
-
height: 'shrink',
|
|
257
|
-
content,
|
|
258
|
-
tags: true,
|
|
259
|
-
style: style,
|
|
260
|
-
wrap: true,
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Render code block
|
|
265
|
-
*/
|
|
266
|
-
renderCodeBlock(token, yOffset) {
|
|
267
|
-
const style = this.defaultStyles.codeBlock;
|
|
268
|
-
const lang = token.lang || 'text';
|
|
269
|
-
let content = token.content;
|
|
270
|
-
if (token.incomplete) {
|
|
271
|
-
content = `{yellow-fg}[Code block (${lang})...]{/yellow-fg}`;
|
|
272
|
-
}
|
|
273
|
-
return blessed_1.default.box({
|
|
274
|
-
parent: this.context.container,
|
|
275
|
-
top: yOffset,
|
|
276
|
-
left: 2,
|
|
277
|
-
width: '100%-4',
|
|
278
|
-
height: 'shrink',
|
|
279
|
-
content: this.highlightCode(content, lang),
|
|
280
|
-
tags: true,
|
|
281
|
-
border: {
|
|
282
|
-
type: 'line',
|
|
283
|
-
},
|
|
284
|
-
style: {
|
|
285
|
-
border: {
|
|
286
|
-
fg: style.fg || 'blue',
|
|
287
|
-
},
|
|
288
|
-
...style,
|
|
289
|
-
},
|
|
290
|
-
padding: {
|
|
291
|
-
left: 1,
|
|
292
|
-
right: 1,
|
|
293
|
-
},
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Render blockquote
|
|
298
|
-
*/
|
|
299
|
-
renderBlockquote(token, yOffset) {
|
|
300
|
-
const style = this.defaultStyles.blockquote;
|
|
301
|
-
return blessed_1.default.box({
|
|
302
|
-
parent: this.context.container,
|
|
303
|
-
top: yOffset,
|
|
304
|
-
left: 2,
|
|
305
|
-
width: '100%-4',
|
|
306
|
-
height: 'shrink',
|
|
307
|
-
content: this.formatInlineStyles(token.content),
|
|
308
|
-
tags: true,
|
|
309
|
-
border: {
|
|
310
|
-
type: 'line',
|
|
311
|
-
},
|
|
312
|
-
style: {
|
|
313
|
-
border: {
|
|
314
|
-
fg: style.fg || 'gray',
|
|
315
|
-
left: false,
|
|
316
|
-
right: false,
|
|
317
|
-
top: false,
|
|
318
|
-
bottom: false,
|
|
319
|
-
},
|
|
320
|
-
...style,
|
|
321
|
-
},
|
|
322
|
-
padding: {
|
|
323
|
-
left: 1,
|
|
324
|
-
},
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* Render list item
|
|
329
|
-
*/
|
|
330
|
-
renderListItem(token, yOffset) {
|
|
331
|
-
const style = this.defaultStyles.listItem;
|
|
332
|
-
// Detect task list items
|
|
333
|
-
let bullet = token.ordered ? '1.' : '•';
|
|
334
|
-
let content = token.content;
|
|
335
|
-
// Handle task list formatting: - [ ] or - [x]
|
|
336
|
-
const taskMatch = content.match(/^(\[ \]|\[x\]|\[X\])\s*(.*)/);
|
|
337
|
-
if (taskMatch) {
|
|
338
|
-
const isCompleted = taskMatch[1] !== '[ ]';
|
|
339
|
-
bullet = isCompleted ? '✅' : '☐';
|
|
340
|
-
content = taskMatch[2];
|
|
341
|
-
}
|
|
342
|
-
const formattedContent = `${bullet} ${this.formatInlineStyles(content)}`;
|
|
343
|
-
// Calculate proper height for wrapping
|
|
344
|
-
const maxWidth = this.context.options.maxWidth || 120;
|
|
345
|
-
const lineWidth = maxWidth - 6; // Account for indentation and padding
|
|
346
|
-
const estimatedLines = Math.ceil(formattedContent.length / lineWidth);
|
|
347
|
-
const height = Math.max(estimatedLines, 1);
|
|
348
|
-
return blessed_1.default.box({
|
|
349
|
-
parent: this.context.container,
|
|
350
|
-
top: yOffset,
|
|
351
|
-
left: 2,
|
|
352
|
-
width: '100%-4',
|
|
353
|
-
height,
|
|
354
|
-
content: formattedContent,
|
|
355
|
-
tags: true,
|
|
356
|
-
style: style,
|
|
357
|
-
wrap: true,
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* Render horizontal rule
|
|
362
|
-
*/
|
|
363
|
-
renderHorizontalRule(token, yOffset) {
|
|
364
|
-
return blessed_1.default.box({
|
|
365
|
-
parent: this.context.container,
|
|
366
|
-
top: yOffset,
|
|
367
|
-
left: 0,
|
|
368
|
-
width: '100%',
|
|
369
|
-
height: 1,
|
|
370
|
-
content: '─'.repeat(80),
|
|
371
|
-
style: {
|
|
372
|
-
fg: 'gray',
|
|
373
|
-
},
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
/**
|
|
377
|
-
* Render table using enhanced table renderer
|
|
378
|
-
*/
|
|
379
|
-
renderTable(token, yOffset) {
|
|
380
|
-
let content;
|
|
381
|
-
try {
|
|
382
|
-
// Try to parse as markdown table first
|
|
383
|
-
const tableData = (0, enhanced_table_renderer_1.parseMarkdownTable)(token.content);
|
|
384
|
-
if (tableData && tableData.headers.length > 0) {
|
|
385
|
-
content = enhanced_table_renderer_1.EnhancedTableRenderer.renderTable(tableData, {
|
|
386
|
-
borderStyle: 'solid',
|
|
387
|
-
compact: false,
|
|
388
|
-
width: this.context.options.maxWidth || 80
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
else if (enhanced_table_renderer_1.EnhancedTableRenderer.isChartData(token.content)) {
|
|
392
|
-
// If it looks like chart data, render as chart
|
|
393
|
-
const chartData = (0, enhanced_table_renderer_1.parseCSVToChart)(token.content);
|
|
394
|
-
if (chartData) {
|
|
395
|
-
content = enhanced_table_renderer_1.EnhancedTableRenderer.renderChart(chartData);
|
|
396
|
-
}
|
|
397
|
-
else {
|
|
398
|
-
content = '[Chart Data]\n' + token.content;
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
else {
|
|
402
|
-
// Fallback: render the raw content
|
|
403
|
-
content = token.content;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
catch (error) {
|
|
407
|
-
// Log errors only in debug mode
|
|
408
|
-
if (process.env.DEBUG) {
|
|
409
|
-
console.warn('Table render error:', error);
|
|
410
|
-
}
|
|
411
|
-
content = '[Table Render Error]\n' + token.content;
|
|
412
|
-
}
|
|
413
|
-
return blessed_1.default.box({
|
|
414
|
-
parent: this.context.container,
|
|
415
|
-
top: yOffset,
|
|
416
|
-
left: 0,
|
|
417
|
-
width: '100%',
|
|
418
|
-
height: 'shrink',
|
|
419
|
-
content,
|
|
420
|
-
tags: false, // Disable tags for table content to preserve formatting
|
|
421
|
-
border: {
|
|
422
|
-
type: 'line'
|
|
423
|
-
},
|
|
424
|
-
style: {
|
|
425
|
-
fg: 'cyan',
|
|
426
|
-
bg: 'black',
|
|
427
|
-
border: {
|
|
428
|
-
fg: 'cyan'
|
|
429
|
-
}
|
|
430
|
-
},
|
|
431
|
-
padding: {
|
|
432
|
-
top: 1,
|
|
433
|
-
bottom: 1,
|
|
434
|
-
left: 2,
|
|
435
|
-
right: 2
|
|
436
|
-
}
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
/**
|
|
440
|
-
* Format inline styles (bold, italic, code, links)
|
|
441
|
-
* This is now used only for text that hasn't been parsed as inline tokens
|
|
442
|
-
*/
|
|
443
|
-
formatInlineStyles(text) {
|
|
444
|
-
let formatted = text;
|
|
445
|
-
// Only apply formatting if the text contains markdown syntax that wasn't parsed
|
|
446
|
-
// This is a fallback for cases where marked.js didn't parse inline elements
|
|
447
|
-
if (/\*\*.*\*\*|__.*__|\*.*\*|_.*_|`.*`|\[.*\]\(.*\)|~~.*~~/.test(text)) {
|
|
448
|
-
// Bold: **text** or __text__
|
|
449
|
-
formatted = formatted.replace(/\*\*(.+?)\*\*/g, '{bold}$1{/bold}');
|
|
450
|
-
formatted = formatted.replace(/__(.+?)__/g, '{bold}$1{/bold}');
|
|
451
|
-
// Italic: *text* or _text_ - use underline for better compatibility
|
|
452
|
-
formatted = formatted.replace(/\*(.+?)\*/g, '{underline}$1{/underline}');
|
|
453
|
-
formatted = formatted.replace(/_(.+?)_/g, '{underline}$1{/underline}');
|
|
454
|
-
// Inline code: `code`
|
|
455
|
-
formatted = formatted.replace(/`(.+?)`/g, '{cyan-fg}{bold}$1{/bold}{/cyan-fg}');
|
|
456
|
-
// Links: [text](url)
|
|
457
|
-
formatted = formatted.replace(/\[(.+?)\]\((.+?)\)/g, '{blue-fg}{underline}$1{/underline}{/blue-fg}');
|
|
458
|
-
// Strikethrough: ~~text~~ (blessed doesn't support strike, use gray)
|
|
459
|
-
formatted = formatted.replace(/~~(.+?)~~/g, '{gray-fg}~~$1~~{/gray-fg}');
|
|
460
|
-
}
|
|
461
|
-
return formatted;
|
|
462
|
-
}
|
|
463
|
-
/**
|
|
464
|
-
* Highlight code (basic implementation)
|
|
465
|
-
*/
|
|
466
|
-
highlightCode(code, lang) {
|
|
467
|
-
// Basic syntax highlighting - in production you'd use a proper highlighter
|
|
468
|
-
if (!this.context.options.syntaxHighlight) {
|
|
469
|
-
return code;
|
|
470
|
-
}
|
|
471
|
-
// Simple keyword highlighting
|
|
472
|
-
const keywords = ['function', 'const', 'let', 'var', 'if', 'else', 'return', 'for', 'while', 'class', 'import', 'export'];
|
|
473
|
-
let highlighted = code;
|
|
474
|
-
for (const keyword of keywords) {
|
|
475
|
-
const regex = new RegExp(`\\b(${keyword})\\b`, 'g');
|
|
476
|
-
highlighted = highlighted.replace(regex, '{magenta-fg}$1{/magenta-fg}');
|
|
477
|
-
}
|
|
478
|
-
// Strings
|
|
479
|
-
highlighted = highlighted.replace(/(["'])(?:(?=(\\?))\2.)*?\1/g, '{green-fg}$&{/green-fg}');
|
|
480
|
-
// Comments
|
|
481
|
-
highlighted = highlighted.replace(/(\/\/.*)$/gm, '{gray-fg}$1{/gray-fg}');
|
|
482
|
-
highlighted = highlighted.replace(/(\/\*[\s\S]*?\*\/)/g, '{gray-fg}$1{/gray-fg}');
|
|
483
|
-
return highlighted;
|
|
484
|
-
}
|
|
485
|
-
/**
|
|
486
|
-
* Get heading style based on depth
|
|
487
|
-
*/
|
|
488
|
-
getHeadingStyle(depth) {
|
|
489
|
-
const styles = [
|
|
490
|
-
this.defaultStyles.h1,
|
|
491
|
-
this.defaultStyles.h2,
|
|
492
|
-
this.defaultStyles.h3,
|
|
493
|
-
this.defaultStyles.h4,
|
|
494
|
-
this.defaultStyles.h5,
|
|
495
|
-
this.defaultStyles.h6,
|
|
496
|
-
];
|
|
497
|
-
return styles[depth - 1] || styles[0];
|
|
498
|
-
}
|
|
499
|
-
/**
|
|
500
|
-
* Get token height for layout calculation
|
|
501
|
-
*/
|
|
502
|
-
getTokenHeight(token) {
|
|
503
|
-
const maxWidth = this.context.options.maxWidth || 120;
|
|
504
|
-
switch (token.type) {
|
|
505
|
-
case 'heading':
|
|
506
|
-
return 2; // Heading + spacing
|
|
507
|
-
case 'codeblock':
|
|
508
|
-
const codeLines = token.content.split('\n').length;
|
|
509
|
-
return codeLines + 4; // Content + border + padding
|
|
510
|
-
case 'hr':
|
|
511
|
-
return 2; // Line + spacing
|
|
512
|
-
case 'table':
|
|
513
|
-
// Better table height calculation
|
|
514
|
-
const lines = token.content.split('\n').filter(line => line.trim());
|
|
515
|
-
return Math.max(lines.length + 4, 6); // Table rows + borders + padding
|
|
516
|
-
case 'mermaid':
|
|
517
|
-
// Estimate mermaid diagram height
|
|
518
|
-
const diagramLines = token.content.split('\n').length;
|
|
519
|
-
return Math.max(diagramLines + 6, 10); // Diagram + border + padding
|
|
520
|
-
case 'blockquote':
|
|
521
|
-
const quoteLines = Math.ceil(token.content.length / (maxWidth - 6));
|
|
522
|
-
return quoteLines + 2; // Content + border
|
|
523
|
-
case 'listitem':
|
|
524
|
-
const itemLines = Math.ceil(token.content.length / (maxWidth - 4));
|
|
525
|
-
return Math.max(itemLines, 1);
|
|
526
|
-
case 'strong':
|
|
527
|
-
case 'em':
|
|
528
|
-
case 'code':
|
|
529
|
-
case 'link':
|
|
530
|
-
case 'del':
|
|
531
|
-
// Inline tokens should be rendered on the same line
|
|
532
|
-
return 0;
|
|
533
|
-
case 'paragraph':
|
|
534
|
-
case 'text':
|
|
535
|
-
default:
|
|
536
|
-
// Better text wrapping calculation
|
|
537
|
-
if (!token.content)
|
|
538
|
-
return 1;
|
|
539
|
-
const textLines = Math.ceil(token.content.length / maxWidth);
|
|
540
|
-
return Math.max(textLines, 1);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
/**
|
|
544
|
-
* Get default styles
|
|
545
|
-
*/
|
|
546
|
-
getDefaultStyles() {
|
|
547
|
-
return {
|
|
548
|
-
h1: { fg: 'cyan', bold: true },
|
|
549
|
-
h2: { fg: 'blue', bold: true },
|
|
550
|
-
h3: { fg: 'green', bold: true },
|
|
551
|
-
h4: { fg: 'yellow', bold: true },
|
|
552
|
-
h5: { fg: 'magenta', bold: true },
|
|
553
|
-
h6: { fg: 'white', bold: true },
|
|
554
|
-
paragraph: { fg: 'white' },
|
|
555
|
-
strong: { bold: true },
|
|
556
|
-
em: { underline: true }, // Use underline for better terminal compatibility
|
|
557
|
-
code: { fg: 'cyan', bold: true },
|
|
558
|
-
codeBlock: { fg: 'white', bg: 'black' },
|
|
559
|
-
blockquote: { fg: 'gray' },
|
|
560
|
-
link: { fg: 'blue', underline: true },
|
|
561
|
-
list: { fg: 'white' },
|
|
562
|
-
listItem: { fg: 'white' },
|
|
563
|
-
table: { fg: 'cyan' },
|
|
564
|
-
tableHeader: { fg: 'cyan', bold: true },
|
|
565
|
-
hr: { fg: 'gray' },
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
/**
|
|
569
|
-
* Render mermaid diagram
|
|
570
|
-
*/
|
|
571
|
-
async renderMermaid(token, yOffset) {
|
|
572
|
-
let content;
|
|
573
|
-
try {
|
|
574
|
-
// Use mermaid-ascii to convert to ASCII art
|
|
575
|
-
const asciiDiagram = await (0, mermaid_renderer_1.renderMermaidDiagram)(token.content);
|
|
576
|
-
content = asciiDiagram;
|
|
577
|
-
}
|
|
578
|
-
catch (error) {
|
|
579
|
-
// Fallback if mermaid rendering fails
|
|
580
|
-
content = `[Mermaid Diagram]\n${token.content}`;
|
|
581
|
-
}
|
|
582
|
-
return blessed_1.default.box({
|
|
583
|
-
parent: this.context.container,
|
|
584
|
-
top: yOffset,
|
|
585
|
-
left: 0,
|
|
586
|
-
width: '100%',
|
|
587
|
-
height: 'shrink',
|
|
588
|
-
content,
|
|
589
|
-
tags: false, // Disable tags for ASCII art to preserve formatting
|
|
590
|
-
border: {
|
|
591
|
-
type: 'line'
|
|
592
|
-
},
|
|
593
|
-
style: {
|
|
594
|
-
fg: 'cyan',
|
|
595
|
-
bg: 'black',
|
|
596
|
-
border: {
|
|
597
|
-
fg: 'blue'
|
|
598
|
-
}
|
|
599
|
-
},
|
|
600
|
-
padding: {
|
|
601
|
-
top: 1,
|
|
602
|
-
bottom: 1,
|
|
603
|
-
left: 2,
|
|
604
|
-
right: 2
|
|
605
|
-
}
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
exports.BlessedRenderer = BlessedRenderer;
|
|
610
|
-
//# sourceMappingURL=blessed-renderer.js.map
|