@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.
Files changed (124) hide show
  1. package/dist/ai-sdk-adapter.d.ts +1 -1
  2. package/dist/ai-sdk-adapter.d.ts.map +1 -1
  3. package/dist/ai-sdk-adapter.js +5 -9
  4. package/dist/ai-sdk-adapter.js.map +1 -1
  5. package/dist/cli.js +5 -46
  6. package/dist/cli.js.map +1 -1
  7. package/dist/errors.js +11 -25
  8. package/dist/errors.js.map +1 -1
  9. package/dist/events.js +9 -17
  10. package/dist/events.js.map +1 -1
  11. package/dist/index.d.ts +27 -40
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +43 -127
  14. package/dist/index.js.map +1 -1
  15. package/dist/parser/streaming-parser.js +4 -8
  16. package/dist/parser/streaming-parser.js.map +1 -1
  17. package/dist/performance.js +9 -15
  18. package/dist/performance.js.map +1 -1
  19. package/dist/plugins/index.d.ts +1 -1
  20. package/dist/plugins/index.d.ts.map +1 -1
  21. package/dist/plugins/index.js +1 -17
  22. package/dist/plugins/index.js.map +1 -1
  23. package/dist/plugins/plugin-system-inline.js +24 -29
  24. package/dist/plugins/plugin-system-inline.js.map +1 -1
  25. package/dist/plugins/plugin-system.js +2 -6
  26. package/dist/plugins/plugin-system.js.map +1 -1
  27. package/dist/plugins/rehype/harden.js +3 -6
  28. package/dist/plugins/rehype/harden.js.map +1 -1
  29. package/dist/plugins/rehype/index.d.ts +1 -1
  30. package/dist/plugins/rehype/index.d.ts.map +1 -1
  31. package/dist/plugins/rehype/index.js +1 -17
  32. package/dist/plugins/rehype/index.js.map +1 -1
  33. package/dist/plugins/remark/index.d.ts +2 -2
  34. package/dist/plugins/remark/index.d.ts.map +1 -1
  35. package/dist/plugins/remark/index.js +2 -18
  36. package/dist/plugins/remark/index.js.map +1 -1
  37. package/dist/plugins/remark/math.js +1 -4
  38. package/dist/plugins/remark/math.js.map +1 -1
  39. package/dist/plugins/remark/mermaid.js +1 -4
  40. package/dist/plugins/remark/mermaid.js.map +1 -1
  41. package/dist/plugins/types.js +1 -2
  42. package/dist/renderer/{blessed-renderer.d.ts → ansi-renderer.d.ts} +20 -36
  43. package/dist/renderer/ansi-renderer.d.ts.map +1 -0
  44. package/dist/renderer/ansi-renderer.js +391 -0
  45. package/dist/renderer/ansi-renderer.js.map +1 -0
  46. package/dist/renderers/index.d.ts +3 -3
  47. package/dist/renderers/index.d.ts.map +1 -1
  48. package/dist/renderers/index.js +3 -17
  49. package/dist/renderers/index.js.map +1 -1
  50. package/dist/renderers/math-renderer.js +4 -11
  51. package/dist/renderers/math-renderer.js.map +1 -1
  52. package/dist/renderers/mermaid-ascii.js +2 -6
  53. package/dist/renderers/mermaid-ascii.js.map +1 -1
  54. package/dist/renderers/mermaid-renderer.js +6 -11
  55. package/dist/renderers/mermaid-renderer.js.map +1 -1
  56. package/dist/renderers/shiki-ansi.js +4 -8
  57. package/dist/renderers/shiki-ansi.js.map +1 -1
  58. package/dist/renderers/table-ascii.js +4 -10
  59. package/dist/renderers/table-ascii.js.map +1 -1
  60. package/dist/renderers/unicode-math.js +5 -12
  61. package/dist/renderers/unicode-math.js.map +1 -1
  62. package/dist/security/ansi-sanitizer.js +8 -18
  63. package/dist/security/ansi-sanitizer.js.map +1 -1
  64. package/dist/security/chunk-processor.js +14 -30
  65. package/dist/security/chunk-processor.js.map +1 -1
  66. package/dist/security/index.d.ts +1 -1
  67. package/dist/security/index.d.ts.map +1 -1
  68. package/dist/security/index.js +1 -17
  69. package/dist/security/index.js.map +1 -1
  70. package/dist/security/input-validator.js +8 -13
  71. package/dist/security/input-validator.js.map +1 -1
  72. package/dist/stream-protocol.js +1 -5
  73. package/dist/stream-protocol.js.map +1 -1
  74. package/dist/streamdown-compat.d.ts +5 -8
  75. package/dist/streamdown-compat.d.ts.map +1 -1
  76. package/dist/streamdown-compat.js +13 -26
  77. package/dist/streamdown-compat.js.map +1 -1
  78. package/dist/streaming/stream-stats.js +2 -7
  79. package/dist/streaming/stream-stats.js.map +1 -1
  80. package/dist/streaming-integration.js +22 -34
  81. package/dist/streaming-integration.js.map +1 -1
  82. package/dist/themes/index.js +9 -14
  83. package/dist/themes/index.js.map +1 -1
  84. package/dist/types/index.d.ts +27 -81
  85. package/dist/types/index.d.ts.map +1 -1
  86. package/dist/types/index.js +1 -2
  87. package/dist/types/plugin-types.js +1 -2
  88. package/dist/types/plugin-types.js.map +1 -1
  89. package/dist/types/stream-events.js +1 -2
  90. package/dist/types/stream-events.js.map +1 -1
  91. package/dist/utils/blessed-syntax-highlighter.js +66 -92
  92. package/dist/utils/blessed-syntax-highlighter.js.map +1 -1
  93. package/dist/utils/enhanced-table-renderer.js +8 -52
  94. package/dist/utils/enhanced-table-renderer.js.map +1 -1
  95. package/dist/utils/formatting.js +17 -33
  96. package/dist/utils/formatting.js.map +1 -1
  97. package/dist/utils/index.d.ts +4 -4
  98. package/dist/utils/index.d.ts.map +1 -1
  99. package/dist/utils/index.js +4 -20
  100. package/dist/utils/index.js.map +1 -1
  101. package/dist/utils/math-unicode-renderer.js +6 -14
  102. package/dist/utils/math-unicode-renderer.js.map +1 -1
  103. package/dist/utils/mermaid-ascii-renderer.js +3 -8
  104. package/dist/utils/mermaid-ascii-renderer.js.map +1 -1
  105. package/dist/utils/mermaid-ascii.js +17 -23
  106. package/dist/utils/mermaid-ascii.js.map +1 -1
  107. package/dist/utils/shiki-ansi-renderer.js +7 -14
  108. package/dist/utils/shiki-ansi-renderer.js.map +1 -1
  109. package/dist/utils/syntax-highlighter.js +27 -44
  110. package/dist/utils/syntax-highlighter.js.map +1 -1
  111. package/dist/utils/table-formatter-inline.js +5 -12
  112. package/dist/utils/table-formatter-inline.js.map +1 -1
  113. package/dist/utils/table.js +9 -15
  114. package/dist/utils/table.js.map +1 -1
  115. package/dist/widgets/stream-indicator.js +6 -15
  116. package/dist/widgets/stream-indicator.js.map +1 -1
  117. package/package.json +12 -14
  118. package/dist/renderer/blessed-renderer.d.ts.map +0 -1
  119. package/dist/renderer/blessed-renderer.js +0 -610
  120. package/dist/renderer/blessed-renderer.js.map +0 -1
  121. package/dist/renderers/table-renderer.d.ts +0 -49
  122. package/dist/renderers/table-renderer.d.ts.map +0 -1
  123. package/dist/renderers/table-renderer.js +0 -224
  124. 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.1",
4
- "description": "A drop-in replacement for markdown rendering in TTY, designed for AI-powered streaming with blessed",
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": "npm run clean && npm run build",
23
+ "prepublishOnly": "bun run clean && bun run build",
23
24
  "test": "echo \"Warning: no tests specified\"",
24
- "example:basic": "npx tsx examples/basic.ts",
25
- "example:streaming": "npx tsx examples/streaming.ts",
26
- "example:interactive": "npx tsx examples/enhanced-streaming-test.ts",
27
- "example:chat": "npx tsx examples/chat.ts"
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
- "blessed",
34
+ "ansi",
34
35
  "streaming",
35
36
  "ai",
36
- "tui"
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
- "node": ">=18.0.0"
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