@textui/core 0.4.0 → 0.5.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/dist/app/app.d.ts +19 -0
- package/dist/app/app.d.ts.map +1 -1
- package/dist/app/app.js +38 -2
- package/dist/jsx/intrinsics.d.ts +14 -1
- package/dist/jsx/intrinsics.d.ts.map +1 -1
- package/dist/runtime/paint.js +49 -1
- package/dist/types/app.d.ts +11 -0
- package/dist/types/app.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/app/app.ts +39 -2
- package/src/jsx/intrinsics.ts +14 -1
- package/src/runtime/paint.ts +53 -2
- package/src/types/app.ts +11 -0
package/dist/app/app.d.ts
CHANGED
|
@@ -54,6 +54,8 @@ export declare class App implements TextUIApp {
|
|
|
54
54
|
private frameScheduled;
|
|
55
55
|
private frameTimer;
|
|
56
56
|
private running_;
|
|
57
|
+
/** What `start` acquired, so `suspend` can put the same thing back. */
|
|
58
|
+
private session;
|
|
57
59
|
private disposed;
|
|
58
60
|
private themeId;
|
|
59
61
|
private shellId;
|
|
@@ -105,6 +107,23 @@ export declare class App implements TextUIApp {
|
|
|
105
107
|
activeShell(): string;
|
|
106
108
|
setCapabilityOverrides(overrides: CapabilityOverrides): void;
|
|
107
109
|
start(): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* Hand the terminal to something else, and take it back.
|
|
112
|
+
*
|
|
113
|
+
* For a program that draws for itself - an editor, a pager, a shell. The
|
|
114
|
+
* session is released, so the alt screen is left, raw mode is off and the
|
|
115
|
+
* child inherits a terminal in the state it expects; then it is acquired
|
|
116
|
+
* again exactly as it was.
|
|
117
|
+
*
|
|
118
|
+
* The frame buffer is invalidated on the way back rather than merely
|
|
119
|
+
* redrawn. The renderer writes the difference between what it painted last
|
|
120
|
+
* and what it paints now, and after another program has been on the screen
|
|
121
|
+
* that difference is against something no longer there - so a plain redraw
|
|
122
|
+
* puts back only the cells this application happened to change.
|
|
123
|
+
*
|
|
124
|
+
* `run` rejecting still gives the terminal back.
|
|
125
|
+
*/
|
|
126
|
+
suspend<T>(run: () => Promise<T>): Promise<T>;
|
|
108
127
|
stop(): Promise<void>;
|
|
109
128
|
dispose(): void;
|
|
110
129
|
/**
|
package/dist/app/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/app/app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAAE,aAAa,EAAE,SAAS,EAC3C,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,EAAE,IAAI,EAAQ,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/app/app.ts"],"names":[],"mappings":"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"}
|
package/dist/app/app.js
CHANGED
|
@@ -70,6 +70,8 @@ export class App {
|
|
|
70
70
|
frameScheduled = false;
|
|
71
71
|
frameTimer = null;
|
|
72
72
|
running_ = false;
|
|
73
|
+
/** What `start` acquired, so `suspend` can put the same thing back. */
|
|
74
|
+
session = null;
|
|
73
75
|
disposed = false;
|
|
74
76
|
themeId;
|
|
75
77
|
shellId;
|
|
@@ -307,7 +309,10 @@ export class App {
|
|
|
307
309
|
this.setTheme(shellTheme);
|
|
308
310
|
}
|
|
309
311
|
const caps = this.terminal.capabilities();
|
|
310
|
-
|
|
312
|
+
// Kept, because `suspend` has to put back exactly what was taken: a
|
|
313
|
+
// session re-acquired from defaults would come back without the mouse, or
|
|
314
|
+
// with an alt screen the caller had asked not to have.
|
|
315
|
+
this.session = {
|
|
311
316
|
managed: true,
|
|
312
317
|
altScreen: true,
|
|
313
318
|
hideCursor: true,
|
|
@@ -317,7 +322,8 @@ export class App {
|
|
|
317
322
|
focusEvents: caps.focusEvents,
|
|
318
323
|
enhancedKeys: caps.kittyKeyboard,
|
|
319
324
|
...this.options.session,
|
|
320
|
-
}
|
|
325
|
+
};
|
|
326
|
+
await this.terminal.acquire(this.session);
|
|
321
327
|
// After `acquire`, never before: with no session there is nothing to put
|
|
322
328
|
// the shape back, so an early call is dropped rather than leaked.
|
|
323
329
|
this.applyCursorShape();
|
|
@@ -327,6 +333,36 @@ export class App {
|
|
|
327
333
|
this.publishEnvironment();
|
|
328
334
|
this.renderFrame();
|
|
329
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* Hand the terminal to something else, and take it back.
|
|
338
|
+
*
|
|
339
|
+
* For a program that draws for itself - an editor, a pager, a shell. The
|
|
340
|
+
* session is released, so the alt screen is left, raw mode is off and the
|
|
341
|
+
* child inherits a terminal in the state it expects; then it is acquired
|
|
342
|
+
* again exactly as it was.
|
|
343
|
+
*
|
|
344
|
+
* The frame buffer is invalidated on the way back rather than merely
|
|
345
|
+
* redrawn. The renderer writes the difference between what it painted last
|
|
346
|
+
* and what it paints now, and after another program has been on the screen
|
|
347
|
+
* that difference is against something no longer there - so a plain redraw
|
|
348
|
+
* puts back only the cells this application happened to change.
|
|
349
|
+
*
|
|
350
|
+
* `run` rejecting still gives the terminal back.
|
|
351
|
+
*/
|
|
352
|
+
async suspend(run) {
|
|
353
|
+
if (!this.running_ || !this.session)
|
|
354
|
+
return run();
|
|
355
|
+
await this.terminal.release();
|
|
356
|
+
try {
|
|
357
|
+
return await run();
|
|
358
|
+
}
|
|
359
|
+
finally {
|
|
360
|
+
await this.terminal.acquire(this.session);
|
|
361
|
+
this.applyCursorShape();
|
|
362
|
+
this.buffer_.invalidate();
|
|
363
|
+
this.renderFrame();
|
|
364
|
+
}
|
|
365
|
+
}
|
|
330
366
|
async stop() {
|
|
331
367
|
if (!this.running_)
|
|
332
368
|
return;
|
package/dist/jsx/intrinsics.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Style, StyleInput } from '../types/style.js';
|
|
1
|
+
import type { Style, StyleColor, StyleInput } from '../types/style.js';
|
|
2
2
|
import type { SemanticRole } from '../types/component-registry.js';
|
|
3
3
|
import type { KeyEvent, MouseEvent } from '../types/input.js';
|
|
4
4
|
import type { PaintSurface, RenderContext } from '../types/render.js';
|
|
@@ -94,6 +94,19 @@ export interface TextProps extends BaseProps {
|
|
|
94
94
|
/** Where to cut when the text does not fit. */
|
|
95
95
|
truncate?: 'end' | 'start' | 'middle' | false;
|
|
96
96
|
ellipsis?: string;
|
|
97
|
+
/**
|
|
98
|
+
* Text to pick out wherever it appears, case-insensitively.
|
|
99
|
+
*
|
|
100
|
+
* For search: the caller passes what it is looking for and the rows are
|
|
101
|
+
* coloured where they hold it. It is applied after wrapping and truncation,
|
|
102
|
+
* to the text as drawn - so nothing about how a paragraph is broken into
|
|
103
|
+
* lines has to change to mark a hit in it, and a match split across a wrap
|
|
104
|
+
* is simply not on either row to colour.
|
|
105
|
+
*/
|
|
106
|
+
match?: string;
|
|
107
|
+
/** The match's colours. Accent on its own foreground by default. */
|
|
108
|
+
matchFg?: StyleColor;
|
|
109
|
+
matchBg?: StyleColor;
|
|
97
110
|
}
|
|
98
111
|
export interface CanvasProps extends BaseProps {
|
|
99
112
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intrinsics.d.ts","sourceRoot":"","sources":["../../src/jsx/intrinsics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"intrinsics.d.ts","sourceRoot":"","sources":["../../src/jsx/intrinsics.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/paint.js
CHANGED
|
@@ -551,6 +551,22 @@ function paintText(surface, box, visual, instance, env) {
|
|
|
551
551
|
attrs: visual.attrs,
|
|
552
552
|
link: typeof instance.props.link === 'string' ? instance.props.link : undefined,
|
|
553
553
|
};
|
|
554
|
+
/*
|
|
555
|
+
* Text to pick out of this one, and how to draw it where it appears.
|
|
556
|
+
*
|
|
557
|
+
* Search highlighting is a paint-time concern and not a content one: the
|
|
558
|
+
* caller passes the same string it is searching for and the wrapped rows
|
|
559
|
+
* are coloured where they hold it, so nothing about how the text is broken
|
|
560
|
+
* into lines has to change to mark a hit in it.
|
|
561
|
+
*/
|
|
562
|
+
const match = typeof instance.props.match === 'string'
|
|
563
|
+
? instance.props.match.toLowerCase()
|
|
564
|
+
: '';
|
|
565
|
+
const matchStyle = {
|
|
566
|
+
...style,
|
|
567
|
+
fg: colorOf(packStyleColor(instance.props.matchFg ?? 'onAccent', env.theme)),
|
|
568
|
+
bg: colorOf(packStyleColor(instance.props.matchBg ?? 'accent', env.theme)),
|
|
569
|
+
};
|
|
554
570
|
const wrap = visual.style.wrap ?? 'none';
|
|
555
571
|
const align = visual.style.textAlign ?? 'left';
|
|
556
572
|
// The ellipsis is a glyph like any other: on an ascii terminal it is '...'.
|
|
@@ -578,9 +594,41 @@ function paintText(surface, box, visual, instance, env) {
|
|
|
578
594
|
const offset = align === 'center' ? Math.max(0, Math.floor((area.width - w) / 2))
|
|
579
595
|
: align === 'right' ? Math.max(0, area.width - w)
|
|
580
596
|
: 0;
|
|
581
|
-
|
|
597
|
+
if (match === '') {
|
|
598
|
+
surface.text(area.x + offset, area.y + i, line, style);
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
for (const run of split(line, match)) {
|
|
602
|
+
surface.text(area.x + offset + stringWidth(line.slice(0, run.at)), area.y + i, run.text, run.hit ? matchStyle : style);
|
|
603
|
+
}
|
|
582
604
|
}
|
|
583
605
|
}
|
|
606
|
+
/**
|
|
607
|
+
* A line cut into the parts that match a needle and the parts that do not.
|
|
608
|
+
*
|
|
609
|
+
* Case-insensitive, and over the line as it will be drawn - so a match broken
|
|
610
|
+
* across a wrap is two lines with no match in either, which is the honest
|
|
611
|
+
* answer: there is nothing on one row to put a colour on.
|
|
612
|
+
*/
|
|
613
|
+
function split(line, needle) {
|
|
614
|
+
const runs = [];
|
|
615
|
+
const haystack = line.toLowerCase();
|
|
616
|
+
let from = 0;
|
|
617
|
+
for (;;) {
|
|
618
|
+
const at = haystack.indexOf(needle, from);
|
|
619
|
+
if (at === -1)
|
|
620
|
+
break;
|
|
621
|
+
if (at > from)
|
|
622
|
+
runs.push({ at: from, text: line.slice(from, at), hit: false });
|
|
623
|
+
runs.push({ at, text: line.slice(at, at + needle.length), hit: true });
|
|
624
|
+
from = at + needle.length;
|
|
625
|
+
}
|
|
626
|
+
if (runs.length === 0)
|
|
627
|
+
return [{ at: 0, text: line, hit: false }];
|
|
628
|
+
if (from < line.length)
|
|
629
|
+
runs.push({ at: from, text: line.slice(from), hit: false });
|
|
630
|
+
return runs;
|
|
631
|
+
}
|
|
584
632
|
/**
|
|
585
633
|
* The escape hatch. A canvas draws in its own coordinate space starting at
|
|
586
634
|
* 0,0, clipped to its content box - so a chart can be written without knowing
|
package/dist/types/app.d.ts
CHANGED
|
@@ -62,6 +62,17 @@ export interface TextUIApp extends Disposable {
|
|
|
62
62
|
start(): Promise<void>;
|
|
63
63
|
/** Release exactly what was acquired, then stop. */
|
|
64
64
|
stop(): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Hand the terminal to something that draws for itself, and take it back.
|
|
67
|
+
*
|
|
68
|
+
* For an editor, a pager, a shell. The session is released so the child
|
|
69
|
+
* inherits a terminal in the state it expects - no alt screen, no raw mode -
|
|
70
|
+
* and is acquired again afterwards exactly as it was, with the frame
|
|
71
|
+
* repainted whole rather than diffed against what another program left.
|
|
72
|
+
*
|
|
73
|
+
* `run` rejecting still gives the terminal back.
|
|
74
|
+
*/
|
|
75
|
+
suspend<T>(run: () => Promise<T>): Promise<T>;
|
|
65
76
|
/** Force a frame now, outside the scheduler. Tests and screenshots use it. */
|
|
66
77
|
flush(): void;
|
|
67
78
|
/**
|
package/dist/types/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/types/app.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/types/app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;GAIG;AACH,MAAM,WAAW,SAAU,SAAQ,UAAU;IAC3C,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IAEnC,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;IAC5C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,IAAI,MAAM,CAAC;IACtB,sBAAsB,CAAC,SAAS,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAE7D,sDAAsD;IACtD,sDAAsD;IACtD,OAAO,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IAEnC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,oDAAoD;IACpD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB;;;;;;;;;OASG;IACH,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9C,8EAA8E;IAC9E,KAAK,IAAI,IAAI,CAAC;IACd;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,8BAA8B;IAC9B,MAAM,IAAI,UAAU,CAAC;IAErB;;;OAGG;IACH,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,UAAU,CAAC;IAEtD,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAC9B,YAAY,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;IAC9C,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;IAEpC,yEAAyE;IACzE,OAAO,IAAI,aAAa,GAAG,IAAI,CAAC;IAEhC;;;OAGG;IACH,KAAK,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/D;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;OASG;IACH,MAAM,CAAC,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,GAAG,UAAU,GAAG,OAAO,CAAC,IAAI,GAAG,UAAU,CAAC,CAAC;IACxE,6CAA6C;IAC7C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC;IAC1B,kDAAkD;IAClD,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IACzB,uDAAuD;IACvD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB"}
|
package/package.json
CHANGED
package/src/app/app.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { ResourceAdapter } from '../types/adapter.js';
|
|
|
7
7
|
import type { Size, Rect } from '../types/geometry.js';
|
|
8
8
|
import type { ResolvedTheme } from '../types/theme.js';
|
|
9
9
|
import type { TerminalCapabilities, CapabilityOverrides } from '../types/capabilities.js';
|
|
10
|
+
import type { TerminalSessionOptions } from '../types/terminal.js';
|
|
10
11
|
import type { InputEvent, KeyEvent, MouseEvent } from '../types/input.js';
|
|
11
12
|
import type { LayerEntry } from '../types/layer.js';
|
|
12
13
|
import type { Instance } from '../runtime/instance.js';
|
|
@@ -93,6 +94,8 @@ export class App implements TextUIApp {
|
|
|
93
94
|
private frameScheduled = false;
|
|
94
95
|
private frameTimer: ReturnType<typeof setTimeout> | null = null;
|
|
95
96
|
private running_ = false;
|
|
97
|
+
/** What `start` acquired, so `suspend` can put the same thing back. */
|
|
98
|
+
private session: TerminalSessionOptions | null = null;
|
|
96
99
|
private disposed = false;
|
|
97
100
|
private themeId: string;
|
|
98
101
|
private shellId: string;
|
|
@@ -363,7 +366,10 @@ export class App implements TextUIApp {
|
|
|
363
366
|
}
|
|
364
367
|
|
|
365
368
|
const caps = this.terminal.capabilities();
|
|
366
|
-
|
|
369
|
+
// Kept, because `suspend` has to put back exactly what was taken: a
|
|
370
|
+
// session re-acquired from defaults would come back without the mouse, or
|
|
371
|
+
// with an alt screen the caller had asked not to have.
|
|
372
|
+
this.session = {
|
|
367
373
|
managed: true,
|
|
368
374
|
altScreen: true,
|
|
369
375
|
hideCursor: true,
|
|
@@ -373,7 +379,8 @@ export class App implements TextUIApp {
|
|
|
373
379
|
focusEvents: caps.focusEvents,
|
|
374
380
|
enhancedKeys: caps.kittyKeyboard,
|
|
375
381
|
...this.options.session,
|
|
376
|
-
}
|
|
382
|
+
};
|
|
383
|
+
await this.terminal.acquire(this.session);
|
|
377
384
|
|
|
378
385
|
// After `acquire`, never before: with no session there is nothing to put
|
|
379
386
|
// the shape back, so an early call is dropped rather than leaked.
|
|
@@ -387,6 +394,36 @@ export class App implements TextUIApp {
|
|
|
387
394
|
this.renderFrame();
|
|
388
395
|
}
|
|
389
396
|
|
|
397
|
+
/**
|
|
398
|
+
* Hand the terminal to something else, and take it back.
|
|
399
|
+
*
|
|
400
|
+
* For a program that draws for itself - an editor, a pager, a shell. The
|
|
401
|
+
* session is released, so the alt screen is left, raw mode is off and the
|
|
402
|
+
* child inherits a terminal in the state it expects; then it is acquired
|
|
403
|
+
* again exactly as it was.
|
|
404
|
+
*
|
|
405
|
+
* The frame buffer is invalidated on the way back rather than merely
|
|
406
|
+
* redrawn. The renderer writes the difference between what it painted last
|
|
407
|
+
* and what it paints now, and after another program has been on the screen
|
|
408
|
+
* that difference is against something no longer there - so a plain redraw
|
|
409
|
+
* puts back only the cells this application happened to change.
|
|
410
|
+
*
|
|
411
|
+
* `run` rejecting still gives the terminal back.
|
|
412
|
+
*/
|
|
413
|
+
async suspend<T>(run: () => Promise<T>): Promise<T> {
|
|
414
|
+
if (!this.running_ || !this.session) return run();
|
|
415
|
+
await this.terminal.release();
|
|
416
|
+
try {
|
|
417
|
+
return await run();
|
|
418
|
+
}
|
|
419
|
+
finally {
|
|
420
|
+
await this.terminal.acquire(this.session);
|
|
421
|
+
this.applyCursorShape();
|
|
422
|
+
this.buffer_.invalidate();
|
|
423
|
+
this.renderFrame();
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
390
427
|
async stop(): Promise<void> {
|
|
391
428
|
if (!this.running_) return;
|
|
392
429
|
this.running_ = false;
|
package/src/jsx/intrinsics.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Style, StyleInput } from '../types/style.js';
|
|
1
|
+
import type { Style, StyleColor, StyleInput } from '../types/style.js';
|
|
2
2
|
import type { SemanticRole } from '../types/component-registry.js';
|
|
3
3
|
import type { KeyEvent, MouseEvent } from '../types/input.js';
|
|
4
4
|
import type { PaintSurface, RenderContext } from '../types/render.js';
|
|
@@ -99,6 +99,19 @@ export interface TextProps extends BaseProps {
|
|
|
99
99
|
/** Where to cut when the text does not fit. */
|
|
100
100
|
truncate?: 'end' | 'start' | 'middle' | false;
|
|
101
101
|
ellipsis?: string;
|
|
102
|
+
/**
|
|
103
|
+
* Text to pick out wherever it appears, case-insensitively.
|
|
104
|
+
*
|
|
105
|
+
* For search: the caller passes what it is looking for and the rows are
|
|
106
|
+
* coloured where they hold it. It is applied after wrapping and truncation,
|
|
107
|
+
* to the text as drawn - so nothing about how a paragraph is broken into
|
|
108
|
+
* lines has to change to mark a hit in it, and a match split across a wrap
|
|
109
|
+
* is simply not on either row to colour.
|
|
110
|
+
*/
|
|
111
|
+
match?: string;
|
|
112
|
+
/** The match's colours. Accent on its own foreground by default. */
|
|
113
|
+
matchFg?: StyleColor;
|
|
114
|
+
matchBg?: StyleColor;
|
|
102
115
|
}
|
|
103
116
|
|
|
104
117
|
export interface CanvasProps extends BaseProps {
|
package/src/runtime/paint.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Rect } from '../types/geometry.js';
|
|
2
|
-
import type { Style, TextWrap } from '../types/style.js';
|
|
2
|
+
import type { Style, StyleColor, TextWrap } from '../types/style.js';
|
|
3
3
|
import type { ResolvedTheme } from '../types/theme.js';
|
|
4
4
|
import type { TerminalCapabilities } from '../types/capabilities.js';
|
|
5
5
|
import type { Cell, Color } from '../types/cells.js';
|
|
@@ -713,6 +713,23 @@ function paintText(
|
|
|
713
713
|
link: typeof instance.props.link === 'string' ? instance.props.link : undefined,
|
|
714
714
|
};
|
|
715
715
|
|
|
716
|
+
/*
|
|
717
|
+
* Text to pick out of this one, and how to draw it where it appears.
|
|
718
|
+
*
|
|
719
|
+
* Search highlighting is a paint-time concern and not a content one: the
|
|
720
|
+
* caller passes the same string it is searching for and the wrapped rows
|
|
721
|
+
* are coloured where they hold it, so nothing about how the text is broken
|
|
722
|
+
* into lines has to change to mark a hit in it.
|
|
723
|
+
*/
|
|
724
|
+
const match = typeof instance.props.match === 'string'
|
|
725
|
+
? instance.props.match.toLowerCase()
|
|
726
|
+
: '';
|
|
727
|
+
const matchStyle: CellStyle = {
|
|
728
|
+
...style,
|
|
729
|
+
fg: colorOf(packStyleColor((instance.props.matchFg as StyleColor | undefined) ?? 'onAccent', env.theme)),
|
|
730
|
+
bg: colorOf(packStyleColor((instance.props.matchBg as StyleColor | undefined) ?? 'accent', env.theme)),
|
|
731
|
+
};
|
|
732
|
+
|
|
716
733
|
const wrap = visual.style.wrap ?? 'none';
|
|
717
734
|
const align = visual.style.textAlign ?? 'left';
|
|
718
735
|
// The ellipsis is a glyph like any other: on an ascii terminal it is '...'.
|
|
@@ -744,8 +761,42 @@ function paintText(
|
|
|
744
761
|
align === 'center' ? Math.max(0, Math.floor((area.width - w) / 2))
|
|
745
762
|
: align === 'right' ? Math.max(0, area.width - w)
|
|
746
763
|
: 0;
|
|
747
|
-
|
|
764
|
+
if (match === '') {
|
|
765
|
+
surface.text(area.x + offset, area.y + i, line, style);
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
for (const run of split(line, match)) {
|
|
769
|
+
surface.text(
|
|
770
|
+
area.x + offset + stringWidth(line.slice(0, run.at)),
|
|
771
|
+
area.y + i,
|
|
772
|
+
run.text,
|
|
773
|
+
run.hit ? matchStyle : style,
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* A line cut into the parts that match a needle and the parts that do not.
|
|
781
|
+
*
|
|
782
|
+
* Case-insensitive, and over the line as it will be drawn - so a match broken
|
|
783
|
+
* across a wrap is two lines with no match in either, which is the honest
|
|
784
|
+
* answer: there is nothing on one row to put a colour on.
|
|
785
|
+
*/
|
|
786
|
+
function split(line: string, needle: string): { at: number; text: string; hit: boolean }[] {
|
|
787
|
+
const runs: { at: number; text: string; hit: boolean }[] = [];
|
|
788
|
+
const haystack = line.toLowerCase();
|
|
789
|
+
let from = 0;
|
|
790
|
+
for (;;) {
|
|
791
|
+
const at = haystack.indexOf(needle, from);
|
|
792
|
+
if (at === -1) break;
|
|
793
|
+
if (at > from) runs.push({ at: from, text: line.slice(from, at), hit: false });
|
|
794
|
+
runs.push({ at, text: line.slice(at, at + needle.length), hit: true });
|
|
795
|
+
from = at + needle.length;
|
|
748
796
|
}
|
|
797
|
+
if (runs.length === 0) return [{ at: 0, text: line, hit: false }];
|
|
798
|
+
if (from < line.length) runs.push({ at: from, text: line.slice(from), hit: false });
|
|
799
|
+
return runs;
|
|
749
800
|
}
|
|
750
801
|
|
|
751
802
|
/**
|
package/src/types/app.ts
CHANGED
|
@@ -67,6 +67,17 @@ export interface TextUIApp extends Disposable {
|
|
|
67
67
|
start(): Promise<void>;
|
|
68
68
|
/** Release exactly what was acquired, then stop. */
|
|
69
69
|
stop(): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Hand the terminal to something that draws for itself, and take it back.
|
|
72
|
+
*
|
|
73
|
+
* For an editor, a pager, a shell. The session is released so the child
|
|
74
|
+
* inherits a terminal in the state it expects - no alt screen, no raw mode -
|
|
75
|
+
* and is acquired again afterwards exactly as it was, with the frame
|
|
76
|
+
* repainted whole rather than diffed against what another program left.
|
|
77
|
+
*
|
|
78
|
+
* `run` rejecting still gives the terminal back.
|
|
79
|
+
*/
|
|
80
|
+
suspend<T>(run: () => Promise<T>): Promise<T>;
|
|
70
81
|
/** Force a frame now, outside the scheduler. Tests and screenshots use it. */
|
|
71
82
|
flush(): void;
|
|
72
83
|
/**
|