@sagmans/dsh-tui 0.3.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 +407 -53
- package/cordis.patch.yml +14 -0
- package/lib/agent/present.js +1 -1
- package/lib/agent/present.js.map +1 -1
- package/lib/agent/projections.d.ts +22 -6
- package/lib/agent/projections.d.ts.map +1 -1
- package/lib/agent/projections.js +21 -10
- package/lib/agent/projections.js.map +1 -1
- package/lib/agent/prompt-history.d.ts +89 -0
- package/lib/agent/prompt-history.d.ts.map +1 -0
- package/lib/agent/prompt-history.js +382 -0
- package/lib/agent/prompt-history.js.map +1 -0
- package/lib/agent/status.d.ts +6 -0
- package/lib/agent/status.d.ts.map +1 -1
- package/lib/agent/status.js +1 -0
- package/lib/agent/status.js.map +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/herdr/client.d.ts +57 -0
- package/lib/herdr/client.d.ts.map +1 -0
- package/lib/herdr/client.js +218 -0
- package/lib/herdr/client.js.map +1 -0
- package/lib/herdr/constants.d.ts +93 -0
- package/lib/herdr/constants.d.ts.map +1 -0
- package/lib/herdr/constants.js +79 -0
- package/lib/herdr/constants.js.map +1 -0
- package/lib/herdr/reporter.d.ts +60 -0
- package/lib/herdr/reporter.d.ts.map +1 -0
- package/lib/herdr/reporter.js +217 -0
- package/lib/herdr/reporter.js.map +1 -0
- package/lib/herdr/state.d.ts +57 -0
- package/lib/herdr/state.d.ts.map +1 -0
- package/lib/herdr/state.js +62 -0
- package/lib/herdr/state.js.map +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +700 -81
- 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 +60 -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/ghost.d.ts +46 -0
- package/lib/input/ghost.d.ts.map +1 -0
- package/lib/input/ghost.js +58 -0
- package/lib/input/ghost.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 +16 -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 +34 -1
- package/lib/input/submission.d.ts.map +1 -1
- package/lib/input/submission.js +33 -5
- 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/lock.d.ts +72 -0
- package/lib/stash/lock.d.ts.map +1 -0
- package/lib/stash/lock.js +374 -0
- package/lib/stash/lock.js.map +1 -0
- package/lib/stash/paths.d.ts +22 -0
- package/lib/stash/paths.d.ts.map +1 -0
- package/lib/stash/paths.js +84 -0
- package/lib/stash/paths.js.map +1 -0
- package/lib/stash/private-fs.d.ts +61 -0
- package/lib/stash/private-fs.d.ts.map +1 -0
- package/lib/stash/private-fs.js +379 -0
- package/lib/stash/private-fs.js.map +1 -0
- package/lib/stash/schema.d.ts +56 -0
- package/lib/stash/schema.d.ts.map +1 -0
- package/lib/stash/schema.js +108 -0
- package/lib/stash/schema.js.map +1 -0
- package/lib/stash/store.d.ts +92 -0
- package/lib/stash/store.d.ts.map +1 -0
- package/lib/stash/store.js +262 -0
- package/lib/stash/store.js.map +1 -0
- package/lib/stash.d.ts +122 -0
- package/lib/stash.d.ts.map +1 -0
- package/lib/stash.js +353 -0
- package/lib/stash.js.map +1 -0
- 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 +72 -10
- package/lib/theme-settings.d.ts.map +1 -1
- package/lib/theme-settings.js +162 -45
- 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 +104 -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/todo-guard.d.ts +116 -0
- package/lib/todo-guard.d.ts.map +1 -0
- package/lib/todo-guard.js +259 -0
- package/lib/todo-guard.js.map +1 -0
- 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 +41 -1
- package/lib/ui/editor.d.ts.map +1 -1
- package/lib/ui/editor.js +100 -4
- 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/history-picker.d.ts +15 -0
- package/lib/ui/history-picker.d.ts.map +1 -0
- package/lib/ui/history-picker.js +26 -0
- package/lib/ui/history-picker.js.map +1 -0
- 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 +50 -2
- package/lib/ui/picker.d.ts.map +1 -1
- package/lib/ui/picker.js +66 -7
- package/lib/ui/picker.js.map +1 -1
- package/lib/ui/prompt.d.ts +12 -2
- package/lib/ui/prompt.d.ts.map +1 -1
- package/lib/ui/prompt.js +25 -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 +43 -0
- package/lib/ui/stash-picker.d.ts.map +1 -0
- package/lib/ui/stash-picker.js +78 -0
- package/lib/ui/stash-picker.js.map +1 -0
- package/lib/ui/status.d.ts +2 -0
- package/lib/ui/status.d.ts.map +1 -1
- package/lib/ui/status.js +25 -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/lib/work.d.ts +3 -1
- package/lib/work.d.ts.map +1 -1
- package/lib/work.js +9 -1
- package/lib/work.js.map +1 -1
- package/package.json +7 -1
- package/themes/deepseek-blue.yaml +183 -0
- package/themes/violet-orbit.yaml +178 -0
package/lib/ui/dock.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {} from '@earendil-works/pi-tui';
|
|
1
|
+
import { visibleWidth } from '@earendil-works/pi-tui';
|
|
2
2
|
import { DOCK_JOB_LIMIT, describeJob, isLive } from "../jobs.js";
|
|
3
3
|
import { DOCK_SUBAGENT_LIMIT, describeSubagent } from "../subagents.js";
|
|
4
|
-
import { displayText } from "../text.js";
|
|
5
4
|
/** Todo rows the dock keeps on screen; the rest become a count. */
|
|
6
5
|
export const DOCK_TODO_LIMIT = 4;
|
|
7
6
|
/** The mark that introduces a dock section, so a literal never lives in a template. */
|
|
@@ -72,7 +71,8 @@ export class WorkDock {
|
|
|
72
71
|
const token = TODO_TOKENS[todo.status];
|
|
73
72
|
if (!this.theme.visible(token))
|
|
74
73
|
continue;
|
|
75
|
-
|
|
74
|
+
const lead = ` ${TODO_GLYPHS[todo.status]} `;
|
|
75
|
+
lines.push(this.theme.cut(this.theme.rich(`${lead}${todo.content}`, { token, column: visibleWidth(lead) }), width, '…'));
|
|
76
76
|
}
|
|
77
77
|
if (ordered.length > DOCK_TODO_LIMIT && this.theme.visible('dock.todos.overflow')) {
|
|
78
78
|
lines.push(this.theme.style('dock.todos.overflow', this.theme.cut(` … ${ordered.length - DOCK_TODO_LIMIT} more`, width, '…')));
|
|
@@ -91,7 +91,8 @@ export class WorkDock {
|
|
|
91
91
|
for (const run of running.slice(0, DOCK_SUBAGENT_LIMIT)) {
|
|
92
92
|
if (!this.theme.visible('dock.subagents.running'))
|
|
93
93
|
continue;
|
|
94
|
-
|
|
94
|
+
const lead = ` ${RUNNING_MARK} `;
|
|
95
|
+
lines.push(this.theme.cut(this.theme.rich(`${lead}${describeSubagent(run, now)}`, { token: 'dock.subagents.running', column: visibleWidth(lead) }), width, '…'));
|
|
95
96
|
}
|
|
96
97
|
if (running.length > DOCK_SUBAGENT_LIMIT && this.theme.visible('dock.subagents.overflow')) {
|
|
97
98
|
lines.push(this.theme.style('dock.subagents.overflow', this.theme.cut(` … ${running.length - DOCK_SUBAGENT_LIMIT} more`, width, '…')));
|
|
@@ -112,7 +113,8 @@ export class WorkDock {
|
|
|
112
113
|
for (const job of ordered.slice(0, DOCK_JOB_LIMIT)) {
|
|
113
114
|
if (!this.theme.visible('dock.jobs.running'))
|
|
114
115
|
continue;
|
|
115
|
-
|
|
116
|
+
const lead = ` ${RUNNING_MARK} `;
|
|
117
|
+
lines.push(this.theme.cut(this.theme.rich(`${lead}${describeJob(job, now)}`, { token: 'dock.jobs.running', column: visibleWidth(lead) }), width, '…'));
|
|
116
118
|
}
|
|
117
119
|
if (ordered.length > DOCK_JOB_LIMIT && this.theme.visible('dock.jobs.overflow')) {
|
|
118
120
|
lines.push(this.theme.style('dock.jobs.overflow', this.theme.cut(` … ${ordered.length - DOCK_JOB_LIMIT} more`, width, '…')));
|
|
@@ -130,7 +132,8 @@ export class WorkDock {
|
|
|
130
132
|
// The row itself decides where a long objective ends, so the reader
|
|
131
133
|
// always sees that something was left out.
|
|
132
134
|
const objective = state.goal.objective.replace(/\s+/gu, ' ');
|
|
133
|
-
|
|
135
|
+
const lead = `${GOAL_MARK} goal ${rounds} · `;
|
|
136
|
+
lines.push(this.theme.cut(this.theme.rich(`${lead}${objective}`, { token: 'dock.goal', column: visibleWidth(lead) }), width, '…'));
|
|
134
137
|
}
|
|
135
138
|
if (state.planMode && this.theme.visible('dock.planMode')) {
|
|
136
139
|
lines.push(this.theme.style('dock.planMode', this.theme.cut(`${PLAN_MODE_MARK} plan mode · answer the plan before edits happen`, width, '…')));
|
package/lib/ui/dock.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dock.js","sourceRoot":"","sources":["../../src/ui/dock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"dock.js","sourceRoot":"","sources":["../../src/ui/dock.ts"],"names":[],"mappings":"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"}
|
package/lib/ui/editor.d.ts
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
import { Editor, type EditorTheme, type TUI, type TuiMouseEvent, type TuiMouseEventResult } from '@earendil-works/pi-tui';
|
|
2
2
|
import { type Keymap } from '../input/actions.ts';
|
|
3
|
+
import { type EditorCursor } from '../input/ghost.ts';
|
|
4
|
+
/** Which run of a ghost is being drawn: the cursor cell, or the text after it. */
|
|
5
|
+
export type GhostCell = 'cursor' | 'rest';
|
|
6
|
+
/** What the bar knows when it asks for a suggestion. */
|
|
7
|
+
export interface GhostRequest {
|
|
8
|
+
readonly text: string;
|
|
9
|
+
readonly lines: readonly string[];
|
|
10
|
+
readonly cursor: EditorCursor;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The recorded-prompt suggestion the bar offers, and how to draw it.
|
|
14
|
+
*
|
|
15
|
+
* Kept as a collaborator rather than built in: the editor owns where the text
|
|
16
|
+
* goes, while the surface owns where the entries come from and which shade they
|
|
17
|
+
* are drawn in, so neither has to know the other's world.
|
|
18
|
+
*/
|
|
19
|
+
export interface GhostBrush {
|
|
20
|
+
/** Whether the affordance may draw at all; colour and settings decide this. */
|
|
21
|
+
enabled(): boolean;
|
|
22
|
+
/** The suffix to offer after the typed text, or undefined for none. */
|
|
23
|
+
suggestion(input: GhostRequest): string | undefined;
|
|
24
|
+
/** Paint one run of the suffix; '' leaves the run undrawn. */
|
|
25
|
+
paint(text: string, cell: GhostCell): string;
|
|
26
|
+
}
|
|
3
27
|
/**
|
|
4
28
|
* The input bar drawn as a box, with its completion menu above it.
|
|
5
29
|
*
|
|
@@ -10,13 +34,14 @@ import { type Keymap } from '../input/actions.ts';
|
|
|
10
34
|
*/
|
|
11
35
|
export declare class BoxedEditor extends Editor {
|
|
12
36
|
private readonly keymap;
|
|
37
|
+
private readonly ghost?;
|
|
13
38
|
/** Rows the menu took in the last render; a click there belongs to the list. */
|
|
14
39
|
private menuRows;
|
|
15
40
|
/** Rows between the rules in the last render; how the base editor counts its own. */
|
|
16
41
|
private textRows;
|
|
17
42
|
/** Whether the last render drew a frame, which is what a click is mapped through. */
|
|
18
43
|
private boxed;
|
|
19
|
-
constructor(tui: TUI, theme: EditorTheme, keymap?: () => Keymap);
|
|
44
|
+
constructor(tui: TUI, theme: EditorTheme, keymap?: () => Keymap, ghost?: GhostBrush | undefined);
|
|
20
45
|
/**
|
|
21
46
|
* Read the two presses the base class cannot place on its own.
|
|
22
47
|
*
|
|
@@ -36,6 +61,21 @@ export declare class BoxedEditor extends Editor {
|
|
|
36
61
|
* what it collects without hiding the box the reader types inside.
|
|
37
62
|
*/
|
|
38
63
|
protected decorateText(row: string): string;
|
|
64
|
+
/** The suggestion to draw this paint, or undefined when the brush offers none. */
|
|
65
|
+
private currentGhostSuffix;
|
|
66
|
+
/**
|
|
67
|
+
* Replace the end-of-text cursor cell with the offered suffix.
|
|
68
|
+
*
|
|
69
|
+
* The base draws the cursor as one reverse-video cell and pads the rest of the
|
|
70
|
+
* row; the suffix takes that cell plus the padding after it, so the row keeps
|
|
71
|
+
* exactly its width and the cursor stays where the reader is typing.
|
|
72
|
+
*/
|
|
73
|
+
private ghostRow;
|
|
74
|
+
/**
|
|
75
|
+
* Take a ghost-accepting key before the base sees it, so the key returns to
|
|
76
|
+
* its own meaning the moment nothing is offered.
|
|
77
|
+
*/
|
|
78
|
+
private acceptGhost;
|
|
39
79
|
render(width: number): string[];
|
|
40
80
|
/**
|
|
41
81
|
* Map a click back through the frame and the lifted menu.
|
package/lib/ui/editor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/ui/editor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/ui/editor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EAMN,KAAK,WAAW,EAChB,KAAK,GAAG,EACR,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACzB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAA4B,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC3E,OAAO,EAAsE,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAmDzH,kFAAkF;AAClF,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEzC,wDAAwD;AACxD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAA;CAC9B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,+EAA+E;IAC/E,OAAO,IAAI,OAAO,CAAA;IAClB,uEAAuE;IACvE,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAAA;IACnD,8DAA8D;IAC9D,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAAA;CAC7C;AAED;;;;;;;GAOG;AACH,qBAAa,WAAY,SAAQ,MAAM;IAWnC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IAXzB,gFAAgF;IAChF,OAAO,CAAC,QAAQ,CAAI;IACpB,qFAAqF;IACrF,OAAO,CAAC,QAAQ,CAAI;IACpB,qFAAqF;IACrF,OAAO,CAAC,KAAK,CAAQ;gBAGnB,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,WAAW,EACD,MAAM,GAAE,MAAM,MAAsB,EACpC,KAAK,CAAC,EAAE,UAAU,YAAA;IAKrC;;;;;;;;OAQG;IACM,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAkCxC,0EAA0E;cACvD,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM;IAIrF,kFAAkF;IAClF,OAAO,CAAC,IAAI;IAIZ;;;OAGG;IACH,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAI3C,kFAAkF;IAClF,OAAO,CAAC,kBAAkB;IAmB1B;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ;IA0BhB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAgBV,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IA4BxC;;;;;;;;OAQG;IACM,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,mBAAmB,GAAG,SAAS;CAQ5E"}
|
package/lib/ui/editor.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { Editor, isKittyProtocolActive, matchesKey, stripTerminalSequences, } from '@earendil-works/pi-tui';
|
|
1
|
+
import { Editor, getKeybindings, isKittyProtocolActive, matchesKey, stripTerminalSequences, visibleWidth, } from '@earendil-works/pi-tui';
|
|
2
2
|
import { ENTER_KEY, defaultKeymap } from "../input/actions.js";
|
|
3
|
+
import { ghostDisplayLine, ghostGraphemes, isCursorAtTextEnd, nextGhostWord } from "../input/ghost.js";
|
|
3
4
|
import { promptKeys } from "../input/keymap.js";
|
|
5
|
+
import { renderTerminalText } from "../terminal-text.js";
|
|
4
6
|
import { FRAME_COLUMNS, FRAME_GLYPHS, MIN_BOX_WIDTH, PADDING_X } from "./frame.js";
|
|
5
7
|
/**
|
|
6
8
|
* Marks the rule that closes the input while one render is in flight.
|
|
@@ -33,6 +35,16 @@ const LEGACY_ALT_ENTER = '\u001b\r';
|
|
|
33
35
|
*/
|
|
34
36
|
const KITTY_ALT_ENTER = '\u001b[13;3u';
|
|
35
37
|
const KITTY_CTRL_J = '\u001b[106;5u';
|
|
38
|
+
/**
|
|
39
|
+
* The cell the base editor draws for a cursor parked past the last character.
|
|
40
|
+
*
|
|
41
|
+
* Ghost text takes that cell over: the base offers no seam for "style the text
|
|
42
|
+
* after the cursor", so one paint pass finds the cell it drew and replaces the
|
|
43
|
+
* padding after it. The cell looks the same when the cursor sits over a typed
|
|
44
|
+
* space, which is why a caller also confirms the cursor is past the last
|
|
45
|
+
* character before treating the sequence as padding.
|
|
46
|
+
*/
|
|
47
|
+
const CURSOR_AT_END = '\u001b[7m \u001b[0m';
|
|
36
48
|
/**
|
|
37
49
|
* The input bar drawn as a box, with its completion menu above it.
|
|
38
50
|
*
|
|
@@ -43,15 +55,17 @@ const KITTY_CTRL_J = '\u001b[106;5u';
|
|
|
43
55
|
*/
|
|
44
56
|
export class BoxedEditor extends Editor {
|
|
45
57
|
keymap;
|
|
58
|
+
ghost;
|
|
46
59
|
/** Rows the menu took in the last render; a click there belongs to the list. */
|
|
47
60
|
menuRows = 0;
|
|
48
61
|
/** Rows between the rules in the last render; how the base editor counts its own. */
|
|
49
62
|
textRows = 0;
|
|
50
63
|
/** Whether the last render drew a frame, which is what a click is mapped through. */
|
|
51
64
|
boxed = false;
|
|
52
|
-
constructor(tui, theme, keymap = defaultKeymap) {
|
|
65
|
+
constructor(tui, theme, keymap = defaultKeymap, ghost) {
|
|
53
66
|
super(tui, theme, { paddingX: PADDING_X });
|
|
54
67
|
this.keymap = keymap;
|
|
68
|
+
this.ghost = ghost;
|
|
55
69
|
}
|
|
56
70
|
/**
|
|
57
71
|
* Read the two presses the base class cannot place on its own.
|
|
@@ -67,6 +81,8 @@ export class BoxedEditor extends Editor {
|
|
|
67
81
|
super.handleInput(data);
|
|
68
82
|
return;
|
|
69
83
|
}
|
|
84
|
+
if (this.acceptGhost(data))
|
|
85
|
+
return;
|
|
70
86
|
const keys = promptKeys(this.keymap());
|
|
71
87
|
// A bare line feed is a line break in the base class whatever the map says,
|
|
72
88
|
// so a reader who moved the line break off ctrl+j and sends with it would
|
|
@@ -109,14 +125,94 @@ export class BoxedEditor extends Editor {
|
|
|
109
125
|
decorateText(row) {
|
|
110
126
|
return row;
|
|
111
127
|
}
|
|
128
|
+
/** The suggestion to draw this paint, or undefined when the brush offers none. */
|
|
129
|
+
currentGhostSuffix() {
|
|
130
|
+
const brush = this.ghost;
|
|
131
|
+
if (brush === undefined || !brush.enabled())
|
|
132
|
+
return undefined;
|
|
133
|
+
const lines = this.getLines();
|
|
134
|
+
const cursor = this.getCursor();
|
|
135
|
+
// A cursor parked over a typed space draws the same cell as one at the very
|
|
136
|
+
// end, so the position has to be confirmed before a brush is asked at all.
|
|
137
|
+
if (!isCursorAtTextEnd({ lines, cursor }))
|
|
138
|
+
return undefined;
|
|
139
|
+
// The brush is a collaborator this class does not own, and its answer is
|
|
140
|
+
// both drawn and inserted: a control sequence would reach the terminal or
|
|
141
|
+
// the bar itself. The store refuses them too, so this only has to hold for
|
|
142
|
+
// any other brush. The expanded text is what was actually written; a large
|
|
143
|
+
// paste is stored as a marker and would otherwise match nothing.
|
|
144
|
+
const suffix = brush.suggestion({ text: this.getExpandedText(), lines, cursor });
|
|
145
|
+
// The bar paints this text itself, so it is drawn without colour: a sequence
|
|
146
|
+
// the brush offered must not escape the face the bar is drawing it in.
|
|
147
|
+
return suffix === undefined ? undefined : renderTerminalText(suffix, { color: 'none' });
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Replace the end-of-text cursor cell with the offered suffix.
|
|
151
|
+
*
|
|
152
|
+
* The base draws the cursor as one reverse-video cell and pads the rest of the
|
|
153
|
+
* row; the suffix takes that cell plus the padding after it, so the row keeps
|
|
154
|
+
* exactly its width and the cursor stays where the reader is typing.
|
|
155
|
+
*/
|
|
156
|
+
ghostRow(row, suffix) {
|
|
157
|
+
const brush = this.ghost;
|
|
158
|
+
if (brush === undefined || suffix === undefined)
|
|
159
|
+
return row;
|
|
160
|
+
const cursorAt = row.indexOf(CURSOR_AT_END);
|
|
161
|
+
if (cursorAt < 0)
|
|
162
|
+
return row;
|
|
163
|
+
const before = row.slice(0, cursorAt);
|
|
164
|
+
const pad = visibleWidth(row.slice(cursorAt + CURSOR_AT_END.length));
|
|
165
|
+
// The freed cursor cell is one more column the suffix may fill.
|
|
166
|
+
const room = pad + 1;
|
|
167
|
+
// A width-aware cut can split a wide grapheme or return the escape that
|
|
168
|
+
// closed a style, so the fit is measured one grapheme at a time; when even
|
|
169
|
+
// the first one is too wide, the row keeps the cursor the base drew.
|
|
170
|
+
let drawn = '';
|
|
171
|
+
let used = 0;
|
|
172
|
+
for (const grapheme of ghostGraphemes(ghostDisplayLine(suffix))) {
|
|
173
|
+
const width = visibleWidth(grapheme);
|
|
174
|
+
if (used + width > room)
|
|
175
|
+
break;
|
|
176
|
+
drawn += grapheme;
|
|
177
|
+
used += width;
|
|
178
|
+
}
|
|
179
|
+
if (drawn === '')
|
|
180
|
+
return row;
|
|
181
|
+
const [first = '', ...rest] = ghostGraphemes(drawn);
|
|
182
|
+
const spaces = ' '.repeat(Math.max(0, room - used));
|
|
183
|
+
return before + brush.paint(first, 'cursor') + brush.paint(rest.join(''), 'rest') + spaces;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Take a ghost-accepting key before the base sees it, so the key returns to
|
|
187
|
+
* its own meaning the moment nothing is offered.
|
|
188
|
+
*/
|
|
189
|
+
acceptGhost(data) {
|
|
190
|
+
const suffix = this.currentGhostSuffix();
|
|
191
|
+
if (suffix === undefined)
|
|
192
|
+
return false;
|
|
193
|
+
if (getKeybindings().matches(data, 'tui.editor.cursorWordRight')) {
|
|
194
|
+
const word = nextGhostWord(suffix);
|
|
195
|
+
if (word === undefined)
|
|
196
|
+
return false;
|
|
197
|
+
this.insertTextAtCursor(word);
|
|
198
|
+
this.tui.requestRender();
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
if (!matchesKey(data, 'ctrl+e'))
|
|
202
|
+
return false;
|
|
203
|
+
this.insertTextAtCursor(suffix);
|
|
204
|
+
this.tui.requestRender();
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
112
207
|
render(width) {
|
|
113
208
|
const side = this.borderColor(FRAME_GLYPHS.side);
|
|
114
209
|
// A frame narrower than its own furniture would eat the text it exists to
|
|
115
210
|
// hold, and a hidden border token asks for no frame at all: both cases keep
|
|
116
211
|
// the plain rules rather than reserve columns for what nobody can see.
|
|
212
|
+
const ghost = this.disableSubmit ? undefined : this.currentGhostSuffix();
|
|
117
213
|
if (width < MIN_BOX_WIDTH || side === '') {
|
|
118
214
|
this.boxed = false;
|
|
119
|
-
return super.render(width).map(row => this.decorateText(row));
|
|
215
|
+
return super.render(width).map(row => this.decorateText(this.ghostRow(row, ghost)));
|
|
120
216
|
}
|
|
121
217
|
const rows = super.render(width - FRAME_COLUMNS);
|
|
122
218
|
const closing = rows.findIndex(row => row.includes(CLOSING_TAG));
|
|
@@ -133,7 +229,7 @@ export class BoxedEditor extends Editor {
|
|
|
133
229
|
const lines = menu.map(row => row + ' '.repeat(FRAME_COLUMNS));
|
|
134
230
|
lines.push(this.edge(FRAME_GLYPHS.topLeft, FRAME_GLYPHS.topRight, rows[0] ?? ''));
|
|
135
231
|
for (const row of text)
|
|
136
|
-
lines.push(`${side}${this.decorateText(row)}${side}`);
|
|
232
|
+
lines.push(`${side}${this.decorateText(this.ghostRow(row, ghost))}${side}`);
|
|
137
233
|
lines.push(this.edge(FRAME_GLYPHS.bottomLeft, FRAME_GLYPHS.bottomRight, rows[closing].replace(CLOSING_TAG, '')));
|
|
138
234
|
return lines;
|
|
139
235
|
}
|
package/lib/ui/editor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.js","sourceRoot":"","sources":["../../src/ui/editor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,qBAAqB,EACrB,UAAU,EACV,sBAAsB,
|
|
1
|
+
{"version":3,"file":"editor.js","sourceRoot":"","sources":["../../src/ui/editor.ts"],"names":[],"mappings":"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"}
|
package/lib/ui/frame.d.ts
CHANGED
|
@@ -43,12 +43,23 @@ export interface FrameFaces {
|
|
|
43
43
|
/** Whether a bar has the width, and the visible border, to close a frame. */
|
|
44
44
|
export declare function canFrame(width: number, borderVisible: boolean): boolean;
|
|
45
45
|
/**
|
|
46
|
-
* One block of
|
|
47
|
-
* closed into it when the frame can be drawn.
|
|
46
|
+
* One block of already-rendered rows as a bar draws it: padded to the frame's
|
|
47
|
+
* own text width, and closed into it when the frame can be drawn.
|
|
48
48
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
49
|
+
* Markdown lays itself out to the width it is given, so its rows may not be
|
|
50
|
+
* wrapped again here: a second pass would break a fence or a table the markdown
|
|
51
|
+
* just drew. A block with a limit is a preview, and the rows it drops are
|
|
52
|
+
* counted on the closing rule: a reader who cannot see the whole text still has
|
|
53
|
+
* to see that it continues.
|
|
54
|
+
*/
|
|
55
|
+
export declare function frameLines(lines: readonly string[], width: number, faces: FrameFaces, limit?: number): string[];
|
|
56
|
+
/**
|
|
57
|
+
* One block of plain text as a bar draws it.
|
|
58
|
+
*
|
|
59
|
+
* A block without a limit is the prompt itself, which is never cut; the text is
|
|
60
|
+
* wrapped here because nothing upstream knows the frame's own width. The text is
|
|
61
|
+
* drawn without colour: a frame holds the surface's own drafts, whose styling is
|
|
62
|
+
* the frame's, and a sequence that reached one would fight the frame that owns it.
|
|
52
63
|
*/
|
|
53
64
|
export declare function frameText(text: string, width: number, faces: FrameFaces, limit?: number): string[];
|
|
54
65
|
//# sourceMappingURL=frame.d.ts.map
|
package/lib/ui/frame.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../src/ui/frame.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY;;;;;;CAAyF,CAAA;AAElH,kFAAkF;AAClF,eAAO,MAAM,aAAa,IAAI,CAAA;AAC9B,mFAAmF;AACnF,eAAO,MAAM,SAAS,IAAI,CAAA;AAC1B,6EAA6E;AAC7E,eAAO,MAAM,aAAa,QAAoC,CAAA;AAE9D,0FAA0F;AAC1F,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,kFAAkF;AAClF,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../src/ui/frame.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY;;;;;;CAAyF,CAAA;AAElH,kFAAkF;AAClF,eAAO,MAAM,aAAa,IAAI,CAAA;AAC9B,mFAAmF;AACnF,eAAO,MAAM,SAAS,IAAI,CAAA;AAC1B,6EAA6E;AAC7E,eAAO,MAAM,aAAa,QAAoC,CAAA;AAE9D,0FAA0F;AAC1F,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,kFAAkF;AAClF,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAQhE;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAgBxE;AAED,0EAA0E;AAC1E,MAAM,WAAW,UAAU;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACvC,kDAAkD;IAClD,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACzC,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CACzB;AAED,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,GAAG,OAAO,CAEvE;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,SAA2B,GAAG,MAAM,EAAE,CAWjI;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,SAA2B,GAAG,MAAM,EAAE,CAIpH"}
|
package/lib/ui/frame.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { visibleWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';
|
|
2
|
-
import {
|
|
1
|
+
import { truncateToWidth, visibleWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';
|
|
2
|
+
import { renderTerminalText } from "../terminal-text.js";
|
|
3
3
|
/**
|
|
4
4
|
* The frame every prompt is closed into.
|
|
5
5
|
*
|
|
@@ -21,8 +21,13 @@ export function textWidth(innerWidth) {
|
|
|
21
21
|
}
|
|
22
22
|
/** One text row of a bar: the air, the text, and the rest of the inside width. */
|
|
23
23
|
export function textRow(text, innerWidth) {
|
|
24
|
-
const
|
|
25
|
-
|
|
24
|
+
const width = Math.max(0, innerWidth);
|
|
25
|
+
const room = Math.max(0, textWidth(width) - visibleWidth(text));
|
|
26
|
+
const row = `${' '.repeat(PADDING_X)}${text}${' '.repeat(room)}${' '.repeat(PADDING_X)}`;
|
|
27
|
+
// A bar can be narrower than its own padding. The frame's columns are the only
|
|
28
|
+
// thing allowed to own the edge, so a row that would overflow is cut here,
|
|
29
|
+
// where the bar can still count what it lost, instead of by the terminal.
|
|
30
|
+
return visibleWidth(row) <= width ? row : truncateToWidth(row, width, '');
|
|
26
31
|
}
|
|
27
32
|
/**
|
|
28
33
|
* The rule that closes a bar, naming what the bar could not fit.
|
|
@@ -55,17 +60,18 @@ export function canFrame(width, borderVisible) {
|
|
|
55
60
|
return borderVisible && width >= MIN_BOX_WIDTH;
|
|
56
61
|
}
|
|
57
62
|
/**
|
|
58
|
-
* One block of
|
|
59
|
-
* closed into it when the frame can be drawn.
|
|
63
|
+
* One block of already-rendered rows as a bar draws it: padded to the frame's
|
|
64
|
+
* own text width, and closed into it when the frame can be drawn.
|
|
60
65
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
66
|
+
* Markdown lays itself out to the width it is given, so its rows may not be
|
|
67
|
+
* wrapped again here: a second pass would break a fence or a table the markdown
|
|
68
|
+
* just drew. A block with a limit is a preview, and the rows it drops are
|
|
69
|
+
* counted on the closing rule: a reader who cannot see the whole text still has
|
|
70
|
+
* to see that it continues.
|
|
64
71
|
*/
|
|
65
|
-
export function
|
|
72
|
+
export function frameLines(lines, width, faces, limit = Number.POSITIVE_INFINITY) {
|
|
66
73
|
const inside = faces.framed ? width - FRAME_COLUMNS : width;
|
|
67
|
-
const
|
|
68
|
-
const body = wrapped.slice(0, Math.max(0, limit));
|
|
74
|
+
const body = lines.slice(0, Math.max(0, limit));
|
|
69
75
|
const rows = body.map(line => textRow(faces.text(line), inside));
|
|
70
76
|
if (!faces.framed)
|
|
71
77
|
return rows;
|
|
@@ -73,7 +79,20 @@ export function frameText(text, width, faces, limit = Number.POSITIVE_INFINITY)
|
|
|
73
79
|
return [
|
|
74
80
|
faces.border(`${FRAME_GLYPHS.topLeft}${frameRule(inside, 0)}${FRAME_GLYPHS.topRight}`),
|
|
75
81
|
...rows.map(row => `${side}${row}${side}`),
|
|
76
|
-
faces.border(`${FRAME_GLYPHS.bottomLeft}${frameRule(inside,
|
|
82
|
+
faces.border(`${FRAME_GLYPHS.bottomLeft}${frameRule(inside, lines.length - body.length)}${FRAME_GLYPHS.bottomRight}`),
|
|
77
83
|
];
|
|
78
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* One block of plain text as a bar draws it.
|
|
87
|
+
*
|
|
88
|
+
* A block without a limit is the prompt itself, which is never cut; the text is
|
|
89
|
+
* wrapped here because nothing upstream knows the frame's own width. The text is
|
|
90
|
+
* drawn without colour: a frame holds the surface's own drafts, whose styling is
|
|
91
|
+
* the frame's, and a sequence that reached one would fight the frame that owns it.
|
|
92
|
+
*/
|
|
93
|
+
export function frameText(text, width, faces, limit = Number.POSITIVE_INFINITY) {
|
|
94
|
+
const inside = faces.framed ? width - FRAME_COLUMNS : width;
|
|
95
|
+
const drawn = renderTerminalText(text, { color: 'none' });
|
|
96
|
+
return frameLines(wrapTextWithAnsi(drawn, textWidth(inside)), width, faces, limit);
|
|
97
|
+
}
|
|
79
98
|
//# sourceMappingURL=frame.js.map
|
package/lib/ui/frame.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame.js","sourceRoot":"","sources":["../../src/ui/frame.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"frame.js","sourceRoot":"","sources":["../../src/ui/frame.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PromptEntry } from '../agent/prompt-history.ts';
|
|
2
|
+
import { type Keymap } from '../input/actions.ts';
|
|
3
|
+
import { ListPicker } from './picker.ts';
|
|
4
|
+
/**
|
|
5
|
+
* The reverse search over recorded prompts.
|
|
6
|
+
*
|
|
7
|
+
* A prompt is taken whole: the reader is looking for something they already
|
|
8
|
+
* wrote, so the row and the value inserted are the same text. The draft seeds
|
|
9
|
+
* the filter, which turns reverse search into "keep going from here" instead of
|
|
10
|
+
* starting the list over.
|
|
11
|
+
*/
|
|
12
|
+
export declare class HistoryPicker extends ListPicker<PromptEntry> {
|
|
13
|
+
constructor(entries: () => readonly PromptEntry[], draft: string, keys: () => Keymap);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=history-picker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-picker.d.ts","sourceRoot":"","sources":["../../src/ui/history-picker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAC7D,OAAO,EAAsB,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACrE,OAAO,EAAE,UAAU,EAAc,MAAM,aAAa,CAAA;AAKpD;;;;;;;GAOG;AACH,qBAAa,aAAc,SAAQ,UAAU,CAAC,WAAW,CAAC;gBAC5C,OAAO,EAAE,MAAM,SAAS,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,MAAM;CAoBrF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { hintKeys, moveHint } from "../input/actions.js";
|
|
2
|
+
import { ListPicker, singleLine } from "./picker.js";
|
|
3
|
+
/** A prompt used exactly once reads as ordinary, so the count only starts at a repeat. */
|
|
4
|
+
const REUSED = 2;
|
|
5
|
+
/**
|
|
6
|
+
* The reverse search over recorded prompts.
|
|
7
|
+
*
|
|
8
|
+
* A prompt is taken whole: the reader is looking for something they already
|
|
9
|
+
* wrote, so the row and the value inserted are the same text. The draft seeds
|
|
10
|
+
* the filter, which turns reverse search into "keep going from here" instead of
|
|
11
|
+
* starting the list over.
|
|
12
|
+
*/
|
|
13
|
+
export class HistoryPicker extends ListPicker {
|
|
14
|
+
constructor(entries, draft, keys) {
|
|
15
|
+
super(entries, () => 'prompt history · ' + entries().length + ' recorded', entry => entry.text, entry => ({
|
|
16
|
+
label: singleLine(entry.text),
|
|
17
|
+
description: entry.useCount >= REUSED ? entry.useCount + ' uses' : undefined,
|
|
18
|
+
// The card marks the row under the cursor, which the list decides.
|
|
19
|
+
current: false,
|
|
20
|
+
}), entry => entry.text, {
|
|
21
|
+
empty: () => `nothing matches · backspace to widen · ${hintKeys(keys(), 'picker.cancel')} cancel`,
|
|
22
|
+
listed: () => `${moveHint(keys(), 'picker.up', 'picker.down')} move · ${hintKeys(keys(), 'picker.confirm')} insert · ${hintKeys(keys(), 'picker.cancel')} cancel · type to filter`,
|
|
23
|
+
}, keys, draft);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=history-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-picker.js","sourceRoot":"","sources":["../../src/ui/history-picker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAe,MAAM,qBAAqB,CAAA;AACrE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAEpD,0FAA0F;AAC1F,MAAM,MAAM,GAAG,CAAC,CAAA;AAEhB;;;;;;;GAOG;AACH,MAAM,OAAO,aAAc,SAAQ,UAAuB;IACxD,YAAY,OAAqC,EAAE,KAAa,EAAE,IAAkB;QAClF,KAAK,CACH,OAAO,EACP,GAAG,EAAE,CAAC,mBAAmB,GAAG,OAAO,EAAE,CAAC,MAAM,GAAG,WAAW,EAC1D,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EACnB,KAAK,CAAC,EAAE,CAAC,CAAC;YACR,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;YAC7B,WAAW,EAAE,KAAK,CAAC,QAAQ,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS;YAC5E,mEAAmE;YACnE,OAAO,EAAE,KAAK;SACf,CAAC,EACF,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EACnB;YACE,KAAK,EAAE,GAAG,EAAE,CAAC,0CAA0C,QAAQ,CAAC,IAAI,EAAE,EAAE,eAAe,CAAC,SAAS;YACjG,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,aAAa,CAAC,WAAW,QAAQ,CAAC,IAAI,EAAE,EAAE,gBAAgB,CAAC,aAAa,QAAQ,CAAC,IAAI,EAAE,EAAE,eAAe,CAAC,0BAA0B;SACnL,EACD,IAAI,EACJ,KAAK,CACN,CAAA;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ActionLayer, type Keymap } from '../input/actions.ts';
|
|
2
|
+
import { type KeymapRow } from '../keys-command.ts';
|
|
3
|
+
import { ListPicker } from './picker.ts';
|
|
4
|
+
/**
|
|
5
|
+
* The key map, as a list the reader narrows by typing.
|
|
6
|
+
*
|
|
7
|
+
* One surface's whole keyboard is too long to read as prose, so it is a list:
|
|
8
|
+
* the filter reaches the action id, the layer, and the row's own words, which
|
|
9
|
+
* is what makes "ctrl+o", "gate", and "stash" each find their rows. The rows
|
|
10
|
+
* are re-read on every key and paint, so a settings edit lands in the open list
|
|
11
|
+
* rather than behind it.
|
|
12
|
+
*/
|
|
13
|
+
export declare class KeymapPicker extends ListPicker<KeymapRow> {
|
|
14
|
+
constructor(map: () => Keymap, layer: ActionLayer | undefined);
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=keymap-picker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keymap-picker.d.ts","sourceRoot":"","sources":["../../src/ui/keymap-picker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACvF,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAiBxC;;;;;;;;GAQG;AACH,qBAAa,YAAa,SAAQ,UAAU,CAAC,SAAS,CAAC;gBACzC,GAAG,EAAE,MAAM,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,SAAS;CAoB9D"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { hintKeys, moveHint } from "../input/actions.js";
|
|
2
|
+
import { keymapRows, layerNote } from "../keys-command.js";
|
|
3
|
+
import { ListPicker } from "./picker.js";
|
|
4
|
+
/**
|
|
5
|
+
* The list's heading: how much of the map is shown, and how much of it is the
|
|
6
|
+
* reader's own.
|
|
7
|
+
*
|
|
8
|
+
* Read per paint rather than built once, because a settings edit made while the
|
|
9
|
+
* list is open moves both counts under the reader's eyes.
|
|
10
|
+
*/
|
|
11
|
+
function heading(map, layer) {
|
|
12
|
+
const rows = keymapRows(map, layer);
|
|
13
|
+
const actions = rows.filter(row => row.action).length;
|
|
14
|
+
const written = rows.filter(row => row.written).length;
|
|
15
|
+
const scope = layer === undefined ? '' : ` · ${layer} · ${layerNote(layer)}`;
|
|
16
|
+
return `keys${scope} · ${actions} actions · ${written} of them yours`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The key map, as a list the reader narrows by typing.
|
|
20
|
+
*
|
|
21
|
+
* One surface's whole keyboard is too long to read as prose, so it is a list:
|
|
22
|
+
* the filter reaches the action id, the layer, and the row's own words, which
|
|
23
|
+
* is what makes "ctrl+o", "gate", and "stash" each find their rows. The rows
|
|
24
|
+
* are re-read on every key and paint, so a settings edit lands in the open list
|
|
25
|
+
* rather than behind it.
|
|
26
|
+
*/
|
|
27
|
+
export class KeymapPicker extends ListPicker {
|
|
28
|
+
constructor(map, layer) {
|
|
29
|
+
super(() => keymapRows(map(), layer), () => heading(map(), layer), row => row.id, row => ({ label: row.label, description: row.group, current: false }), row => [row.id, row.group, row.label].join(' '), {
|
|
30
|
+
empty: () => `nothing matches · backspace to widen · ${hintKeys(map(), 'picker.cancel')} close`,
|
|
31
|
+
// Nothing here is a pick, so both keys that settle the list close it;
|
|
32
|
+
// naming each one keeps a remapped cancel key visible where it answers.
|
|
33
|
+
listed: () => `${moveHint(map(), 'picker.up', 'picker.down')} move · ${hintKeys(map(), 'picker.confirm')} close`
|
|
34
|
+
+ ` · ${hintKeys(map(), 'picker.cancel')} close · type to filter`,
|
|
35
|
+
},
|
|
36
|
+
// The map the list draws and the map its own keys are read from are the
|
|
37
|
+
// same document, so a reader who moves picker.cancel sees both follow.
|
|
38
|
+
map);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=keymap-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keymap-picker.js","sourceRoot":"","sources":["../../src/ui/keymap-picker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAiC,MAAM,qBAAqB,CAAA;AACvF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAkB,MAAM,oBAAoB,CAAA;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC;;;;;;GAMG;AACH,SAAS,OAAO,CAAC,GAAW,EAAE,KAA8B;IAC1D,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAA;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAA;IACtD,MAAM,KAAK,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,SAAS,CAAC,KAAK,CAAC,EAAE,CAAA;IAC5E,OAAO,OAAO,KAAK,MAAM,OAAO,cAAc,OAAO,gBAAgB,CAAA;AACvE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,YAAa,SAAQ,UAAqB;IACrD,YAAY,GAAiB,EAAE,KAA8B;QAC3D,KAAK,CACH,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,EAC9B,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,EAC3B,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EACb,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EACrE,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAC/C;YACE,KAAK,EAAE,GAAG,EAAE,CAAC,0CAA0C,QAAQ,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,QAAQ;YAC/F,sEAAsE;YACtE,wEAAwE;YACxE,MAAM,EAAE,GAAG,EAAE,CACX,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,aAAa,CAAC,WAAW,QAAQ,CAAC,GAAG,EAAE,EAAE,gBAAgB,CAAC,QAAQ;kBAChG,MAAM,QAAQ,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,yBAAyB;SACpE;QACD,wEAAwE;QACxE,uEAAuE;QACvE,GAAG,CACJ,CAAA;IACH,CAAC;CACF"}
|