@sagmans/dsh-tui 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/LICENSE +1 -1
- package/README.md +270 -68
- package/lib/agent/present.js +1 -1
- package/lib/agent/present.js.map +1 -1
- package/lib/agent/prompt-history.d.ts.map +1 -1
- package/lib/agent/prompt-history.js +5 -3
- package/lib/agent/prompt-history.js.map +1 -1
- package/lib/agent/status.d.ts +1 -1
- package/lib/cards.d.ts +83 -13
- package/lib/cards.d.ts.map +1 -1
- package/lib/cards.js +96 -28
- package/lib/cards.js.map +1 -1
- package/lib/export.d.ts +3 -3
- package/lib/export.d.ts.map +1 -1
- package/lib/export.js +23 -13
- package/lib/export.js.map +1 -1
- package/lib/fold-cursor.d.ts +12 -5
- package/lib/fold-cursor.d.ts.map +1 -1
- package/lib/fold-cursor.js +16 -5
- package/lib/fold-cursor.js.map +1 -1
- package/lib/gates.d.ts.map +1 -1
- package/lib/gates.js +42 -9
- package/lib/gates.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +459 -72
- package/lib/index.js.map +1 -1
- package/lib/injection.d.ts +9 -0
- package/lib/injection.d.ts.map +1 -0
- package/lib/injection.js +128 -0
- package/lib/injection.js.map +1 -0
- package/lib/input/actions.d.ts +19 -2
- package/lib/input/actions.d.ts.map +1 -1
- package/lib/input/actions.js +57 -11
- package/lib/input/actions.js.map +1 -1
- package/lib/input/cancel.d.ts +55 -0
- package/lib/input/cancel.d.ts.map +1 -0
- package/lib/input/cancel.js +47 -0
- package/lib/input/cancel.js.map +1 -0
- package/lib/input/completion.d.ts +5 -2
- package/lib/input/completion.d.ts.map +1 -1
- package/lib/input/completion.js +79 -4
- package/lib/input/completion.js.map +1 -1
- package/lib/input/file-search.d.ts +105 -0
- package/lib/input/file-search.d.ts.map +1 -0
- package/lib/input/file-search.js +665 -0
- package/lib/input/file-search.js.map +1 -0
- package/lib/input/fuzzy.d.ts +42 -0
- package/lib/input/fuzzy.d.ts.map +1 -0
- package/lib/input/fuzzy.js +289 -0
- package/lib/input/fuzzy.js.map +1 -0
- package/lib/input/keymap.d.ts +3 -1
- package/lib/input/keymap.d.ts.map +1 -1
- package/lib/input/keymap.js +14 -3
- package/lib/input/keymap.js.map +1 -1
- package/lib/input/match.d.ts +12 -4
- package/lib/input/match.d.ts.map +1 -1
- package/lib/input/match.js +50 -51
- package/lib/input/match.js.map +1 -1
- package/lib/input/submission.d.ts +10 -0
- package/lib/input/submission.d.ts.map +1 -1
- package/lib/input/submission.js +7 -6
- package/lib/input/submission.js.map +1 -1
- package/lib/keys-command.d.ts +19 -3
- package/lib/keys-command.d.ts.map +1 -1
- package/lib/keys-command.js +34 -31
- package/lib/keys-command.js.map +1 -1
- package/lib/settings-notice.d.ts +5 -0
- package/lib/settings-notice.d.ts.map +1 -1
- package/lib/settings-notice.js +9 -7
- package/lib/settings-notice.js.map +1 -1
- package/lib/stash/paths.d.ts +8 -8
- package/lib/stash/paths.d.ts.map +1 -1
- package/lib/stash/paths.js +19 -18
- package/lib/stash/paths.js.map +1 -1
- package/lib/stash/schema.d.ts +11 -12
- package/lib/stash/schema.d.ts.map +1 -1
- package/lib/stash/schema.js +10 -29
- package/lib/stash/schema.js.map +1 -1
- package/lib/stash/store.js +10 -10
- package/lib/stash/store.js.map +1 -1
- package/lib/stash.d.ts +37 -6
- package/lib/stash.d.ts.map +1 -1
- package/lib/stash.js +93 -36
- package/lib/stash.js.map +1 -1
- package/lib/terminal/external-editor.d.ts +93 -0
- package/lib/terminal/external-editor.d.ts.map +1 -0
- package/lib/terminal/external-editor.js +263 -0
- package/lib/terminal/external-editor.js.map +1 -0
- package/lib/terminal/host-writes.d.ts +39 -0
- package/lib/terminal/host-writes.d.ts.map +1 -0
- package/lib/terminal/host-writes.js +136 -0
- package/lib/terminal/host-writes.js.map +1 -0
- package/lib/terminal/signals.d.ts +25 -0
- package/lib/terminal/signals.d.ts.map +1 -0
- package/lib/terminal/signals.js +39 -0
- package/lib/terminal/signals.js.map +1 -0
- package/lib/terminal/warning-screen.d.ts +19 -1
- package/lib/terminal/warning-screen.d.ts.map +1 -1
- package/lib/terminal/warning-screen.js +37 -1
- package/lib/terminal/warning-screen.js.map +1 -1
- package/lib/terminal-text.d.ts +72 -0
- package/lib/terminal-text.d.ts.map +1 -0
- package/lib/terminal-text.js +603 -0
- package/lib/terminal-text.js.map +1 -0
- package/lib/text.d.ts +45 -6
- package/lib/text.d.ts.map +1 -1
- package/lib/text.js +106 -46
- package/lib/text.js.map +1 -1
- package/lib/theme-command.d.ts +7 -4
- package/lib/theme-command.d.ts.map +1 -1
- package/lib/theme-command.js +32 -12
- package/lib/theme-command.js.map +1 -1
- package/lib/theme-files.d.ts +110 -0
- package/lib/theme-files.d.ts.map +1 -0
- package/lib/theme-files.js +352 -0
- package/lib/theme-files.js.map +1 -0
- package/lib/theme-schema.d.ts +121 -0
- package/lib/theme-schema.d.ts.map +1 -0
- package/lib/theme-schema.js +87 -0
- package/lib/theme-schema.js.map +1 -0
- package/lib/theme-settings.d.ts +43 -10
- package/lib/theme-settings.d.ts.map +1 -1
- package/lib/theme-settings.js +103 -43
- package/lib/theme-settings.js.map +1 -1
- package/lib/theme-tokens.d.ts +39 -7
- package/lib/theme-tokens.d.ts.map +1 -1
- package/lib/theme-tokens.js +96 -13
- package/lib/theme-tokens.js.map +1 -1
- package/lib/theme.d.ts +24 -2
- package/lib/theme.d.ts.map +1 -1
- package/lib/theme.js +49 -6
- package/lib/theme.js.map +1 -1
- package/lib/tool-display.d.ts +57 -0
- package/lib/tool-display.d.ts.map +1 -0
- package/lib/tool-display.js +51 -0
- package/lib/tool-display.js.map +1 -0
- package/lib/transcript.d.ts +28 -0
- package/lib/transcript.d.ts.map +1 -1
- package/lib/transcript.js +126 -37
- package/lib/transcript.js.map +1 -1
- package/lib/ui/diff.d.ts +49 -0
- package/lib/ui/diff.d.ts.map +1 -0
- package/lib/ui/diff.js +208 -0
- package/lib/ui/diff.js.map +1 -0
- package/lib/ui/dock.d.ts.map +1 -1
- package/lib/ui/dock.js +9 -6
- package/lib/ui/dock.js.map +1 -1
- package/lib/ui/editor.d.ts.map +1 -1
- package/lib/ui/editor.js +4 -2
- package/lib/ui/editor.js.map +1 -1
- package/lib/ui/frame.d.ts +16 -5
- package/lib/ui/frame.d.ts.map +1 -1
- package/lib/ui/frame.js +32 -13
- package/lib/ui/frame.js.map +1 -1
- package/lib/ui/keymap-picker.d.ts +16 -0
- package/lib/ui/keymap-picker.d.ts.map +1 -0
- package/lib/ui/keymap-picker.js +41 -0
- package/lib/ui/keymap-picker.js.map +1 -0
- package/lib/ui/layout.d.ts +33 -0
- package/lib/ui/layout.d.ts.map +1 -0
- package/lib/ui/layout.js +33 -0
- package/lib/ui/layout.js.map +1 -0
- package/lib/ui/markdown.d.ts +25 -3
- package/lib/ui/markdown.d.ts.map +1 -1
- package/lib/ui/markdown.js +12 -8
- package/lib/ui/markdown.js.map +1 -1
- package/lib/ui/picker-card.d.ts +42 -0
- package/lib/ui/picker-card.d.ts.map +1 -0
- package/lib/ui/picker-card.js +148 -0
- package/lib/ui/picker-card.js.map +1 -0
- package/lib/ui/picker.d.ts +40 -2
- package/lib/ui/picker.d.ts.map +1 -1
- package/lib/ui/picker.js +50 -6
- package/lib/ui/picker.js.map +1 -1
- package/lib/ui/prompt.d.ts +10 -2
- package/lib/ui/prompt.d.ts.map +1 -1
- package/lib/ui/prompt.js +21 -2
- package/lib/ui/prompt.js.map +1 -1
- package/lib/ui/rows.d.ts +8 -6
- package/lib/ui/rows.d.ts.map +1 -1
- package/lib/ui/rows.js +10 -18
- package/lib/ui/rows.js.map +1 -1
- package/lib/ui/stash-picker.d.ts +2 -2
- package/lib/ui/stash-picker.d.ts.map +1 -1
- package/lib/ui/stash-picker.js +4 -4
- package/lib/ui/stash-picker.js.map +1 -1
- package/lib/ui/status.d.ts.map +1 -1
- package/lib/ui/status.js +18 -16
- package/lib/ui/status.js.map +1 -1
- package/lib/ui/theme-picker.d.ts +18 -0
- package/lib/ui/theme-picker.d.ts.map +1 -0
- package/lib/ui/theme-picker.js +68 -0
- package/lib/ui/theme-picker.js.map +1 -0
- package/lib/ui/view.d.ts +146 -22
- package/lib/ui/view.d.ts.map +1 -1
- package/lib/ui/view.js +461 -154
- package/lib/ui/view.js.map +1 -1
- package/package.json +3 -1
- package/themes/deepseek-blue.yaml +183 -0
- package/themes/violet-orbit.yaml +178 -0
package/lib/text.d.ts
CHANGED
|
@@ -3,17 +3,56 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Model output, tool output, and file content all reach the screen, and a
|
|
5
5
|
* terminal executes the escape sequences it is given: a crafted result could
|
|
6
|
-
* repaint the frame, retitle the window, or write the clipboard.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* repaint the frame, retitle the window, or write the clipboard. Every drawn
|
|
7
|
+
* fragment crosses one of the two boundaries here: `displayText` spells control
|
|
8
|
+
* characters out, and `terminal-text.ts` draws the safe subset the way the
|
|
9
|
+
* terminal that produced it would have, consuming the rest.
|
|
10
|
+
*
|
|
11
|
+
* Not every fragment is drawn, though: text restored into a live editor is
|
|
12
|
+
* stripped rather than escaped, because the editor has no way to show an escape
|
|
13
|
+
* and the terminal would act on it. `stripControlCharacters` is that boundary.
|
|
9
14
|
*/
|
|
15
|
+
import { type EscapeTextOptions } from './terminal-text.ts';
|
|
10
16
|
/**
|
|
11
17
|
* Render control characters as visible escapes, keeping line feeds.
|
|
12
18
|
*
|
|
13
19
|
* A line feed is the only control a renderer already understands; everything
|
|
14
20
|
* else becomes text so the reader can see that it was there instead of the
|
|
15
|
-
* terminal acting on it.
|
|
16
|
-
* stop the
|
|
21
|
+
* terminal acting on it. A tab is the exception that is not spelled: it is
|
|
22
|
+
* expanded to the stop the tool that wrote it used, because a stop the layout
|
|
23
|
+
* cannot predict would desynchronize wrapping. Text that is *drawn* is not read
|
|
24
|
+
* this way at all — it goes through `renderTerminalText`, which interprets the
|
|
25
|
+
* sequences a terminal would have interpreted.
|
|
26
|
+
*/
|
|
27
|
+
export declare function displayText(raw: string, options?: EscapeTextOptions): string;
|
|
28
|
+
/** One row of text: every run of line breaks becomes the space between its rows. */
|
|
29
|
+
export declare function oneRow(text: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* The first `limit` grapheme clusters of text.
|
|
32
|
+
*
|
|
33
|
+
* A budget counted in code points can cut a combining mark, a skin-tone modifier,
|
|
34
|
+
* or a joined emoji away from the cluster it belongs to, leaving half a character
|
|
35
|
+
* on the row. A cluster is the smallest run a cut may keep or drop; counting is
|
|
36
|
+
* still not measuring, so the renderer wraps and cuts by display width after.
|
|
37
|
+
*/
|
|
38
|
+
export declare function sliceGraphemes(text: string, limit: number): string;
|
|
39
|
+
/**
|
|
40
|
+
* The last `limit` grapheme clusters of text.
|
|
41
|
+
*
|
|
42
|
+
* A live thought grows from the end, so the head is what can be given up; the cut
|
|
43
|
+
* still falls between clusters, because half a character at the top of the row is
|
|
44
|
+
* the same glitch as half a character at the end of it.
|
|
45
|
+
*/
|
|
46
|
+
export declare function tailGraphemes(text: string, limit: number): string;
|
|
47
|
+
/**
|
|
48
|
+
* Text as the clusters a reader would count.
|
|
49
|
+
*
|
|
50
|
+
* The two cutters above bail out before scanning when the text is shorter than
|
|
51
|
+
* the budget; a caller comparing two pieces of text cluster by cluster — the
|
|
52
|
+
* two sides of an edit, for one — has to see every one of them, and comparing
|
|
53
|
+
* clusters is what keeps a drawn run from ending inside a character.
|
|
17
54
|
*/
|
|
18
|
-
export declare function
|
|
55
|
+
export declare function splitGraphemes(text: string): string[];
|
|
56
|
+
/** The form of text that is safe to put back into a live editor. */
|
|
57
|
+
export declare function stripControlCharacters(text: string): string;
|
|
19
58
|
//# sourceMappingURL=text.d.ts.map
|
package/lib/text.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAE/E;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAE5E;AAaD,oFAAoF;AACpF,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3C;AAKD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAUlE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOjE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAIrD;AAqBD,oEAAoE;AACpE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3D"}
|
package/lib/text.js
CHANGED
|
@@ -3,59 +3,119 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Model output, tool output, and file content all reach the screen, and a
|
|
5
5
|
* terminal executes the escape sequences it is given: a crafted result could
|
|
6
|
-
* repaint the frame, retitle the window, or write the clipboard.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* repaint the frame, retitle the window, or write the clipboard. Every drawn
|
|
7
|
+
* fragment crosses one of the two boundaries here: `displayText` spells control
|
|
8
|
+
* characters out, and `terminal-text.ts` draws the safe subset the way the
|
|
9
|
+
* terminal that produced it would have, consuming the rest.
|
|
10
|
+
*
|
|
11
|
+
* Not every fragment is drawn, though: text restored into a live editor is
|
|
12
|
+
* stripped rather than escaped, because the editor has no way to show an escape
|
|
13
|
+
* and the terminal would act on it. `stripControlCharacters` is that boundary.
|
|
9
14
|
*/
|
|
10
|
-
|
|
11
|
-
const LAST_C0 = 0x1f;
|
|
12
|
-
const DELETE = 0x7f;
|
|
13
|
-
const FIRST_C1 = 0x80;
|
|
14
|
-
const LAST_C1 = 0x9f;
|
|
15
|
-
const FIRST_SURROGATE = 0xd800;
|
|
16
|
-
const LAST_SURROGATE = 0xdfff;
|
|
17
|
-
const REPLACEMENT = '\uFFFD';
|
|
18
|
-
const C0_PREFIX = '\\x';
|
|
19
|
-
const UNICODE_PREFIX = '\\u';
|
|
20
|
-
/** Directional overrides and isolates can reorder the frame around a payload. */
|
|
21
|
-
const BIDI_CONTROLS = new Set([0x202a, 0x202b, 0x202c, 0x202d, 0x202e, 0x2066, 0x2067, 0x2068, 0x2069]);
|
|
22
|
-
/** Separators that end a line without a line feed. */
|
|
23
|
-
const LINE_SEPARATOR = 0x2028;
|
|
24
|
-
const PARAGRAPH_SEPARATOR = 0x2029;
|
|
25
|
-
function escapeCode(prefix, code, digits) {
|
|
26
|
-
return prefix + code.toString(16).toUpperCase().padStart(digits, '0');
|
|
27
|
-
}
|
|
15
|
+
import { escapeTerminalText } from "./terminal-text.js";
|
|
28
16
|
/**
|
|
29
17
|
* Render control characters as visible escapes, keeping line feeds.
|
|
30
18
|
*
|
|
31
19
|
* A line feed is the only control a renderer already understands; everything
|
|
32
20
|
* else becomes text so the reader can see that it was there instead of the
|
|
33
|
-
* terminal acting on it.
|
|
34
|
-
* stop the
|
|
21
|
+
* terminal acting on it. A tab is the exception that is not spelled: it is
|
|
22
|
+
* expanded to the stop the tool that wrote it used, because a stop the layout
|
|
23
|
+
* cannot predict would desynchronize wrapping. Text that is *drawn* is not read
|
|
24
|
+
* this way at all — it goes through `renderTerminalText`, which interprets the
|
|
25
|
+
* sequences a terminal would have interpreted.
|
|
26
|
+
*/
|
|
27
|
+
export function displayText(raw, options) {
|
|
28
|
+
return escapeTerminalText(raw, options);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The breaks a one-row cut must not carry.
|
|
32
|
+
*
|
|
33
|
+
* A line feed is the one control a renderer understands, so it survives
|
|
34
|
+
* {@link displayText}; a row that kept it would write the rest of itself on the
|
|
35
|
+
* row below, because the alternate screen runs with autowrap off and the break
|
|
36
|
+
* moves the cursor down instead of wrapping. Cutting is where a caller promises
|
|
37
|
+
* a single row, so the flattening happens there.
|
|
35
38
|
*/
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
39
|
+
const ROW_BREAKS = /[\r\n\u2028\u2029]+/gu;
|
|
40
|
+
/** One row of text: every run of line breaks becomes the space between its rows. */
|
|
41
|
+
export function oneRow(text) {
|
|
42
|
+
return text.replace(ROW_BREAKS, ' ');
|
|
43
|
+
}
|
|
44
|
+
/** Grapheme clusters, the smallest run of text a reader would recognize as one thing. */
|
|
45
|
+
const GRAPHEMES = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
|
|
46
|
+
/**
|
|
47
|
+
* The first `limit` grapheme clusters of text.
|
|
48
|
+
*
|
|
49
|
+
* A budget counted in code points can cut a combining mark, a skin-tone modifier,
|
|
50
|
+
* or a joined emoji away from the cluster it belongs to, leaving half a character
|
|
51
|
+
* on the row. A cluster is the smallest run a cut may keep or drop; counting is
|
|
52
|
+
* still not measuring, so the renderer wraps and cuts by display width after.
|
|
53
|
+
*/
|
|
54
|
+
export function sliceGraphemes(text, limit) {
|
|
55
|
+
if (limit <= 0)
|
|
56
|
+
return '';
|
|
57
|
+
// Code units are never fewer than clusters, so a short string needs no scan.
|
|
58
|
+
if (text.length <= limit)
|
|
59
|
+
return text;
|
|
60
|
+
const kept = [];
|
|
61
|
+
for (const { segment } of GRAPHEMES.segment(text)) {
|
|
62
|
+
if (kept.length >= limit)
|
|
63
|
+
break;
|
|
64
|
+
kept.push(segment);
|
|
58
65
|
}
|
|
59
|
-
return
|
|
66
|
+
return kept.join('');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The last `limit` grapheme clusters of text.
|
|
70
|
+
*
|
|
71
|
+
* A live thought grows from the end, so the head is what can be given up; the cut
|
|
72
|
+
* still falls between clusters, because half a character at the top of the row is
|
|
73
|
+
* the same glitch as half a character at the end of it.
|
|
74
|
+
*/
|
|
75
|
+
export function tailGraphemes(text, limit) {
|
|
76
|
+
if (limit <= 0)
|
|
77
|
+
return '';
|
|
78
|
+
// Code units are never fewer than clusters, so a short string needs no scan.
|
|
79
|
+
if (text.length <= limit)
|
|
80
|
+
return text;
|
|
81
|
+
const clusters = [];
|
|
82
|
+
for (const { segment } of GRAPHEMES.segment(text))
|
|
83
|
+
clusters.push(segment);
|
|
84
|
+
return clusters.length <= limit ? text : clusters.slice(-limit).join('');
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Text as the clusters a reader would count.
|
|
88
|
+
*
|
|
89
|
+
* The two cutters above bail out before scanning when the text is shorter than
|
|
90
|
+
* the budget; a caller comparing two pieces of text cluster by cluster — the
|
|
91
|
+
* two sides of an edit, for one — has to see every one of them, and comparing
|
|
92
|
+
* clusters is what keeps a drawn run from ending inside a character.
|
|
93
|
+
*/
|
|
94
|
+
export function splitGraphemes(text) {
|
|
95
|
+
const clusters = [];
|
|
96
|
+
for (const { segment } of GRAPHEMES.segment(text))
|
|
97
|
+
clusters.push(segment);
|
|
98
|
+
return clusters;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Control characters text kept for a terminal can never legitimately need:
|
|
102
|
+
* everything below the printable range except the tab and line feed that lay
|
|
103
|
+
* text out, plus DEL, the C1 block, and the bidi overrides.
|
|
104
|
+
*
|
|
105
|
+
* Escaping is what text that is drawn needs; this is for text handed back to a
|
|
106
|
+
* live editor instead — a stashed draft being restored, or a draft returning
|
|
107
|
+
* from the reader's own editor. A sequence that reached either through a
|
|
108
|
+
* hand-edited file would be executed as a command rather than appearing as the
|
|
109
|
+
* text they asked for: clearing the screen, or replacing the clipboard over
|
|
110
|
+
* OSC 52. The bidi overrides go with them because they draw nothing, so they
|
|
111
|
+
* cannot be seen and cannot be removed by hand, and what they reorder is what
|
|
112
|
+
* the reader is about to run; a terminal that shapes right-to-left text still
|
|
113
|
+
* has the letters themselves. A carriage return goes too, so a draft saved with
|
|
114
|
+
* CRLF endings arrives as lines rather than as a control the editor would draw.
|
|
115
|
+
*/
|
|
116
|
+
const DISALLOWED_CONTROL_CHARACTERS = /[\u0000-\u0008\u000B-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/gu;
|
|
117
|
+
/** The form of text that is safe to put back into a live editor. */
|
|
118
|
+
export function stripControlCharacters(text) {
|
|
119
|
+
return text.replace(DISALLOWED_CONTROL_CHARACTERS, '');
|
|
60
120
|
}
|
|
61
121
|
//# sourceMappingURL=text.js.map
|
package/lib/text.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,kBAAkB,EAA0B,MAAM,oBAAoB,CAAA;AAE/E;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,OAA2B;IAClE,OAAO,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;AACzC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,GAAG,uBAAuB,CAAA;AAE1C,oFAAoF;AACpF,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;AACtC,CAAC;AAED,yFAAyF;AACzF,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAA;AAE5E;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,KAAa;IACxD,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,EAAE,CAAA;IACzB,6EAA6E;IAC7E,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK;QAAE,OAAO,IAAI,CAAA;IACrC,MAAM,IAAI,GAAa,EAAE,CAAA;IACzB,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAClD,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK;YAAE,MAAK;QAC/B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACpB,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AACtB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,KAAa;IACvD,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,EAAE,CAAA;IACzB,6EAA6E;IAC7E,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK;QAAE,OAAO,IAAI,CAAA;IACrC,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACzE,OAAO,QAAQ,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAC1E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACzE,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,6BAA6B,GACjC,yFAAyF,CAAA;AAE3F,oEAAoE;AACpE,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAO,IAAI,CAAC,OAAO,CAAC,6BAA6B,EAAE,EAAE,CAAC,CAAA;AACxD,CAAC"}
|
package/lib/theme-command.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ThemeLibrary } from './theme-files.ts';
|
|
2
|
+
import { type ThemeOverrides } from './theme-settings.ts';
|
|
2
3
|
/**
|
|
3
4
|
* The effective table, one line per element.
|
|
4
5
|
*
|
|
5
6
|
* The token name comes first because it is what the reader types into
|
|
6
|
-
* settings.yaml; the origin comes last because it is what explains the value
|
|
7
|
-
*
|
|
7
|
+
* settings.yaml; the origin comes last because it is what explains the value when
|
|
8
|
+
* the value is not what they expected. The footer names the themes that exist
|
|
9
|
+
* rather than the ones this build was compiled with, because the file a reader
|
|
10
|
+
* saved a second ago is the one they need to hear about.
|
|
8
11
|
*/
|
|
9
|
-
export declare function renderThemeTable(overrides: ThemeOverrides): string[];
|
|
12
|
+
export declare function renderThemeTable(overrides: ThemeOverrides, library: ThemeLibrary): string[];
|
|
10
13
|
//# sourceMappingURL=theme-command.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-command.d.ts","sourceRoot":"","sources":["../src/theme-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"theme-command.d.ts","sourceRoot":"","sources":["../src/theme-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAwDrE;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,EAAE,CA4B3F"}
|
package/lib/theme-command.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { themeLayer } from "./theme-settings.js";
|
|
2
|
+
import { mergeTokenSpec, PALETTE_NAMES, TUI_TOKENS, } from "./theme-tokens.js";
|
|
2
3
|
/** A colour as the reader would see it applied, with a palette name resolved. */
|
|
3
4
|
function showColour(spec, palette) {
|
|
4
5
|
if (typeof spec === 'string' && PALETTE_NAMES.includes(spec)) {
|
|
@@ -10,12 +11,12 @@ function showColour(spec, palette) {
|
|
|
10
11
|
* Describe one token's effective value and its origin.
|
|
11
12
|
*
|
|
12
13
|
* A settings file that does nothing looks exactly like one that works, so the
|
|
13
|
-
* reader needs to see which layer won:
|
|
14
|
-
* named, or the shipped default it never touched. The value is the
|
|
15
|
-
* renderer would apply, not the fragment the reader happened to write.
|
|
14
|
+
* reader needs to see which layer won: a field they wrote, a theme they chose,
|
|
15
|
+
* the palette it named, or the shipped default it never touched. The value is the
|
|
16
|
+
* merged one a renderer would apply, not the fragment the reader happened to write.
|
|
16
17
|
*/
|
|
17
|
-
function describeToken(token, overrides) {
|
|
18
|
-
const spec = mergeTokenSpec(token, overrides.tokens);
|
|
18
|
+
function describeToken(token, overrides, themed) {
|
|
19
|
+
const spec = mergeTokenSpec(token, overrides.tokens, themed);
|
|
19
20
|
const fields = [];
|
|
20
21
|
if (spec.fg !== undefined)
|
|
21
22
|
fields.push(showColour(spec.fg, overrides.palette));
|
|
@@ -30,7 +31,11 @@ function describeToken(token, overrides) {
|
|
|
30
31
|
if (spec.hidden === true)
|
|
31
32
|
fields.push('hidden');
|
|
32
33
|
const named = typeof spec.fg === 'string' && PALETTE_NAMES.includes(spec.fg);
|
|
33
|
-
|
|
34
|
+
// A theme is a layer the reader chose, not one they wrote: the file to edit
|
|
35
|
+
// differs, so the two get their own answer even when both set one element.
|
|
36
|
+
const source = overrides.tokens.has(token) ? 'override'
|
|
37
|
+
: themed?.[token] !== undefined ? 'theme'
|
|
38
|
+
: named ? 'palette' : 'default';
|
|
34
39
|
return { text: fields.length === 0 ? 'plain' : fields.join(' '), source };
|
|
35
40
|
}
|
|
36
41
|
/** Where the reader edits the section; the home is a variable, not a fixed path. */
|
|
@@ -39,11 +44,19 @@ const SETTINGS_HINT = 'edit $DSH_HOME/settings.yaml (default ~/.dsh/settings.yam
|
|
|
39
44
|
* The effective table, one line per element.
|
|
40
45
|
*
|
|
41
46
|
* The token name comes first because it is what the reader types into
|
|
42
|
-
* settings.yaml; the origin comes last because it is what explains the value
|
|
43
|
-
*
|
|
47
|
+
* settings.yaml; the origin comes last because it is what explains the value when
|
|
48
|
+
* the value is not what they expected. The footer names the themes that exist
|
|
49
|
+
* rather than the ones this build was compiled with, because the file a reader
|
|
50
|
+
* saved a second ago is the one they need to hear about.
|
|
44
51
|
*/
|
|
45
|
-
export function renderThemeTable(overrides) {
|
|
46
|
-
const
|
|
52
|
+
export function renderThemeTable(overrides, library) {
|
|
53
|
+
const themed = themeLayer(overrides);
|
|
54
|
+
const chosen = overrides.theme;
|
|
55
|
+
// The name is in the heading rather than the footer because a reader who opened
|
|
56
|
+
// this to find out why a shade moved needs it before the table; it is missing
|
|
57
|
+
// only when nothing answered to the name the document carries.
|
|
58
|
+
const heading = chosen === undefined ? 'theme' : `theme · ${chosen.name}`;
|
|
59
|
+
const lines = [`${heading} · ${TUI_TOKENS.length} elements`, ''];
|
|
47
60
|
let group = '';
|
|
48
61
|
for (const token of TUI_TOKENS) {
|
|
49
62
|
const head = token.split('.')[0] ?? token;
|
|
@@ -51,10 +64,17 @@ export function renderThemeTable(overrides) {
|
|
|
51
64
|
group = head;
|
|
52
65
|
lines.push(`${group}:`);
|
|
53
66
|
}
|
|
54
|
-
const { text, source } = describeToken(token, overrides);
|
|
67
|
+
const { text, source } = describeToken(token, overrides, themed);
|
|
55
68
|
lines.push(` ${token} = ${text} (${source})`);
|
|
56
69
|
}
|
|
57
70
|
lines.push('', `palette: ${Object.entries(overrides.palette).map(([name, value]) => `${name} ${value}`).join(' · ')}`);
|
|
71
|
+
const own = new Set(library.list().filter(theme => !theme.builtin).map(theme => theme.name));
|
|
72
|
+
const names = library.names().map(name => (own.has(name) ? `${name}*` : name));
|
|
73
|
+
lines.push('', `themes: ${names.join(' · ')} — /theme <name> applies one${own.size === 0 ? '' : ' (* yours)'}`);
|
|
74
|
+
// The hint carries the directory because it is the one fact a reader cannot
|
|
75
|
+
// guess: the package's own file is replaced on update, so the copy is the only
|
|
76
|
+
// editable one and it does not live beside the original.
|
|
77
|
+
lines.push(`export: /theme export <built-in> writes a copy into ${library.home} to edit`);
|
|
58
78
|
lines.push('', SETTINGS_HINT);
|
|
59
79
|
return lines;
|
|
60
80
|
}
|
package/lib/theme-command.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-command.js","sourceRoot":"","sources":["../src/theme-command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"theme-command.js","sourceRoot":"","sources":["../src/theme-command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAuB,MAAM,qBAAqB,CAAA;AACrE,OAAO,EACL,cAAc,EACd,aAAa,EACb,UAAU,GAKX,MAAM,mBAAmB,CAAA;AAK1B,iFAAiF;AACjF,SAAS,UAAU,CAAC,IAAgB,EAAE,OAA8C;IAClF,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAK,aAAmC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACpF,OAAO,OAAO,CAAC,IAAmB,CAAC,CAAA;IACrC,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAA;AACrB,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,aAAa,CACpB,KAAe,EACf,SAAyB,EACzB,MAA+B;IAE/B,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5D,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS;QAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;IAC9E,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS;QAAE,MAAM,CAAC,IAAI,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IACtF,KAAK,MAAM,SAAS,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAU,EAAE,CAAC;QAClF,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI;YAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACtD,CAAC;IACD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,EAAE;QAAE,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IACrG,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI;QAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC/C,MAAM,KAAK,GAAG,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAK,aAAmC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACnG,4EAA4E;IAC5E,2EAA2E;IAC3E,MAAM,MAAM,GAAW,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU;QAC7D,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO;YACvC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;IACnC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAA;AAC3E,CAAC;AAED,oFAAoF;AACpF,MAAM,aAAa,GAAG,wGAAwG,CAAA;AAE9H;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAyB,EAAE,OAAqB;IAC/E,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,CAAA;IACpC,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAA;IAC9B,gFAAgF;IAChF,8EAA8E;IAC9E,+DAA+D;IAC/D,MAAM,OAAO,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,MAAM,CAAC,IAAI,EAAE,CAAA;IACzE,MAAM,KAAK,GAAG,CAAC,GAAG,OAAO,MAAM,UAAU,CAAC,MAAM,WAAW,EAAE,EAAE,CAAC,CAAA;IAChE,IAAI,KAAK,GAAG,EAAE,CAAA;IACd,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAA;QACzC,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACnB,KAAK,GAAG,IAAI,CAAA;YACZ,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,CAAA;QACzB,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,CAAA;QAChE,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,MAAM,IAAI,KAAK,MAAM,GAAG,CAAC,CAAA;IAChD,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,YAAY,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IACtH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IAC5F,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;IAC9E,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,WAAW,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,+BAA+B,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAA;IAC/G,4EAA4E;IAC5E,+EAA+E;IAC/E,yDAAyD;IACzD,KAAK,CAAC,IAAI,CAAC,uDAAuD,OAAO,CAAC,IAAI,UAAU,CAAC,CAAA;IACzF,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,aAAa,CAAC,CAAA;IAC7B,OAAO,KAAK,CAAA;AACd,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { PaletteName, ThemedSpecs } from './theme-tokens.ts';
|
|
2
|
+
/** The directory under `DSH_HOME` the reader's own themes live in. */
|
|
3
|
+
export declare const THEMES_DIR_NAME = "themes";
|
|
4
|
+
/**
|
|
5
|
+
* The theme the surface draws until the reader names another.
|
|
6
|
+
*
|
|
7
|
+
* A name rather than the table underneath, because the default look should be one
|
|
8
|
+
* a reader can read, list, and copy: the package's own theme takes its place in
|
|
9
|
+
* the list beside every other, so no default hides behind an absence.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_THEME = "deepseek-blue";
|
|
12
|
+
/**
|
|
13
|
+
* The largest theme file the surface will read.
|
|
14
|
+
*
|
|
15
|
+
* js-yaml bounds neither the size of a document nor how far an alias chain may
|
|
16
|
+
* expand it, so a file small enough to type can still be a bomb. A cap does not
|
|
17
|
+
* stop that on its own — the host parses settings.yaml with the same library, so a
|
|
18
|
+
* theme file adds no exposure that is not already there — but it keeps the crude
|
|
19
|
+
* case away from the parser.
|
|
20
|
+
*/
|
|
21
|
+
export declare const MAX_THEME_FILE_BYTES: number;
|
|
22
|
+
/** One theme, wherever it came from. */
|
|
23
|
+
export interface LoadedTheme {
|
|
24
|
+
/** The name it answers to, which is the file's stem. */
|
|
25
|
+
readonly name: string;
|
|
26
|
+
/** The file it was read from. */
|
|
27
|
+
readonly path: string;
|
|
28
|
+
/** Whether the package ships it, which is what a reader may not edit. */
|
|
29
|
+
readonly builtin: boolean;
|
|
30
|
+
/** The shades it moves, over the shipped palette. */
|
|
31
|
+
readonly palette: Readonly<Partial<Record<PaletteName, string>>>;
|
|
32
|
+
/** The elements it draws its own way. */
|
|
33
|
+
readonly tokens: ThemedSpecs;
|
|
34
|
+
}
|
|
35
|
+
/** Every theme the surface can draw, plus everything it could not read. */
|
|
36
|
+
export interface ThemeLibrary {
|
|
37
|
+
/** Where the reader's own themes live, whether or not the directory exists. */
|
|
38
|
+
readonly home: string;
|
|
39
|
+
/** Every theme: the built-ins, then the reader's, each in name order. */
|
|
40
|
+
list(): readonly LoadedTheme[];
|
|
41
|
+
/** Every name, in {@link ThemeLibrary.list} order. */
|
|
42
|
+
names(): readonly string[];
|
|
43
|
+
/** One theme by name, or undefined when nothing answers to it. */
|
|
44
|
+
get(name: string | undefined): LoadedTheme | undefined;
|
|
45
|
+
/** Everything that could not be read, each phrased for the reader. */
|
|
46
|
+
problems(): readonly string[];
|
|
47
|
+
}
|
|
48
|
+
/** What an export wrote, or why it wrote nothing. */
|
|
49
|
+
export type ExportOutcome = {
|
|
50
|
+
readonly ok: true;
|
|
51
|
+
readonly path: string;
|
|
52
|
+
readonly select: string;
|
|
53
|
+
} | {
|
|
54
|
+
readonly ok: false;
|
|
55
|
+
readonly problem: string;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* The themes directory inside the installed package.
|
|
59
|
+
*
|
|
60
|
+
* Resolved from this module's own URL so the answer survives installation:
|
|
61
|
+
* `lib/` and `themes/` are siblings in the tarball and `src/` and `themes/` are
|
|
62
|
+
* siblings in the checkout, so the same relative step lands in both.
|
|
63
|
+
*/
|
|
64
|
+
export declare function builtinThemesDir(): string;
|
|
65
|
+
/**
|
|
66
|
+
* The directory the reader's own themes live in.
|
|
67
|
+
*
|
|
68
|
+
* The harness home comes from the stash's helper rather than from another copy of
|
|
69
|
+
* the same precedence rule — "where is DSH_HOME" has more than one answer in this
|
|
70
|
+
* tree already, and a third would be one more to keep in step.
|
|
71
|
+
*/
|
|
72
|
+
export declare function themesHomeDir(env?: NodeJS.ProcessEnv, home?: string): string;
|
|
73
|
+
/** Create the reader's theme directory if it is missing; empty when it is there. */
|
|
74
|
+
export declare function ensureThemesHome(dir: string): readonly string[];
|
|
75
|
+
/** The names the package ships a file for, which are the ones an export can copy. */
|
|
76
|
+
export declare function builtinNames(library: ThemeLibrary): string[];
|
|
77
|
+
/**
|
|
78
|
+
* The name a copy of `name` takes, given the names already in use.
|
|
79
|
+
*
|
|
80
|
+
* Numbered rather than overwritten: a second export is a reader asking for a fresh
|
|
81
|
+
* copy of a built-in that has moved on since the first, and the file they have been
|
|
82
|
+
* editing is the one thing that must survive the request.
|
|
83
|
+
*/
|
|
84
|
+
export declare function exportName(name: string, taken: ReadonlySet<string>): string;
|
|
85
|
+
/**
|
|
86
|
+
* Write a built-in out as a theme of the reader's own.
|
|
87
|
+
*
|
|
88
|
+
* The bytes are copied rather than re-serialized, so the comments a built-in
|
|
89
|
+
* carries — which is where a port records why a shade is the shade it is — arrive
|
|
90
|
+
* with it. The one line added says where the copy came from, because a fork nobody
|
|
91
|
+
* can date is a fork nobody can rebase onto a later reference.
|
|
92
|
+
*/
|
|
93
|
+
export declare function exportTheme(library: ThemeLibrary, name: string): ExportOutcome;
|
|
94
|
+
/**
|
|
95
|
+
* Read every theme the surface can draw.
|
|
96
|
+
*
|
|
97
|
+
* One broken file never costs the others, and never throws: a reader is editing
|
|
98
|
+
* these by hand, so a save caught mid-write has to leave the screen exactly as it
|
|
99
|
+
* was and say so, rather than take the session down.
|
|
100
|
+
*/
|
|
101
|
+
export declare function loadThemes(homeDir: string, builtinDir: string): ThemeLibrary;
|
|
102
|
+
/**
|
|
103
|
+
* Call `onChange` after a burst of changes settles in a theme directory.
|
|
104
|
+
*
|
|
105
|
+
* Not persistent, because a theme is not a reason to keep a process alive: the
|
|
106
|
+
* terminal owns the session, and a watcher that outlived it would be a handle
|
|
107
|
+
* nobody closes.
|
|
108
|
+
*/
|
|
109
|
+
export declare function watchThemes(dir: string, onChange: () => void): () => void;
|
|
110
|
+
//# sourceMappingURL=theme-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-files.d.ts","sourceRoot":"","sources":["../src/theme-files.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,WAAW,EAAa,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE5E,sEAAsE;AACtE,eAAO,MAAM,eAAe,WAAW,CAAA;AAEvC;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,kBAAkB,CAAA;AAQ5C;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,QAAY,CAAA;AAK7C,wCAAwC;AACxC,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,iCAAiC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,qDAAqD;IACrD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;IAChE,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAC7B;AAED,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,yEAAyE;IACzE,IAAI,IAAI,SAAS,WAAW,EAAE,CAAA;IAC9B,sDAAsD;IACtD,KAAK,IAAI,SAAS,MAAM,EAAE,CAAA;IAC1B,kEAAkE;IAClE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAA;IACtD,sEAAsE;IACtE,QAAQ,IAAI,SAAS,MAAM,EAAE,CAAA;CAC9B;AAED,qDAAqD;AACrD,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAWpD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,EAAE,IAAI,GAAE,MAAkB,GAAG,MAAM,CAEpG;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAO/D;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,EAAE,CAI5D;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,MAAM,CAK3E;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CA4B9E;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,YAAY,CAgC5E;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CA0BzE"}
|