@dungle-scrubs/tallow 0.8.21 → 0.8.23
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/cli.js +35 -4
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/interactive-mode-patch.d.ts +2 -0
- package/dist/interactive-mode-patch.d.ts.map +1 -1
- package/dist/interactive-mode-patch.js +82 -0
- package/dist/interactive-mode-patch.js.map +1 -1
- package/dist/sdk.d.ts +17 -0
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +68 -1
- package/dist/sdk.js.map +1 -1
- package/dist/workspace-transition-relay.d.ts +40 -7
- package/dist/workspace-transition-relay.d.ts.map +1 -1
- package/dist/workspace-transition-relay.js +81 -16
- package/dist/workspace-transition-relay.js.map +1 -1
- package/extensions/__integration__/background-task-widget-ownership.test.ts +216 -0
- package/extensions/__integration__/claude-hooks-compat.test.ts +156 -0
- package/extensions/__integration__/slash-command-bridge.test.ts +169 -23
- package/extensions/_shared/atomic-write.ts +1 -1
- package/extensions/_shared/bordered-box.ts +102 -0
- package/extensions/_shared/interop-events.ts +5 -0
- package/extensions/_shared/pid-registry.ts +1 -1
- package/extensions/agent-commands-tool/index.ts +4 -1
- package/extensions/background-task-tool/__tests__/lifecycle.test.ts +50 -25
- package/extensions/background-task-tool/index.ts +139 -221
- package/extensions/bash-tool-enhanced/index.ts +1 -75
- package/extensions/cd-tool/index.ts +2 -2
- package/extensions/context-fork/spawn.ts +4 -1
- package/extensions/health/index.ts +6 -6
- package/extensions/hooks/__tests__/claude-compat.test.ts +35 -0
- package/extensions/hooks/__tests__/subprocess-hardening.test.ts +73 -0
- package/extensions/hooks/index.ts +27 -4
- package/extensions/loop/__tests__/loop.test.ts +168 -4
- package/extensions/loop/extension.json +6 -5
- package/extensions/loop/index.ts +242 -31
- package/extensions/plan-mode-tool/__tests__/agent-end-execution.test.ts +373 -0
- package/extensions/plan-mode-tool/index.ts +103 -41
- package/extensions/prompt-suggestions/__tests__/editor-compatibility.test.ts +42 -0
- package/extensions/prompt-suggestions/index.ts +41 -6
- package/extensions/slash-command-bridge/__tests__/slash-command-bridge.test.ts +267 -671
- package/extensions/slash-command-bridge/extension.json +1 -1
- package/extensions/slash-command-bridge/index.ts +230 -116
- package/extensions/subagent-tool/index.ts +2 -2
- package/extensions/subagent-tool/process.ts +4 -5
- package/extensions/tasks/commands/register-tasks-extension.ts +41 -0
- package/extensions/teams-tool/__tests__/peer-messaging.test.ts +29 -24
- package/extensions/teams-tool/dashboard.ts +3 -5
- package/extensions/teams-tool/dispatch/auto-dispatch.ts +18 -1
- package/extensions/teams-tool/tools/teammate-tools.ts +9 -6
- package/extensions/wezterm-pane-control/__tests__/index.test.ts +88 -4
- package/extensions/wezterm-pane-control/index.ts +113 -8
- package/package.json +6 -4
- package/packages/tallow-tui/README.md +51 -0
- package/packages/tallow-tui/dist/autocomplete.d.ts +48 -0
- package/packages/tallow-tui/dist/autocomplete.d.ts.map +1 -0
- package/packages/tallow-tui/dist/autocomplete.js +564 -0
- package/packages/tallow-tui/dist/autocomplete.js.map +1 -0
- package/packages/tallow-tui/dist/border-styles.d.ts +32 -0
- package/packages/tallow-tui/dist/border-styles.d.ts.map +1 -0
- package/packages/tallow-tui/dist/border-styles.js +46 -0
- package/packages/tallow-tui/dist/border-styles.js.map +1 -0
- package/packages/tallow-tui/dist/components/bordered-box.d.ts +52 -0
- package/packages/tallow-tui/dist/components/bordered-box.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/bordered-box.js +89 -0
- package/packages/tallow-tui/dist/components/bordered-box.js.map +1 -0
- package/packages/tallow-tui/dist/components/box.d.ts +22 -0
- package/packages/tallow-tui/dist/components/box.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/box.js +104 -0
- package/packages/tallow-tui/dist/components/box.js.map +1 -0
- package/packages/tallow-tui/dist/components/cancellable-loader.d.ts +22 -0
- package/packages/tallow-tui/dist/components/cancellable-loader.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/cancellable-loader.js +35 -0
- package/packages/tallow-tui/dist/components/cancellable-loader.js.map +1 -0
- package/packages/tallow-tui/dist/components/editor.d.ts +240 -0
- package/packages/tallow-tui/dist/components/editor.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/editor.js +1766 -0
- package/packages/tallow-tui/dist/components/editor.js.map +1 -0
- package/packages/tallow-tui/dist/components/image.d.ts +126 -0
- package/packages/tallow-tui/dist/components/image.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/image.js +245 -0
- package/packages/tallow-tui/dist/components/image.js.map +1 -0
- package/packages/tallow-tui/dist/components/input.d.ts +37 -0
- package/packages/tallow-tui/dist/components/input.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/input.js +439 -0
- package/packages/tallow-tui/dist/components/input.js.map +1 -0
- package/packages/tallow-tui/dist/components/loader.d.ts +88 -0
- package/packages/tallow-tui/dist/components/loader.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/loader.js +146 -0
- package/packages/tallow-tui/dist/components/loader.js.map +1 -0
- package/packages/tallow-tui/dist/components/markdown.d.ts +95 -0
- package/packages/tallow-tui/dist/components/markdown.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/markdown.js +633 -0
- package/packages/tallow-tui/dist/components/markdown.js.map +1 -0
- package/packages/tallow-tui/dist/components/select-list.d.ts +32 -0
- package/packages/tallow-tui/dist/components/select-list.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/select-list.js +156 -0
- package/packages/tallow-tui/dist/components/select-list.js.map +1 -0
- package/packages/tallow-tui/dist/components/settings-list.d.ts +50 -0
- package/packages/tallow-tui/dist/components/settings-list.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/settings-list.js +189 -0
- package/packages/tallow-tui/dist/components/settings-list.js.map +1 -0
- package/packages/tallow-tui/dist/components/spacer.d.ts +12 -0
- package/packages/tallow-tui/dist/components/spacer.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/spacer.js +23 -0
- package/packages/tallow-tui/dist/components/spacer.js.map +1 -0
- package/packages/tallow-tui/dist/components/text.d.ts +19 -0
- package/packages/tallow-tui/dist/components/text.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/text.js +91 -0
- package/packages/tallow-tui/dist/components/text.js.map +1 -0
- package/packages/tallow-tui/dist/components/truncated-text.d.ts +13 -0
- package/packages/tallow-tui/dist/components/truncated-text.d.ts.map +1 -0
- package/packages/tallow-tui/dist/components/truncated-text.js +51 -0
- package/packages/tallow-tui/dist/components/truncated-text.js.map +1 -0
- package/packages/tallow-tui/dist/editor-component.d.ts +50 -0
- package/packages/tallow-tui/dist/editor-component.d.ts.map +1 -0
- package/packages/tallow-tui/dist/editor-component.js +2 -0
- package/packages/tallow-tui/dist/editor-component.js.map +1 -0
- package/packages/tallow-tui/dist/fuzzy.d.ts +16 -0
- package/packages/tallow-tui/dist/fuzzy.d.ts.map +1 -0
- package/packages/tallow-tui/dist/fuzzy.js +107 -0
- package/packages/tallow-tui/dist/fuzzy.js.map +1 -0
- package/packages/tallow-tui/dist/index.d.ts +25 -0
- package/packages/tallow-tui/dist/index.d.ts.map +1 -0
- package/packages/tallow-tui/dist/index.js +35 -0
- package/packages/tallow-tui/dist/index.js.map +1 -0
- package/packages/tallow-tui/dist/keybindings.d.ts +39 -0
- package/packages/tallow-tui/dist/keybindings.d.ts.map +1 -0
- package/packages/tallow-tui/dist/keybindings.js +114 -0
- package/packages/tallow-tui/dist/keybindings.js.map +1 -0
- package/packages/tallow-tui/dist/keys.d.ts +168 -0
- package/packages/tallow-tui/dist/keys.d.ts.map +1 -0
- package/packages/tallow-tui/dist/keys.js +971 -0
- package/packages/tallow-tui/dist/keys.js.map +1 -0
- package/packages/tallow-tui/dist/kill-ring.d.ts +28 -0
- package/packages/tallow-tui/dist/kill-ring.d.ts.map +1 -0
- package/packages/tallow-tui/dist/kill-ring.js +44 -0
- package/packages/tallow-tui/dist/kill-ring.js.map +1 -0
- package/packages/tallow-tui/dist/stdin-buffer.d.ts +48 -0
- package/packages/tallow-tui/dist/stdin-buffer.d.ts.map +1 -0
- package/packages/tallow-tui/dist/stdin-buffer.js +317 -0
- package/packages/tallow-tui/dist/stdin-buffer.js.map +1 -0
- package/packages/tallow-tui/dist/terminal-image.d.ts +161 -0
- package/packages/tallow-tui/dist/terminal-image.d.ts.map +1 -0
- package/packages/tallow-tui/dist/terminal-image.js +460 -0
- package/packages/tallow-tui/dist/terminal-image.js.map +1 -0
- package/packages/tallow-tui/dist/terminal.d.ts +102 -0
- package/packages/tallow-tui/dist/terminal.d.ts.map +1 -0
- package/packages/tallow-tui/dist/terminal.js +263 -0
- package/packages/tallow-tui/dist/terminal.js.map +1 -0
- package/packages/tallow-tui/dist/test-utils/capability-env.d.ts +14 -0
- package/packages/tallow-tui/dist/test-utils/capability-env.d.ts.map +1 -0
- package/packages/tallow-tui/dist/test-utils/capability-env.js +55 -0
- package/packages/tallow-tui/dist/test-utils/capability-env.js.map +1 -0
- package/packages/tallow-tui/dist/tui.d.ts +239 -0
- package/packages/tallow-tui/dist/tui.d.ts.map +1 -0
- package/packages/tallow-tui/dist/tui.js +1058 -0
- package/packages/tallow-tui/dist/tui.js.map +1 -0
- package/packages/tallow-tui/dist/undo-stack.d.ts +17 -0
- package/packages/tallow-tui/dist/undo-stack.d.ts.map +1 -0
- package/packages/tallow-tui/dist/undo-stack.js +25 -0
- package/packages/tallow-tui/dist/undo-stack.js.map +1 -0
- package/packages/tallow-tui/dist/utils.d.ts +96 -0
- package/packages/tallow-tui/dist/utils.d.ts.map +1 -0
- package/packages/tallow-tui/dist/utils.js +843 -0
- package/packages/tallow-tui/dist/utils.js.map +1 -0
- package/packages/tallow-tui/package.json +24 -0
- package/packages/tallow-tui/src/__tests__/__snapshots__/render.test.ts.snap +121 -0
- package/packages/tallow-tui/src/__tests__/editor-border.test.ts +72 -0
- package/packages/tallow-tui/src/__tests__/editor-change-listener.test.ts +121 -0
- package/packages/tallow-tui/src/__tests__/editor-ghost-text.test.ts +112 -0
- package/packages/tallow-tui/src/__tests__/fuzzy.test.ts +91 -0
- package/packages/tallow-tui/src/__tests__/image-component.test.ts +113 -0
- package/packages/tallow-tui/src/__tests__/keys.test.ts +141 -0
- package/packages/tallow-tui/src/__tests__/render.test.ts +179 -0
- package/packages/tallow-tui/src/__tests__/stdin-buffer.test.ts +82 -0
- package/packages/tallow-tui/src/__tests__/terminal-image.test.ts +363 -0
- package/packages/tallow-tui/src/__tests__/tui-diff-regression.test.ts +454 -0
- package/packages/tallow-tui/src/__tests__/tui-render-scheduling.test.ts +256 -0
- package/packages/tallow-tui/src/__tests__/utils.test.ts +259 -0
- package/packages/tallow-tui/src/autocomplete.ts +716 -0
- package/packages/tallow-tui/src/border-styles.ts +60 -0
- package/packages/tallow-tui/src/components/bordered-box.ts +113 -0
- package/packages/tallow-tui/src/components/box.ts +137 -0
- package/packages/tallow-tui/src/components/cancellable-loader.ts +40 -0
- package/packages/tallow-tui/src/components/editor.ts +2143 -0
- package/packages/tallow-tui/src/components/image.ts +315 -0
- package/packages/tallow-tui/src/components/input.ts +522 -0
- package/packages/tallow-tui/src/components/loader.ts +187 -0
- package/packages/tallow-tui/src/components/markdown.ts +780 -0
- package/packages/tallow-tui/src/components/select-list.ts +197 -0
- package/packages/tallow-tui/src/components/settings-list.ts +264 -0
- package/packages/tallow-tui/src/components/spacer.ts +28 -0
- package/packages/tallow-tui/src/components/text.ts +113 -0
- package/packages/tallow-tui/src/components/truncated-text.ts +65 -0
- package/packages/tallow-tui/src/editor-component.ts +92 -0
- package/packages/tallow-tui/src/fuzzy.ts +133 -0
- package/packages/tallow-tui/src/index.ts +118 -0
- package/packages/tallow-tui/src/keybindings.ts +183 -0
- package/packages/tallow-tui/src/keys.ts +1189 -0
- package/packages/tallow-tui/src/kill-ring.ts +46 -0
- package/packages/tallow-tui/src/stdin-buffer.ts +386 -0
- package/packages/tallow-tui/src/terminal-image.ts +619 -0
- package/packages/tallow-tui/src/terminal.ts +350 -0
- package/packages/tallow-tui/src/test-utils/capability-env.ts +56 -0
- package/packages/tallow-tui/src/tui.ts +1336 -0
- package/packages/tallow-tui/src/undo-stack.ts +28 -0
- package/packages/tallow-tui/src/utils.ts +948 -0
- package/packages/tallow-tui/tsconfig.build.json +21 -0
- package/runtime/agent-runner.ts +20 -0
- package/runtime/atomic-write.ts +8 -0
- package/runtime/otel.ts +12 -0
- package/runtime/resolve-module.ts +23 -0
- package/runtime/runtime-path-provider.ts +12 -0
- package/runtime/runtime-provenance.ts +17 -0
- package/runtime/workspace-transition-relay.ts +21 -0
- package/runtime/workspace-transition.ts +29 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Border character sets for box-drawing.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** A set of box-drawing characters for rendering borders. */
|
|
8
|
+
export interface BorderStyle {
|
|
9
|
+
topLeft: string;
|
|
10
|
+
topRight: string;
|
|
11
|
+
bottomLeft: string;
|
|
12
|
+
bottomRight: string;
|
|
13
|
+
horizontal: string;
|
|
14
|
+
vertical: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Sharp corners — standard box-drawing (┌┐└┘). */
|
|
18
|
+
export const SHARP: BorderStyle = {
|
|
19
|
+
topLeft: "┌",
|
|
20
|
+
topRight: "┐",
|
|
21
|
+
bottomLeft: "└",
|
|
22
|
+
bottomRight: "┘",
|
|
23
|
+
horizontal: "─",
|
|
24
|
+
vertical: "│",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** Rounded corners — Unicode arc box-drawing (╭╮╰╯). */
|
|
28
|
+
export const ROUNDED: BorderStyle = {
|
|
29
|
+
topLeft: "╭",
|
|
30
|
+
topRight: "╮",
|
|
31
|
+
bottomLeft: "╰",
|
|
32
|
+
bottomRight: "╯",
|
|
33
|
+
horizontal: "─",
|
|
34
|
+
vertical: "│",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** Flat — horizontal rules only, no corners or verticals. */
|
|
38
|
+
export const FLAT: BorderStyle = {
|
|
39
|
+
topLeft: "─",
|
|
40
|
+
topRight: "─",
|
|
41
|
+
bottomLeft: "─",
|
|
42
|
+
bottomRight: "─",
|
|
43
|
+
horizontal: "─",
|
|
44
|
+
vertical: " ",
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Global default border style — set once, applies to all new BorderedBox instances.
|
|
49
|
+
* Extensions can set this at session_start to override.
|
|
50
|
+
*/
|
|
51
|
+
export let defaultBorderStyle: BorderStyle = SHARP;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Set the global default border style.
|
|
55
|
+
*
|
|
56
|
+
* @param style - Border style to use as default
|
|
57
|
+
*/
|
|
58
|
+
export function setDefaultBorderStyle(style: BorderStyle): void {
|
|
59
|
+
defaultBorderStyle = style;
|
|
60
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Box component with configurable border style (sharp, rounded, flat).
|
|
3
|
+
*
|
|
4
|
+
* Wraps child content lines in a full border with optional title,
|
|
5
|
+
* padding, and background fill.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { type BorderStyle, defaultBorderStyle } from "../border-styles.js";
|
|
11
|
+
import { truncateToWidth, visibleWidth } from "../utils.js";
|
|
12
|
+
import { Text } from "./text.js";
|
|
13
|
+
|
|
14
|
+
/** Configuration for a BorderedBox. */
|
|
15
|
+
export interface BorderedBoxOptions {
|
|
16
|
+
/** Border character set (defaults to global defaultBorderStyle). */
|
|
17
|
+
borderStyle?: BorderStyle;
|
|
18
|
+
/** Title rendered in the top border (optional). */
|
|
19
|
+
title?: string;
|
|
20
|
+
/** Horizontal padding inside the border (default: 1). */
|
|
21
|
+
paddingX?: number;
|
|
22
|
+
/** Color function applied to border characters. */
|
|
23
|
+
borderColorFn?: (str: string) => string;
|
|
24
|
+
/** Color function applied to the title. */
|
|
25
|
+
titleColorFn?: (str: string) => string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Renders content inside a bordered box.
|
|
30
|
+
*
|
|
31
|
+
* Usage:
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const box = new BorderedBox(["line 1", "line 2"], {
|
|
34
|
+
* borderStyle: ROUNDED,
|
|
35
|
+
* title: "Output",
|
|
36
|
+
* });
|
|
37
|
+
* const lines = box.render(80);
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export class BorderedBox extends Text {
|
|
41
|
+
private contentLines: string[];
|
|
42
|
+
private options: BorderedBoxOptions;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param contentLines - Pre-rendered content lines to wrap
|
|
46
|
+
* @param options - Border style, title, padding, color functions
|
|
47
|
+
*/
|
|
48
|
+
constructor(contentLines: string[], options: BorderedBoxOptions = {}) {
|
|
49
|
+
super("", contentLines.length + 2, 0);
|
|
50
|
+
this.contentLines = contentLines;
|
|
51
|
+
this.options = options;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Render the bordered box to an array of terminal lines.
|
|
56
|
+
*
|
|
57
|
+
* @param width - Available terminal width
|
|
58
|
+
* @returns Array of rendered lines including top/bottom borders
|
|
59
|
+
*/
|
|
60
|
+
render(width: number): string[] {
|
|
61
|
+
const style = this.options.borderStyle ?? defaultBorderStyle;
|
|
62
|
+
const padX = this.options.paddingX ?? 1;
|
|
63
|
+
const colorBorder = this.options.borderColorFn ?? ((s: string) => s);
|
|
64
|
+
const colorTitle = this.options.titleColorFn ?? ((s: string) => s);
|
|
65
|
+
|
|
66
|
+
const innerWidth = width - 2 - padX * 2; // borders + padding
|
|
67
|
+
if (innerWidth < 1) return this.contentLines;
|
|
68
|
+
|
|
69
|
+
const pad = " ".repeat(padX);
|
|
70
|
+
|
|
71
|
+
// Top border with optional title
|
|
72
|
+
let topBar: string;
|
|
73
|
+
if (this.options.title) {
|
|
74
|
+
const titleStr = ` ${colorTitle(this.options.title)} `;
|
|
75
|
+
const titleVisLen = visibleWidth(titleStr);
|
|
76
|
+
// topLeft(1) + leftBar(1) + titleStr + rightBar(rightFill) + topRight(1)
|
|
77
|
+
const rightFill = Math.max(0, width - 3 - titleVisLen);
|
|
78
|
+
topBar =
|
|
79
|
+
colorBorder(style.topLeft) +
|
|
80
|
+
colorBorder(style.horizontal) +
|
|
81
|
+
titleStr +
|
|
82
|
+
colorBorder(style.horizontal.repeat(rightFill)) +
|
|
83
|
+
colorBorder(style.topRight);
|
|
84
|
+
} else {
|
|
85
|
+
topBar =
|
|
86
|
+
colorBorder(style.topLeft) +
|
|
87
|
+
colorBorder(style.horizontal.repeat(width - 2)) +
|
|
88
|
+
colorBorder(style.topRight);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Content lines with side borders
|
|
92
|
+
const bodyLines = this.contentLines.map((line) => {
|
|
93
|
+
const clamped = visibleWidth(line) > innerWidth ? truncateToWidth(line, innerWidth) : line;
|
|
94
|
+
const fill = Math.max(0, innerWidth - visibleWidth(clamped));
|
|
95
|
+
return (
|
|
96
|
+
colorBorder(style.vertical) +
|
|
97
|
+
pad +
|
|
98
|
+
clamped +
|
|
99
|
+
" ".repeat(fill) +
|
|
100
|
+
pad +
|
|
101
|
+
colorBorder(style.vertical)
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Bottom border
|
|
106
|
+
const bottomBar =
|
|
107
|
+
colorBorder(style.bottomLeft) +
|
|
108
|
+
colorBorder(style.horizontal.repeat(width - 2)) +
|
|
109
|
+
colorBorder(style.bottomRight);
|
|
110
|
+
|
|
111
|
+
return [topBar, ...bodyLines, bottomBar];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { Component } from "../tui.js";
|
|
2
|
+
import { applyBackgroundToLine, visibleWidth } from "../utils.js";
|
|
3
|
+
|
|
4
|
+
type RenderCache = {
|
|
5
|
+
childLines: string[];
|
|
6
|
+
width: number;
|
|
7
|
+
bgSample: string | undefined;
|
|
8
|
+
lines: string[];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Box component - a container that applies padding and background to all children
|
|
13
|
+
*/
|
|
14
|
+
export class Box implements Component {
|
|
15
|
+
children: Component[] = [];
|
|
16
|
+
private paddingX: number;
|
|
17
|
+
private paddingY: number;
|
|
18
|
+
private bgFn?: (text: string) => string;
|
|
19
|
+
|
|
20
|
+
// Cache for rendered output
|
|
21
|
+
private cache?: RenderCache;
|
|
22
|
+
|
|
23
|
+
constructor(paddingX = 1, paddingY = 1, bgFn?: (text: string) => string) {
|
|
24
|
+
this.paddingX = paddingX;
|
|
25
|
+
this.paddingY = paddingY;
|
|
26
|
+
this.bgFn = bgFn;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
addChild(component: Component): void {
|
|
30
|
+
this.children.push(component);
|
|
31
|
+
this.invalidateCache();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
removeChild(component: Component): void {
|
|
35
|
+
const index = this.children.indexOf(component);
|
|
36
|
+
if (index !== -1) {
|
|
37
|
+
this.children.splice(index, 1);
|
|
38
|
+
this.invalidateCache();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
clear(): void {
|
|
43
|
+
this.children = [];
|
|
44
|
+
this.invalidateCache();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
setBgFn(bgFn?: (text: string) => string): void {
|
|
48
|
+
this.bgFn = bgFn;
|
|
49
|
+
// Don't invalidate here - we'll detect bgFn changes by sampling output
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private invalidateCache(): void {
|
|
53
|
+
this.cache = undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private matchCache(width: number, childLines: string[], bgSample: string | undefined): boolean {
|
|
57
|
+
const cache = this.cache;
|
|
58
|
+
return (
|
|
59
|
+
!!cache &&
|
|
60
|
+
cache.width === width &&
|
|
61
|
+
cache.bgSample === bgSample &&
|
|
62
|
+
cache.childLines.length === childLines.length &&
|
|
63
|
+
cache.childLines.every((line, i) => line === childLines[i])
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
invalidate(): void {
|
|
68
|
+
this.invalidateCache();
|
|
69
|
+
for (const child of this.children) {
|
|
70
|
+
child.invalidate?.();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
render(width: number): string[] {
|
|
75
|
+
if (this.children.length === 0) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const contentWidth = Math.max(1, width - this.paddingX * 2);
|
|
80
|
+
const leftPad = " ".repeat(this.paddingX);
|
|
81
|
+
|
|
82
|
+
// Render all children
|
|
83
|
+
const childLines: string[] = [];
|
|
84
|
+
for (const child of this.children) {
|
|
85
|
+
const lines = child.render(contentWidth);
|
|
86
|
+
for (const line of lines) {
|
|
87
|
+
childLines.push(leftPad + line);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (childLines.length === 0) {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Check if bgFn output changed by sampling
|
|
96
|
+
const bgSample = this.bgFn ? this.bgFn("test") : undefined;
|
|
97
|
+
|
|
98
|
+
// Check cache validity
|
|
99
|
+
if (this.matchCache(width, childLines, bgSample)) {
|
|
100
|
+
return this.cache!.lines;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Apply background and padding
|
|
104
|
+
const result: string[] = [];
|
|
105
|
+
|
|
106
|
+
// Top padding
|
|
107
|
+
for (let i = 0; i < this.paddingY; i++) {
|
|
108
|
+
result.push(this.applyBg("", width));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Content
|
|
112
|
+
for (const line of childLines) {
|
|
113
|
+
result.push(this.applyBg(line, width));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Bottom padding
|
|
117
|
+
for (let i = 0; i < this.paddingY; i++) {
|
|
118
|
+
result.push(this.applyBg("", width));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Update cache
|
|
122
|
+
this.cache = { childLines, width, bgSample, lines: result };
|
|
123
|
+
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private applyBg(line: string, width: number): string {
|
|
128
|
+
const visLen = visibleWidth(line);
|
|
129
|
+
const padNeeded = Math.max(0, width - visLen);
|
|
130
|
+
const padded = line + " ".repeat(padNeeded);
|
|
131
|
+
|
|
132
|
+
if (this.bgFn) {
|
|
133
|
+
return applyBackgroundToLine(padded, width, this.bgFn);
|
|
134
|
+
}
|
|
135
|
+
return padded;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { getEditorKeybindings } from "../keybindings.js";
|
|
2
|
+
import { Loader } from "./loader.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Loader that can be cancelled with Escape.
|
|
6
|
+
* Extends Loader with an AbortSignal for cancelling async operations.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* const loader = new CancellableLoader(tui, cyan, dim, "Working...");
|
|
10
|
+
* loader.onAbort = () => done(null);
|
|
11
|
+
* doWork(loader.signal).then(done);
|
|
12
|
+
*/
|
|
13
|
+
export class CancellableLoader extends Loader {
|
|
14
|
+
private abortController = new AbortController();
|
|
15
|
+
|
|
16
|
+
/** Called when user presses Escape */
|
|
17
|
+
onAbort?: () => void;
|
|
18
|
+
|
|
19
|
+
/** AbortSignal that is aborted when user presses Escape */
|
|
20
|
+
get signal(): AbortSignal {
|
|
21
|
+
return this.abortController.signal;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Whether the loader was aborted */
|
|
25
|
+
get aborted(): boolean {
|
|
26
|
+
return this.abortController.signal.aborted;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
handleInput(data: string): void {
|
|
30
|
+
const kb = getEditorKeybindings();
|
|
31
|
+
if (kb.matches(data, "selectCancel")) {
|
|
32
|
+
this.abortController.abort();
|
|
33
|
+
this.onAbort?.();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
dispose(): void {
|
|
38
|
+
this.stop();
|
|
39
|
+
}
|
|
40
|
+
}
|