@retrovm/terminal 0.2.0 → 0.3.0
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 +117 -1
- package/dist/node.js +52 -2
- package/dist/terminal.d.ts +43 -0
- package/dist/terminal.js +50 -0
- package/package.json +27 -27
- package/src/bun.ts +32 -32
- package/src/node.ts +2 -2
- package/src/terminal.ts +535 -447
package/README.md
CHANGED
|
@@ -11,6 +11,9 @@ Depends on [`@retrovm/color`](https://www.npmjs.com/package/@retrovm/color) (bun
|
|
|
11
11
|
- **Named color shortcuts** — `term.red(...)`, `term.bgBlue(...)` etc., generated automatically from the `Color` registry
|
|
12
12
|
- **Full cursor control** — move, save/restore, show/hide
|
|
13
13
|
- **Screen management** — clear, alternate buffer, scroll region, auto-wrap
|
|
14
|
+
- **Buffered output** — coalesce thousands of small writes into a single `write()` call with `buffer()` / `flush()`
|
|
15
|
+
- **Synchronized output** — wrap redraws in `sync()` for tear-free animation via DEC mode 2026
|
|
16
|
+
- **Pixel framebuffer** — render a `Uint32Array` pixel buffer directly to the terminal using the half-block trick (`framebuffer()`)
|
|
14
17
|
- **Sink-agnostic** — works with Bun's stdout/stderr writers, Node.js `Writable`s, xterm.js terminals, or any test double
|
|
15
18
|
- **`NO_COLOR` support** — respects the [no-color.org](https://no-color.org/) convention out of the box
|
|
16
19
|
- **TypeScript-first** — strict types with full autocompletion for all color methods
|
|
@@ -104,8 +107,15 @@ term.ink(new Color('#3399ff'), 'Color instance')
|
|
|
104
107
|
term.ink('#aaaaaa') // set color only, write nothing
|
|
105
108
|
```
|
|
106
109
|
|
|
110
|
+
#### `resetText(fmt?, ...args)`
|
|
111
|
+
Resets all text attributes (color, background, bold, dim, italic, underline, …) without touching the cursor or alternate screen.
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
term.red('colored').resetText(' — plain again')
|
|
115
|
+
```
|
|
116
|
+
|
|
107
117
|
#### `reset(fmt?, ...args)`
|
|
108
|
-
|
|
118
|
+
Full teardown: shows the cursor, exits the alternate screen buffer, and resets all text attributes. Use this as the last call in a TUI lifecycle.
|
|
109
119
|
|
|
110
120
|
```typescript
|
|
111
121
|
term.red('warning').reset(' — back to normal')
|
|
@@ -225,6 +235,98 @@ term.scrollRegion(1, process.stdout.rows) // reset to full screen
|
|
|
225
235
|
|
|
226
236
|
---
|
|
227
237
|
|
|
238
|
+
### Buffered output
|
|
239
|
+
|
|
240
|
+
#### `buffer()`
|
|
241
|
+
Enters buffered mode. All subsequent emissions accumulate in memory instead of being written immediately. Calling `buffer()` while already buffered is a no-op.
|
|
242
|
+
|
|
243
|
+
#### `flush()`
|
|
244
|
+
Commits the buffer in a single `write()` call and exits buffered mode. Calling `flush()` when not buffered is a no-op.
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
term.buffer()
|
|
248
|
+
for (let i = 0; i < 1000; i++) term.moveTo(i % 24 + 1, 1).print('row %d', i)
|
|
249
|
+
term.flush() // one syscall instead of thousands
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
#### `raw(data)`
|
|
253
|
+
Writes a pre-built string directly, bypassing `util.format`. Useful in hot loops where the caller has already constructed the exact bytes to emit.
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
const seq = '\x1b[38;2;255;128;0m' // precomputed orange
|
|
257
|
+
term.raw(seq).raw('hot loop text').resetText()
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
### Synchronized output
|
|
263
|
+
|
|
264
|
+
#### `sync(fn)`
|
|
265
|
+
Runs `fn` inside a synchronized-output block (DEC private mode 2026). The terminal accumulates all changes and presents them atomically when the block ends, eliminating tearing in TUIs and animations. Terminals that don't support mode 2026 ignore the escape silently.
|
|
266
|
+
|
|
267
|
+
Automatically enables buffered mode for the duration of the block. Re-entrant: nested `sync()` calls share the outermost block.
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
out.sync(() => {
|
|
271
|
+
for (let row = 0; row < H; row++) {
|
|
272
|
+
for (let col = 0; col < W; col++) {
|
|
273
|
+
out.moveTo(row + 1, col + 1).paper(bg).ink(fg).raw('▄')
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
})
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
### Pixel graphics
|
|
282
|
+
|
|
283
|
+
#### `framebuffer(fb, w, h)`
|
|
284
|
+
Renders a raw pixel buffer to the terminal using the half-block trick. Each pair of vertically adjacent pixels is encoded as a single `▄` character: the upper pixel becomes the background color and the lower pixel the foreground color, doubling the effective vertical resolution.
|
|
285
|
+
|
|
286
|
+
- **`fb`** — `Uint32Array` of packed pixels. Format: little-endian RGBA (`0xAABBGGRR`), alpha ignored. Matches `Canvas.getImageData` output on little-endian systems.
|
|
287
|
+
- **`w`** — Width in pixels (terminal columns).
|
|
288
|
+
- **`h`** — Height in pixels. Must be even.
|
|
289
|
+
|
|
290
|
+
The entire frame is assembled into one string before writing; the write is wrapped in `sync()`.
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
const W = out.width ?? 80
|
|
294
|
+
const H = (out.height ?? 24) * 2 // 2 pixel rows per character row
|
|
295
|
+
const fb = new Uint32Array(W * H)
|
|
296
|
+
|
|
297
|
+
// fill fb with 0xAABBGGRR pixels...
|
|
298
|
+
fb[0] = 0xFF0000FF // red pixel at (0, 0)
|
|
299
|
+
|
|
300
|
+
out.framebuffer(fb, W, H)
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
### Dimensions
|
|
306
|
+
|
|
307
|
+
#### `width` *(getter)*
|
|
308
|
+
Current width of the terminal in columns, as reported by the writer. Returns `-1` if the writer does not implement `width()`. Always reflects the current size — read on every access, so it stays correct after a resize.
|
|
309
|
+
|
|
310
|
+
#### `height` *(getter)*
|
|
311
|
+
Current height of the terminal in rows, as reported by the writer. Returns `-1` if the writer does not implement `height()`. Same live semantics as `width`.
|
|
312
|
+
|
|
313
|
+
The built-in `Terminal.out` and `Terminal.err` instances always provide both — wired to `process.stdout.columns` / `process.stdout.rows` in both Bun and Node.
|
|
314
|
+
|
|
315
|
+
Custom sinks can opt in by implementing the optional `width` and `height` functions on `ITerminalWriter`:
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
const term = createTerminal({
|
|
319
|
+
write: s => myCanvas.write(s),
|
|
320
|
+
width: () => myCanvas.cols,
|
|
321
|
+
height: () => myCanvas.rows,
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
term.width // myCanvas.cols, live
|
|
325
|
+
term.height // myCanvas.rows, live
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
228
330
|
### Options
|
|
229
331
|
|
|
230
332
|
#### `plain`
|
|
@@ -346,6 +448,20 @@ Procedural fire simulation using the **half-block trick**: the `▄` character h
|
|
|
346
448
|
bun run sample/fire.ts
|
|
347
449
|
```
|
|
348
450
|
|
|
451
|
+
### `snake.ts`
|
|
452
|
+
Fully playable Snake game running in the alternate buffer. Uses `sync()` for tear-free rendering and updates only the cells that actually changed each tick. The snake body carries a smooth cyan-to-teal gradient; food pulses with an orange-yellow glow. Controls: WASD or arrow keys, Q to quit.
|
|
453
|
+
|
|
454
|
+
```sh
|
|
455
|
+
bun run sample/snake.ts
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### `rotozoom.ts`
|
|
459
|
+
Real-time rotating and zooming texture effect. Each frame the CPU computes a rotated/scaled UV map over the terminal dimensions and calls `out.framebuffer()` to push the result as a pixel buffer — demonstrating that `framebuffer()` is fast enough for 60 fps animation. Exit with any key.
|
|
460
|
+
|
|
461
|
+
```sh
|
|
462
|
+
bun run sample/rotozoom.ts
|
|
463
|
+
```
|
|
464
|
+
|
|
349
465
|
### `sysmon.ts`
|
|
350
466
|
Live system monitor that refreshes every second inside the alternate buffer. Two-panel layout drawn with box-drawing characters (`┌┬┐│├┤└┴┘─`). Left panel shows overall CPU average and per-core usage bars; right panel shows system RAM and process heap. All bars are color-coded: green below 70%, orange 70–90%, red above 90%.
|
|
351
467
|
|
package/dist/node.js
CHANGED
|
@@ -27,6 +27,11 @@ class Color {
|
|
|
27
27
|
this._g = g;
|
|
28
28
|
this._b = b;
|
|
29
29
|
this._a = a;
|
|
30
|
+
} else if (typeof rs === "number" && g === undefined && b === undefined) {
|
|
31
|
+
this._r = (rs & 255) / 255;
|
|
32
|
+
this._g = (rs >> 8 & 255) / 255;
|
|
33
|
+
this._b = (rs >> 16 & 255) / 255;
|
|
34
|
+
this._a = (rs >> 24 & 255) / 255;
|
|
30
35
|
} else if (typeof rs === "string") {
|
|
31
36
|
const match = rs.match(/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i);
|
|
32
37
|
if (match) {
|
|
@@ -126,6 +131,9 @@ class Color {
|
|
|
126
131
|
this._ansiFg = undefined;
|
|
127
132
|
this._ansiBg = undefined;
|
|
128
133
|
}
|
|
134
|
+
toRGBA() {
|
|
135
|
+
return (Math.round(this._a * 255) << 24 | Math.round(this._b * 255) << 16 | Math.round(this._g * 255) << 8 | Math.round(this._r * 255)) >>> 0;
|
|
136
|
+
}
|
|
129
137
|
toString() {
|
|
130
138
|
return `#${Math.round(this._r * 255).toString(16).padStart(2, "0")}${Math.round(this._g * 255).toString(16).padStart(2, "0")}${Math.round(this._b * 255).toString(16).padStart(2, "0")}${Math.round(this._a * 255).toString(16).padStart(2, "0")}`;
|
|
131
139
|
}
|
|
@@ -461,6 +469,48 @@ class TerminalCore {
|
|
|
461
469
|
else
|
|
462
470
|
this.writer.write(data);
|
|
463
471
|
}
|
|
472
|
+
framebuffer(fb, w, h) {
|
|
473
|
+
const ch = [];
|
|
474
|
+
for (let y = 0;y < h; y += 2) {
|
|
475
|
+
for (let x = 0;x < w; x++) {
|
|
476
|
+
const i = y * w + x;
|
|
477
|
+
const c1 = fb[i];
|
|
478
|
+
const c2 = fb[i + w];
|
|
479
|
+
const b1 = c1 >> 16 & 255;
|
|
480
|
+
const g1 = c1 >> 8 & 255;
|
|
481
|
+
const r1 = c1 & 255;
|
|
482
|
+
const b2 = c2 >> 16 & 255;
|
|
483
|
+
const g2 = c2 >> 8 & 255;
|
|
484
|
+
const r2 = c2 & 255;
|
|
485
|
+
ch.push("\x1B[48;2;");
|
|
486
|
+
ch.push(r1.toString());
|
|
487
|
+
ch.push(";");
|
|
488
|
+
ch.push(g1.toString());
|
|
489
|
+
ch.push(";");
|
|
490
|
+
ch.push(b1.toString());
|
|
491
|
+
ch.push("m\x1B[38;2;");
|
|
492
|
+
ch.push(r2.toString());
|
|
493
|
+
ch.push(";");
|
|
494
|
+
ch.push(g2.toString());
|
|
495
|
+
ch.push(";");
|
|
496
|
+
ch.push(b2.toString());
|
|
497
|
+
ch.push("m▄");
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
this.sync(() => {
|
|
501
|
+
this.raw(ch.join(""));
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
get width() {
|
|
505
|
+
if (this.writer.width)
|
|
506
|
+
return this.writer.width();
|
|
507
|
+
return -1;
|
|
508
|
+
}
|
|
509
|
+
get height() {
|
|
510
|
+
if (this.writer.height)
|
|
511
|
+
return this.writer.height();
|
|
512
|
+
return -1;
|
|
513
|
+
}
|
|
464
514
|
}
|
|
465
515
|
function installColorMethods() {
|
|
466
516
|
const proto = TerminalCore.prototype;
|
|
@@ -484,8 +534,8 @@ function createTerminal(writer, options = {}) {
|
|
|
484
534
|
}
|
|
485
535
|
// src/node.ts
|
|
486
536
|
var Terminal = {
|
|
487
|
-
out: createTerminal(process.stdout),
|
|
488
|
-
err: createTerminal(process.stderr)
|
|
537
|
+
out: createTerminal({ write: (data) => process.stdout.write(data), width: () => process.stdout.columns ?? 80, height: () => process.stdout.rows ?? 24 }),
|
|
538
|
+
err: createTerminal({ write: (data) => process.stderr.write(data), width: () => process.stderr.columns ?? 80, height: () => process.stderr.rows ?? 24 })
|
|
489
539
|
};
|
|
490
540
|
export {
|
|
491
541
|
createTerminal,
|
package/dist/terminal.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ import { Color } from '@retrovm/color';
|
|
|
6
6
|
*/
|
|
7
7
|
export interface ITerminalWriter {
|
|
8
8
|
write(data: string): void;
|
|
9
|
+
width?: () => number;
|
|
10
|
+
height?: () => number;
|
|
9
11
|
}
|
|
10
12
|
/**
|
|
11
13
|
* Extracts from `Color` only the keys whose value is an instance of `Color`,
|
|
@@ -212,6 +214,47 @@ declare class TerminalCore {
|
|
|
212
214
|
*/
|
|
213
215
|
sync(fn: () => void): this;
|
|
214
216
|
private emit;
|
|
217
|
+
/**
|
|
218
|
+
* Renders a raw pixel buffer to the terminal using the half-block trick.
|
|
219
|
+
*
|
|
220
|
+
* Each pair of vertically adjacent pixels is encoded as a single `▄`
|
|
221
|
+
* character: the upper pixel becomes the background color and the lower
|
|
222
|
+
* pixel becomes the foreground color, effectively doubling the vertical
|
|
223
|
+
* resolution — one character row covers two pixel rows.
|
|
224
|
+
*
|
|
225
|
+
* Pixel format: little-endian RGBA packed into a `Uint32Array`. Each
|
|
226
|
+
* element is `0xAABBGGRR` — R in the low byte, G in the next, B in the
|
|
227
|
+
* next, alpha ignored. This matches the layout produced by
|
|
228
|
+
* `Canvas.getImageData` and most image-decoding libraries when read as a
|
|
229
|
+
* `Uint32Array` on a little-endian system.
|
|
230
|
+
*
|
|
231
|
+
* The entire frame is assembled into one string before writing, which is
|
|
232
|
+
* far cheaper than calling `ink`/`paper`/`raw` per pixel. The write is
|
|
233
|
+
* wrapped in `sync()` to reduce tearing on capable terminals.
|
|
234
|
+
*
|
|
235
|
+
* @param fb - Pixel buffer. Length must be at least `w * h`.
|
|
236
|
+
* @param w - Width in pixels (equals the number of terminal columns used).
|
|
237
|
+
* @param h - Height in pixels. Must be even; an odd last row is ignored.
|
|
238
|
+
*/
|
|
239
|
+
framebuffer(fb: Uint32Array, w: number, h: number): void;
|
|
240
|
+
/**
|
|
241
|
+
* Current width of the terminal in columns, as reported by the writer.
|
|
242
|
+
* Returns `-1` if the writer does not implement `width()`.
|
|
243
|
+
*
|
|
244
|
+
* Called on every access so it always reflects the current size, even after
|
|
245
|
+
* a resize event. The built-in Bun and Node writers read
|
|
246
|
+
* `process.stdout.columns` each time.
|
|
247
|
+
*/
|
|
248
|
+
get width(): number;
|
|
249
|
+
/**
|
|
250
|
+
* Current height of the terminal in rows, as reported by the writer.
|
|
251
|
+
* Returns `-1` if the writer does not implement `height()`.
|
|
252
|
+
*
|
|
253
|
+
* Called on every access so it always reflects the current size, even after
|
|
254
|
+
* a resize event. The built-in Bun and Node writers read
|
|
255
|
+
* `process.stdout.rows` each time.
|
|
256
|
+
*/
|
|
257
|
+
get height(): number;
|
|
215
258
|
}
|
|
216
259
|
/**
|
|
217
260
|
* Creates a new `Terminal` instance backed by `writer`.
|
package/dist/terminal.js
CHANGED
|
@@ -27,6 +27,11 @@ class Color {
|
|
|
27
27
|
this._g = g;
|
|
28
28
|
this._b = b;
|
|
29
29
|
this._a = a;
|
|
30
|
+
} else if (typeof rs === "number" && g === undefined && b === undefined) {
|
|
31
|
+
this._r = (rs & 255) / 255;
|
|
32
|
+
this._g = (rs >> 8 & 255) / 255;
|
|
33
|
+
this._b = (rs >> 16 & 255) / 255;
|
|
34
|
+
this._a = (rs >> 24 & 255) / 255;
|
|
30
35
|
} else if (typeof rs === "string") {
|
|
31
36
|
const match = rs.match(/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i);
|
|
32
37
|
if (match) {
|
|
@@ -126,6 +131,9 @@ class Color {
|
|
|
126
131
|
this._ansiFg = undefined;
|
|
127
132
|
this._ansiBg = undefined;
|
|
128
133
|
}
|
|
134
|
+
toRGBA() {
|
|
135
|
+
return (Math.round(this._a * 255) << 24 | Math.round(this._b * 255) << 16 | Math.round(this._g * 255) << 8 | Math.round(this._r * 255)) >>> 0;
|
|
136
|
+
}
|
|
129
137
|
toString() {
|
|
130
138
|
return `#${Math.round(this._r * 255).toString(16).padStart(2, "0")}${Math.round(this._g * 255).toString(16).padStart(2, "0")}${Math.round(this._b * 255).toString(16).padStart(2, "0")}${Math.round(this._a * 255).toString(16).padStart(2, "0")}`;
|
|
131
139
|
}
|
|
@@ -461,6 +469,48 @@ class TerminalCore {
|
|
|
461
469
|
else
|
|
462
470
|
this.writer.write(data);
|
|
463
471
|
}
|
|
472
|
+
framebuffer(fb, w, h) {
|
|
473
|
+
const ch = [];
|
|
474
|
+
for (let y = 0;y < h; y += 2) {
|
|
475
|
+
for (let x = 0;x < w; x++) {
|
|
476
|
+
const i = y * w + x;
|
|
477
|
+
const c1 = fb[i];
|
|
478
|
+
const c2 = fb[i + w];
|
|
479
|
+
const b1 = c1 >> 16 & 255;
|
|
480
|
+
const g1 = c1 >> 8 & 255;
|
|
481
|
+
const r1 = c1 & 255;
|
|
482
|
+
const b2 = c2 >> 16 & 255;
|
|
483
|
+
const g2 = c2 >> 8 & 255;
|
|
484
|
+
const r2 = c2 & 255;
|
|
485
|
+
ch.push("\x1B[48;2;");
|
|
486
|
+
ch.push(r1.toString());
|
|
487
|
+
ch.push(";");
|
|
488
|
+
ch.push(g1.toString());
|
|
489
|
+
ch.push(";");
|
|
490
|
+
ch.push(b1.toString());
|
|
491
|
+
ch.push("m\x1B[38;2;");
|
|
492
|
+
ch.push(r2.toString());
|
|
493
|
+
ch.push(";");
|
|
494
|
+
ch.push(g2.toString());
|
|
495
|
+
ch.push(";");
|
|
496
|
+
ch.push(b2.toString());
|
|
497
|
+
ch.push("m▄");
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
this.sync(() => {
|
|
501
|
+
this.raw(ch.join(""));
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
get width() {
|
|
505
|
+
if (this.writer.width)
|
|
506
|
+
return this.writer.width();
|
|
507
|
+
return -1;
|
|
508
|
+
}
|
|
509
|
+
get height() {
|
|
510
|
+
if (this.writer.height)
|
|
511
|
+
return this.writer.height();
|
|
512
|
+
return -1;
|
|
513
|
+
}
|
|
464
514
|
}
|
|
465
515
|
function installColorMethods() {
|
|
466
516
|
const proto = TerminalCore.prototype;
|
package/package.json
CHANGED
|
@@ -1,28 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrovm/terminal",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Fluent ANSI terminal library — 24-bit color, cursor control and screen management for Bun and Node.js",
|
|
3
|
+
"version": "0.3.0",
|
|
5
4
|
"author": "Juan Carlos González Amestoy",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"keywords": [
|
|
8
|
-
"terminal",
|
|
9
|
-
"ansi",
|
|
10
|
-
"color",
|
|
11
|
-
"cursor",
|
|
12
|
-
"tui",
|
|
13
|
-
"cli",
|
|
14
|
-
"bun",
|
|
15
|
-
"fluent"
|
|
16
|
-
],
|
|
17
5
|
"repository": {
|
|
18
6
|
"type": "git",
|
|
19
7
|
"url": "https://github.com/retrovm/terminal.git"
|
|
20
8
|
},
|
|
21
|
-
"type": "module",
|
|
22
9
|
"module": "src/terminal.ts",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@types/bun": "latest",
|
|
12
|
+
"@types/node": "^25.9.1",
|
|
13
|
+
"typescript": "^5.9.3"
|
|
14
|
+
},
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"typescript": "^5"
|
|
26
17
|
},
|
|
27
18
|
"exports": {
|
|
28
19
|
".": {
|
|
@@ -35,22 +26,31 @@
|
|
|
35
26
|
"import": "./dist/terminal.js"
|
|
36
27
|
}
|
|
37
28
|
},
|
|
29
|
+
"description": "Fluent ANSI terminal library — 24-bit color, cursor control and screen management for Bun and Node.js",
|
|
38
30
|
"files": [
|
|
39
31
|
"src",
|
|
40
32
|
"dist"
|
|
41
33
|
],
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
34
|
+
"keywords": [
|
|
35
|
+
"terminal",
|
|
36
|
+
"ansi",
|
|
37
|
+
"color",
|
|
38
|
+
"cursor",
|
|
39
|
+
"tui",
|
|
40
|
+
"cli",
|
|
41
|
+
"bun",
|
|
42
|
+
"fluent"
|
|
43
|
+
],
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
46
47
|
},
|
|
47
|
-
"
|
|
48
|
-
"
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "bun build src/terminal.ts src/node.ts --outdir dist --target node && tsc -p tsconfig.build.json",
|
|
50
|
+
"prepublishOnly": "bun run build"
|
|
49
51
|
},
|
|
52
|
+
"type": "module",
|
|
50
53
|
"dependencies": {
|
|
51
|
-
"@retrovm/color": "^0.
|
|
52
|
-
},
|
|
53
|
-
"publishConfig": {
|
|
54
|
-
"access": "public"
|
|
54
|
+
"@retrovm/color": "^0.2.2"
|
|
55
55
|
}
|
|
56
56
|
}
|
package/src/bun.ts
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
/*Copyright (c) 2026 Juan Carlos González Amestoy
|
|
2
|
-
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
-
in the Software without restriction, including without limitation the rights
|
|
6
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
-
furnished to do so, subject to the following conditions:
|
|
9
|
-
|
|
10
|
-
The above copyright notice and this permission notice shall be included in all
|
|
11
|
-
copies or substantial portions of the Software.
|
|
12
|
-
|
|
13
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
-
SOFTWARE.*/
|
|
20
|
-
|
|
21
|
-
import { createTerminal } from "./terminal"
|
|
22
|
-
export { createTerminal, type ITerminal, type ITerminalWriter } from "./terminal"
|
|
23
|
-
|
|
24
|
-
const _outWriter = Bun.stdout.writer()
|
|
25
|
-
const _errWriter = Bun.stderr.writer()
|
|
26
|
-
|
|
27
|
-
const _writeOut = (data: string) => { _outWriter.write(data); _outWriter.flush() }
|
|
28
|
-
const _writeErr = (data: string) => { _errWriter.write(data); _errWriter.flush() }
|
|
29
|
-
|
|
30
|
-
export const Terminal = {
|
|
31
|
-
out: createTerminal({ write: _writeOut }),
|
|
32
|
-
err: createTerminal({ write: _writeErr }),
|
|
1
|
+
/*Copyright (c) 2026 Juan Carlos González Amestoy
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.*/
|
|
20
|
+
|
|
21
|
+
import { createTerminal } from "./terminal"
|
|
22
|
+
export { createTerminal, type ITerminal, type ITerminalWriter } from "./terminal"
|
|
23
|
+
|
|
24
|
+
const _outWriter = Bun.stdout.writer()
|
|
25
|
+
const _errWriter = Bun.stderr.writer()
|
|
26
|
+
|
|
27
|
+
const _writeOut = (data: string) => { _outWriter.write(data); _outWriter.flush() }
|
|
28
|
+
const _writeErr = (data: string) => { _errWriter.write(data); _errWriter.flush() }
|
|
29
|
+
|
|
30
|
+
export const Terminal = {
|
|
31
|
+
out: createTerminal({ write: _writeOut, width: () => process.stdout.columns ?? 80, height: () => process.stdout.rows ?? 24 }),
|
|
32
|
+
err: createTerminal({ write: _writeErr, width: () => process.stderr.columns ?? 80, height: () => process.stderr.rows ?? 24 }),
|
|
33
33
|
}
|
package/src/node.ts
CHANGED
|
@@ -2,6 +2,6 @@ import { createTerminal } from "./terminal"
|
|
|
2
2
|
export { createTerminal, type ITerminal, type ITerminalWriter } from "./terminal"
|
|
3
3
|
|
|
4
4
|
export const Terminal = {
|
|
5
|
-
out: createTerminal(process.stdout),
|
|
6
|
-
err: createTerminal(process.stderr),
|
|
5
|
+
out: createTerminal({ write: (data: string) => process.stdout.write(data), width: () => process.stdout.columns ?? 80, height: () => process.stdout.rows ?? 24 }),
|
|
6
|
+
err: createTerminal({ write: (data: string) => process.stderr.write(data), width: () => process.stderr.columns ?? 80, height: () => process.stderr.rows ?? 24 }),
|
|
7
7
|
}
|