@dungle-scrubs/tallow 0.9.3 → 0.9.6
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 +7 -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 +24 -10
- package/dist/interactive-mode-patch.d.ts.map +1 -1
- package/dist/interactive-mode-patch.js +285 -148
- package/dist/interactive-mode-patch.js.map +1 -1
- package/dist/interactive-reset.d.ts +49 -0
- package/dist/interactive-reset.d.ts.map +1 -0
- package/dist/interactive-reset.js +40 -0
- package/dist/interactive-reset.js.map +1 -0
- package/dist/pi-tui-editor-patch.d.ts +10 -0
- package/dist/pi-tui-editor-patch.d.ts.map +1 -0
- package/dist/pi-tui-editor-patch.js +159 -0
- package/dist/pi-tui-editor-patch.js.map +1 -0
- package/dist/pi-tui-patch.d.ts +2 -0
- package/dist/pi-tui-patch.d.ts.map +1 -0
- package/dist/pi-tui-patch.js +563 -0
- package/dist/pi-tui-patch.js.map +1 -0
- package/dist/pi-tui-settings-list-patch.d.ts +11 -0
- package/dist/pi-tui-settings-list-patch.d.ts.map +1 -0
- package/dist/pi-tui-settings-list-patch.js +38 -0
- package/dist/pi-tui-settings-list-patch.js.map +1 -0
- package/dist/reset-diagnostics.d.ts +69 -0
- package/dist/reset-diagnostics.d.ts.map +1 -0
- package/dist/reset-diagnostics.js +41 -0
- package/dist/reset-diagnostics.js.map +1 -0
- package/dist/sdk.d.ts +5 -21
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +180 -149
- package/dist/sdk.js.map +1 -1
- package/dist/workspace-transition-interactive.d.ts +1 -0
- package/dist/workspace-transition-interactive.d.ts.map +1 -1
- package/dist/workspace-transition-interactive.js +7 -17
- package/dist/workspace-transition-interactive.js.map +1 -1
- package/extensions/__integration__/audit-findings.test.ts +6 -16
- package/extensions/__integration__/teams-runtime.test.ts +4 -1
- package/extensions/_icons/index.ts +2 -4
- package/extensions/_shared/__tests__/image-metadata.test.ts +33 -0
- package/extensions/_shared/__tests__/terminal-links.test.ts +18 -0
- package/extensions/_shared/image-metadata.ts +99 -0
- package/extensions/_shared/inline-preview.ts +1 -1
- package/extensions/_shared/pid-registry.ts +0 -1
- package/extensions/_shared/terminal-links.ts +22 -0
- package/extensions/ask-user-question-tool/index.ts +0 -3
- package/extensions/clear/__tests__/clear.test.ts +270 -3
- package/extensions/command-expansion/index.ts +1 -1
- package/extensions/context-files/index.ts +5 -1
- package/extensions/context-fork/__tests__/context-fork.test.ts +94 -1
- package/extensions/context-fork/extension.json +1 -1
- package/extensions/context-fork/index.ts +32 -0
- package/extensions/edit-tool-enhanced/index.ts +2 -1
- package/extensions/hooks/index.ts +33 -11
- package/extensions/loop/index.ts +14 -1
- package/extensions/lsp/index.ts +64 -13
- package/extensions/lsp/package.json +2 -2
- package/extensions/permissions/__tests__/permissions.test.ts +4 -4
- package/extensions/random-spinner/index.ts +7 -642
- package/extensions/read-tool-enhanced/index.ts +6 -8
- package/extensions/render-stabilizer/__tests__/render-stabilizer.test.ts +4 -5
- package/extensions/render-stabilizer/index.ts +6 -6
- package/extensions/show-system-prompt/__tests__/show-system-prompt.test.ts +1 -1
- package/extensions/slash-command-bridge/__tests__/slash-command-bridge.test.ts +26 -0
- package/extensions/slash-command-bridge/index.ts +14 -2
- package/extensions/subagent-tool/index.ts +1 -1
- package/extensions/subagent-tool/model-resolver.ts +274 -7
- package/extensions/tasks/__tests__/state-ui.test.ts +3 -3
- package/extensions/tasks/__tests__/widget-subagents.test.ts +2 -2
- package/extensions/tasks/commands/register-tasks-extension.ts +10 -10
- package/extensions/tasks/state/index.ts +1 -1
- package/extensions/tasks/ui/index.ts +2 -7
- package/extensions/teams-tool/tools/register-extension.ts +1 -3
- package/extensions/web-search-tool/index.ts +2 -1
- package/extensions/write-tool-enhanced/__tests__/write-tool-enhanced.test.ts +21 -6
- package/extensions/write-tool-enhanced/index.ts +2 -1
- package/node_modules/@mariozechner/pi-tui/README.md +56 -34
- package/node_modules/@mariozechner/pi-tui/dist/autocomplete.d.ts +18 -13
- package/node_modules/@mariozechner/pi-tui/dist/autocomplete.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/autocomplete.js +182 -113
- package/node_modules/@mariozechner/pi-tui/dist/autocomplete.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/cancellable-loader.js +3 -3
- package/node_modules/@mariozechner/pi-tui/dist/components/cancellable-loader.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/editor.d.ts +45 -36
- package/node_modules/@mariozechner/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/editor.js +489 -325
- package/node_modules/@mariozechner/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/image.d.ts +1 -99
- package/node_modules/@mariozechner/pi-tui/dist/components/image.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/image.js +17 -192
- package/node_modules/@mariozechner/pi-tui/dist/components/image.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/input.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/input.js +57 -60
- package/node_modules/@mariozechner/pi-tui/dist/components/input.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/loader.d.ts +2 -69
- package/node_modules/@mariozechner/pi-tui/dist/components/loader.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/loader.js +5 -102
- package/node_modules/@mariozechner/pi-tui/dist/components/loader.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/markdown.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/markdown.js +111 -53
- package/node_modules/@mariozechner/pi-tui/dist/components/markdown.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/select-list.d.ts +19 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/select-list.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/select-list.js +78 -67
- package/node_modules/@mariozechner/pi-tui/dist/components/select-list.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts +0 -2
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js +12 -23
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/index.d.ts +8 -10
- package/node_modules/@mariozechner/pi-tui/dist/index.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/index.js +6 -9
- package/node_modules/@mariozechner/pi-tui/dist/index.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts +108 -238
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.js +108 -365
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts +33 -48
- package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keys.js +239 -155
- package/node_modules/@mariozechner/pi-tui/dist/keys.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal-image.d.ts +14 -94
- package/node_modules/@mariozechner/pi-tui/dist/terminal-image.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal-image.js +44 -186
- package/node_modules/@mariozechner/pi-tui/dist/terminal-image.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts +13 -58
- package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal.js +78 -111
- package/node_modules/@mariozechner/pi-tui/dist/terminal.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts +24 -110
- package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/tui.js +188 -435
- package/node_modules/@mariozechner/pi-tui/dist/tui.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/utils.d.ts +0 -18
- package/node_modules/@mariozechner/pi-tui/dist/utils.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/utils.js +251 -119
- package/node_modules/@mariozechner/pi-tui/dist/utils.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/package.json +6 -6
- package/node_modules/@mariozechner/pi-tui/src/__tests__/__snapshots__/render.test.ts.snap +3 -40
- package/node_modules/@mariozechner/pi-tui/src/__tests__/image-component.test.ts +71 -81
- package/node_modules/@mariozechner/pi-tui/src/__tests__/render.test.ts +0 -33
- package/node_modules/@mariozechner/pi-tui/src/__tests__/terminal-image.test.ts +93 -334
- package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-render-scheduling.test.ts +1 -1
- package/node_modules/@mariozechner/pi-tui/src/__tests__/utils.test.ts +11 -196
- package/node_modules/@mariozechner/pi-tui/src/autocomplete.ts +228 -142
- package/node_modules/@mariozechner/pi-tui/src/components/cancellable-loader.ts +3 -3
- package/node_modules/@mariozechner/pi-tui/src/components/editor.ts +624 -390
- package/node_modules/@mariozechner/pi-tui/src/components/image.ts +17 -227
- package/node_modules/@mariozechner/pi-tui/src/components/input.ts +71 -63
- package/node_modules/@mariozechner/pi-tui/src/components/loader.ts +5 -137
- package/node_modules/@mariozechner/pi-tui/src/components/markdown.ts +143 -52
- package/node_modules/@mariozechner/pi-tui/src/components/select-list.ts +136 -70
- package/node_modules/@mariozechner/pi-tui/src/components/settings-list.ts +11 -23
- package/node_modules/@mariozechner/pi-tui/src/index.ts +17 -36
- package/node_modules/@mariozechner/pi-tui/src/keybindings.ts +148 -421
- package/node_modules/@mariozechner/pi-tui/src/keys.ts +253 -181
- package/node_modules/@mariozechner/pi-tui/src/terminal-image.ts +51 -252
- package/node_modules/@mariozechner/pi-tui/src/terminal.ts +78 -133
- package/node_modules/@mariozechner/pi-tui/src/tui.ts +202 -478
- package/node_modules/@mariozechner/pi-tui/src/utils.ts +289 -125
- package/node_modules/@mariozechner/pi-tui/tsconfig.build.json +1 -0
- package/package.json +13 -13
- package/packages/tallow-tui/node_modules/@types/mime-types/README.md +8 -2
- package/packages/tallow-tui/node_modules/@types/mime-types/index.d.ts +6 -0
- package/packages/tallow-tui/node_modules/@types/mime-types/package.json +9 -3
- package/packages/tallow-tui/node_modules/get-east-asian-width/lookup-data.js +18 -0
- package/packages/tallow-tui/node_modules/get-east-asian-width/lookup.js +116 -384
- package/packages/tallow-tui/node_modules/get-east-asian-width/package.json +5 -4
- package/packages/tallow-tui/node_modules/get-east-asian-width/utilities.js +24 -0
- package/packages/tallow-tui/node_modules/marked/README.md +5 -4
- package/packages/tallow-tui/node_modules/marked/bin/main.js +10 -8
- package/packages/tallow-tui/node_modules/marked/bin/marked.js +2 -1
- package/packages/tallow-tui/node_modules/marked/lib/marked.d.ts +156 -125
- package/packages/tallow-tui/node_modules/marked/lib/marked.esm.js +67 -2179
- package/packages/tallow-tui/node_modules/marked/lib/marked.esm.js.map +3 -3
- package/packages/tallow-tui/node_modules/marked/lib/marked.umd.js +67 -2201
- package/packages/tallow-tui/node_modules/marked/lib/marked.umd.js.map +3 -3
- package/packages/tallow-tui/node_modules/marked/man/marked.1 +4 -2
- package/packages/tallow-tui/node_modules/marked/man/marked.1.md +2 -1
- package/packages/tallow-tui/node_modules/marked/package.json +26 -34
- package/runtime/model-metadata-overrides.ts +10 -1
- package/runtime/pid-schema.ts +26 -6
- package/skills/tallow-expert/SKILL.md +1 -3
- package/node_modules/@mariozechner/pi-tui/dist/border-styles.d.ts +0 -32
- package/node_modules/@mariozechner/pi-tui/dist/border-styles.d.ts.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/border-styles.js +0 -46
- package/node_modules/@mariozechner/pi-tui/dist/border-styles.js.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.d.ts +0 -52
- package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.d.ts.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.js +0 -89
- package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.js.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.d.ts +0 -14
- package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.d.ts.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.js +0 -55
- package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.js.map +0 -1
- package/node_modules/@mariozechner/pi-tui/src/__tests__/editor-change-listener.test.ts +0 -121
- package/node_modules/@mariozechner/pi-tui/src/__tests__/editor-ghost-text.test.ts +0 -112
- package/node_modules/@mariozechner/pi-tui/src/__tests__/mouse-events.test.ts +0 -134
- package/node_modules/@mariozechner/pi-tui/src/__tests__/settings-list.test.ts +0 -49
- package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-diff-regression.test.ts +0 -555
- package/node_modules/@mariozechner/pi-tui/src/border-styles.ts +0 -60
- package/node_modules/@mariozechner/pi-tui/src/components/bordered-box.ts +0 -113
- package/node_modules/@mariozechner/pi-tui/src/test-utils/capability-env.ts +0 -56
- package/packages/tallow-tui/node_modules/marked/lib/marked.cjs +0 -2211
- package/packages/tallow-tui/node_modules/marked/lib/marked.cjs.map +0 -7
- package/packages/tallow-tui/node_modules/marked/lib/marked.d.cts +0 -728
- package/packages/tallow-tui/node_modules/marked/marked.min.js +0 -69
|
@@ -1,87 +1,20 @@
|
|
|
1
1
|
import type { TUI } from "../tui.js";
|
|
2
2
|
import { Text } from "./text.js";
|
|
3
|
-
/** Optional configuration for the Loader's spinner appearance and timing. */
|
|
4
|
-
export interface LoaderOptions {
|
|
5
|
-
/** Spinner animation frames (defaults to braille dots). */
|
|
6
|
-
frames?: string[];
|
|
7
|
-
/** Animation interval in ms (default: 80). */
|
|
8
|
-
intervalMs?: number;
|
|
9
|
-
}
|
|
10
|
-
/** Context passed to the message transform callback each tick. */
|
|
11
|
-
export interface MessageTransformContext {
|
|
12
|
-
/** The current message set on this Loader (from constructor or setMessage). */
|
|
13
|
-
message: string;
|
|
14
|
-
/** Monotonic tick counter — increments each animation frame for this instance. */
|
|
15
|
-
tick: number;
|
|
16
|
-
/** True if the message has not been changed via setMessage() since construction. */
|
|
17
|
-
isInitialMessage: boolean;
|
|
18
|
-
}
|
|
19
3
|
/**
|
|
20
|
-
* Loader component that updates with
|
|
21
|
-
*
|
|
22
|
-
* @param ui - TUI instance for rendering
|
|
23
|
-
* @param spinnerColorFn - Color function applied to the spinner frame
|
|
24
|
-
* @param messageColorFn - Color function applied to the message text
|
|
25
|
-
* @param message - Text shown next to the spinner (default: "Loading...")
|
|
26
|
-
* @param options - Optional frames and interval override
|
|
4
|
+
* Loader component that updates every 80ms with spinning animation
|
|
27
5
|
*/
|
|
28
6
|
export declare class Loader extends Text {
|
|
29
7
|
private spinnerColorFn;
|
|
30
8
|
private messageColorFn;
|
|
31
9
|
private message;
|
|
32
10
|
private frames;
|
|
33
|
-
private intervalMs;
|
|
34
11
|
private currentFrame;
|
|
35
12
|
private intervalId;
|
|
36
|
-
private _transformIntervalId;
|
|
37
13
|
private ui;
|
|
38
|
-
|
|
39
|
-
private _transformTick;
|
|
40
|
-
/** Tracks whether setMessage() has been called since construction. */
|
|
41
|
-
private _messageChanged;
|
|
42
|
-
constructor(ui: TUI, spinnerColorFn: (str: string) => string, messageColorFn: (str: string) => string, message?: string, options?: LoaderOptions);
|
|
43
|
-
/**
|
|
44
|
-
* Global default spinner frames — set once, applies to all new Loader instances.
|
|
45
|
-
* Extensions can set this at session_start to override the braille default.
|
|
46
|
-
*/
|
|
47
|
-
static defaultFrames: string[] | undefined;
|
|
48
|
-
/**
|
|
49
|
-
* Global default interval — set once, applies to all new Loader instances.
|
|
50
|
-
*/
|
|
51
|
-
static defaultIntervalMs: number | undefined;
|
|
52
|
-
/**
|
|
53
|
-
* Global message transform — called each tick to modify the displayed message.
|
|
54
|
-
* Extensions use this to animate or replace the loader text.
|
|
55
|
-
* Return the string to display. The transform is applied before messageColorFn.
|
|
56
|
-
*/
|
|
57
|
-
static defaultMessageTransform?: (ctx: MessageTransformContext) => string;
|
|
58
|
-
/**
|
|
59
|
-
* Interval (ms) for the message transform tick — independent of the spinner frame rate.
|
|
60
|
-
* When set to a value faster than the spinner interval, a separate timer drives
|
|
61
|
-
* the transform tick and re-renders, giving animations higher
|
|
62
|
-
* frame rates without affecting the spinner animation speed.
|
|
63
|
-
*/
|
|
64
|
-
static defaultTransformIntervalMs: number | undefined;
|
|
65
|
-
/** Whether the loader is hidden (renders as empty space). */
|
|
66
|
-
private hidden;
|
|
67
|
-
/**
|
|
68
|
-
* Hide the loader — renders nothing but keeps the interval alive.
|
|
69
|
-
* Call show() to restore.
|
|
70
|
-
*/
|
|
71
|
-
hide(): void;
|
|
72
|
-
/**
|
|
73
|
-
* Show the loader after a hide() call.
|
|
74
|
-
*/
|
|
75
|
-
show(): void;
|
|
14
|
+
constructor(ui: TUI, spinnerColorFn: (str: string) => string, messageColorFn: (str: string) => string, message?: string);
|
|
76
15
|
render(width: number): string[];
|
|
77
16
|
start(): void;
|
|
78
17
|
stop(): void;
|
|
79
|
-
/** Sentinel value — pass to setWorkingMessage() to hide the loader. */
|
|
80
|
-
static readonly HIDE = "\u200B";
|
|
81
|
-
/**
|
|
82
|
-
* Set the loader message. Pass Loader.HIDE to hide, any other string to show.
|
|
83
|
-
* @param message - Message text or Loader.HIDE sentinel
|
|
84
|
-
*/
|
|
85
18
|
setMessage(message: string): void;
|
|
86
19
|
private updateDisplay;
|
|
87
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/components/loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/components/loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;GAEG;AACH,qBAAa,MAAO,SAAQ,IAAI;IAQ9B,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,OAAO;IAThB,OAAO,CAAC,MAAM,CAAsD;IACpE,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,EAAE,CAAoB;gBAG7B,EAAE,EAAE,GAAG,EACC,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EACvC,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EACvC,OAAO,GAAE,MAAqB;IAOvC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAI/B,KAAK;IAQL,IAAI;IAOJ,UAAU,CAAC,OAAO,EAAE,MAAM;IAK1B,OAAO,CAAC,aAAa;CAOrB"}
|
|
@@ -1,143 +1,46 @@
|
|
|
1
1
|
import { Text } from "./text.js";
|
|
2
|
-
/** Default braille spinner frames used when no custom frames are provided. */
|
|
3
|
-
const DEFAULT_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
4
|
-
/** Default animation interval in milliseconds. */
|
|
5
|
-
const DEFAULT_INTERVAL_MS = 80;
|
|
6
2
|
/**
|
|
7
|
-
* Loader component that updates with
|
|
8
|
-
*
|
|
9
|
-
* @param ui - TUI instance for rendering
|
|
10
|
-
* @param spinnerColorFn - Color function applied to the spinner frame
|
|
11
|
-
* @param messageColorFn - Color function applied to the message text
|
|
12
|
-
* @param message - Text shown next to the spinner (default: "Loading...")
|
|
13
|
-
* @param options - Optional frames and interval override
|
|
3
|
+
* Loader component that updates every 80ms with spinning animation
|
|
14
4
|
*/
|
|
15
5
|
export class Loader extends Text {
|
|
16
6
|
spinnerColorFn;
|
|
17
7
|
messageColorFn;
|
|
18
8
|
message;
|
|
19
|
-
frames;
|
|
20
|
-
intervalMs;
|
|
9
|
+
frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
21
10
|
currentFrame = 0;
|
|
22
11
|
intervalId = null;
|
|
23
|
-
_transformIntervalId = null;
|
|
24
12
|
ui = null;
|
|
25
|
-
|
|
26
|
-
_transformTick = 0;
|
|
27
|
-
/** Tracks whether setMessage() has been called since construction. */
|
|
28
|
-
_messageChanged = false;
|
|
29
|
-
constructor(ui, spinnerColorFn, messageColorFn, message = "Loading...", options) {
|
|
13
|
+
constructor(ui, spinnerColorFn, messageColorFn, message = "Loading...") {
|
|
30
14
|
super("", 1, 0);
|
|
31
15
|
this.spinnerColorFn = spinnerColorFn;
|
|
32
16
|
this.messageColorFn = messageColorFn;
|
|
33
17
|
this.message = message;
|
|
34
|
-
this.frames = options?.frames ?? Loader.defaultFrames ?? DEFAULT_FRAMES;
|
|
35
|
-
this.intervalMs = options?.intervalMs ?? Loader.defaultIntervalMs ?? DEFAULT_INTERVAL_MS;
|
|
36
18
|
this.ui = ui;
|
|
37
19
|
this.start();
|
|
38
20
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Global default spinner frames — set once, applies to all new Loader instances.
|
|
41
|
-
* Extensions can set this at session_start to override the braille default.
|
|
42
|
-
*/
|
|
43
|
-
static defaultFrames;
|
|
44
|
-
/**
|
|
45
|
-
* Global default interval — set once, applies to all new Loader instances.
|
|
46
|
-
*/
|
|
47
|
-
static defaultIntervalMs;
|
|
48
|
-
/**
|
|
49
|
-
* Global message transform — called each tick to modify the displayed message.
|
|
50
|
-
* Extensions use this to animate or replace the loader text.
|
|
51
|
-
* Return the string to display. The transform is applied before messageColorFn.
|
|
52
|
-
*/
|
|
53
|
-
static defaultMessageTransform;
|
|
54
|
-
/**
|
|
55
|
-
* Interval (ms) for the message transform tick — independent of the spinner frame rate.
|
|
56
|
-
* When set to a value faster than the spinner interval, a separate timer drives
|
|
57
|
-
* the transform tick and re-renders, giving animations higher
|
|
58
|
-
* frame rates without affecting the spinner animation speed.
|
|
59
|
-
*/
|
|
60
|
-
static defaultTransformIntervalMs;
|
|
61
|
-
/** Whether the loader is hidden (renders as empty space). */
|
|
62
|
-
hidden = false;
|
|
63
|
-
/**
|
|
64
|
-
* Hide the loader — renders nothing but keeps the interval alive.
|
|
65
|
-
* Call show() to restore.
|
|
66
|
-
*/
|
|
67
|
-
hide() {
|
|
68
|
-
this.hidden = true;
|
|
69
|
-
this.setText("");
|
|
70
|
-
this.ui?.requestRender();
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Show the loader after a hide() call.
|
|
74
|
-
*/
|
|
75
|
-
show() {
|
|
76
|
-
this.hidden = false;
|
|
77
|
-
this.updateDisplay();
|
|
78
|
-
}
|
|
79
21
|
render(width) {
|
|
80
|
-
if (this.hidden)
|
|
81
|
-
return [];
|
|
82
22
|
return ["", ...super.render(width)];
|
|
83
23
|
}
|
|
84
24
|
start() {
|
|
85
25
|
this.updateDisplay();
|
|
86
|
-
const transformMs = Loader.defaultTransformIntervalMs;
|
|
87
|
-
const hasFastTransform = Loader.defaultMessageTransform != null &&
|
|
88
|
-
transformMs != null &&
|
|
89
|
-
transformMs < this.intervalMs;
|
|
90
26
|
this.intervalId = setInterval(() => {
|
|
91
27
|
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
92
|
-
this._transformTick++;
|
|
93
28
|
this.updateDisplay();
|
|
94
|
-
},
|
|
95
|
-
// Separate faster interval for message transform re-renders only.
|
|
96
|
-
// Does NOT advance _transformTick — just re-rolls random visuals.
|
|
97
|
-
if (hasFastTransform) {
|
|
98
|
-
this._transformIntervalId = setInterval(() => {
|
|
99
|
-
this.updateDisplay();
|
|
100
|
-
}, transformMs);
|
|
101
|
-
}
|
|
29
|
+
}, 80);
|
|
102
30
|
}
|
|
103
31
|
stop() {
|
|
104
32
|
if (this.intervalId) {
|
|
105
33
|
clearInterval(this.intervalId);
|
|
106
34
|
this.intervalId = null;
|
|
107
35
|
}
|
|
108
|
-
if (this._transformIntervalId) {
|
|
109
|
-
clearInterval(this._transformIntervalId);
|
|
110
|
-
this._transformIntervalId = null;
|
|
111
|
-
}
|
|
112
36
|
}
|
|
113
|
-
/** Sentinel value — pass to setWorkingMessage() to hide the loader. */
|
|
114
|
-
static HIDE = "\u200B";
|
|
115
|
-
/**
|
|
116
|
-
* Set the loader message. Pass Loader.HIDE to hide, any other string to show.
|
|
117
|
-
* @param message - Message text or Loader.HIDE sentinel
|
|
118
|
-
*/
|
|
119
37
|
setMessage(message) {
|
|
120
|
-
if (message === Loader.HIDE) {
|
|
121
|
-
this.hide();
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (this.hidden)
|
|
125
|
-
this.show();
|
|
126
|
-
this._messageChanged = true;
|
|
127
38
|
this.message = message;
|
|
128
39
|
this.updateDisplay();
|
|
129
40
|
}
|
|
130
41
|
updateDisplay() {
|
|
131
42
|
const frame = this.frames[this.currentFrame];
|
|
132
|
-
|
|
133
|
-
if (Loader.defaultMessageTransform) {
|
|
134
|
-
displayMessage = Loader.defaultMessageTransform({
|
|
135
|
-
message: this.message,
|
|
136
|
-
tick: this._transformTick,
|
|
137
|
-
isInitialMessage: !this._messageChanged,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
this.setText(`${this.spinnerColorFn(frame)} ${this.messageColorFn(displayMessage)}`);
|
|
43
|
+
this.setText(`${this.spinnerColorFn(frame)} ${this.messageColorFn(this.message)}`);
|
|
141
44
|
if (this.ui) {
|
|
142
45
|
this.ui.requestRender();
|
|
143
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/components/loader.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/components/loader.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;GAEG;AACH,MAAM,OAAO,MAAO,SAAQ,IAAI;IAQtB;IACA;IACA;IATD,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAC5D,YAAY,GAAG,CAAC,CAAC;IACjB,UAAU,GAA0B,IAAI,CAAC;IACzC,EAAE,GAAe,IAAI,CAAC;IAE9B,YACC,EAAO,EACC,cAAuC,EACvC,cAAuC,EACvC,UAAkB,YAAY;QAEtC,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAJR,mBAAc,GAAd,cAAc,CAAyB;QACvC,mBAAc,GAAd,cAAc,CAAyB;QACvC,YAAO,GAAP,OAAO,CAAuB;QAGtC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,KAAK,EAAE,CAAC;IACd,CAAC;IAED,MAAM,CAAC,KAAa;QACnB,OAAO,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACrC,CAAC;IAED,KAAK;QACJ,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;YAClC,IAAI,CAAC,YAAY,GAAG,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;YACjE,IAAI,CAAC,aAAa,EAAE,CAAC;QACtB,CAAC,EAAE,EAAE,CAAC,CAAC;IACR,CAAC;IAED,IAAI;QACH,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACxB,CAAC;IACF,CAAC;IAED,UAAU,CAAC,OAAe;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAEO,aAAa;QACpB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACnF,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,IAAI,CAAC,EAAE,CAAC,aAAa,EAAE,CAAC;QACzB,CAAC;IACF,CAAC;CACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/components/markdown.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/components/markdown.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AA2B3C;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,gCAAgC;IAChC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,gCAAgC;IAChC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC,gBAAgB;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,kBAAkB;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yBAAyB;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAClC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAClC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/B,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAChC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7B,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IAC1D,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAOD,qBAAa,QAAS,YAAW,SAAS;IACzC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAC5C,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,kBAAkB,CAAC,CAAS;IAGpC,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAC,CAAW;gBAG9B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,aAAa,EACpB,gBAAgB,CAAC,EAAE,gBAAgB;IASpC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK3B,UAAU,IAAI,IAAI;IAMlB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAwF/B;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IA6BzB,OAAO,CAAC,qBAAqB;IAkC7B,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,WAAW;IA2KnB,OAAO,CAAC,kBAAkB;IAiG1B;;OAEG;IACH,OAAO,CAAC,UAAU;IAoDlB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAoDtB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAY3B;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAIpB;;;OAGG;IACH,OAAO,CAAC,WAAW;CAgLnB"}
|
|
@@ -1,6 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isImageLine } from "../terminal-image.js";
|
|
1
|
+
import { Marked, Tokenizer } from "marked";
|
|
2
|
+
import { getCapabilities, hyperlink, isImageLine } from "../terminal-image.js";
|
|
3
3
|
import { applyBackgroundToLine, visibleWidth, wrapTextWithAnsi } from "../utils.js";
|
|
4
|
+
const STRICT_STRIKETHROUGH_REGEX = /^(~~)(?=[^\s~])((?:\\.|[^\\])*?(?:\\.|[^\s~\\]))\1(?=[^~]|$)/;
|
|
5
|
+
class StrictStrikethroughTokenizer extends Tokenizer {
|
|
6
|
+
del(src) {
|
|
7
|
+
const match = STRICT_STRIKETHROUGH_REGEX.exec(src);
|
|
8
|
+
if (!match) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
const text = match[2];
|
|
12
|
+
return {
|
|
13
|
+
type: "del",
|
|
14
|
+
raw: match[0],
|
|
15
|
+
text,
|
|
16
|
+
tokens: this.lexer.inlineTokens(text),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const markdownParser = new Marked();
|
|
21
|
+
markdownParser.setOptions({
|
|
22
|
+
tokenizer: new StrictStrikethroughTokenizer(),
|
|
23
|
+
});
|
|
4
24
|
export class Markdown {
|
|
5
25
|
text;
|
|
6
26
|
paddingX; // Left/right padding
|
|
@@ -47,7 +67,7 @@ export class Markdown {
|
|
|
47
67
|
// Replace tabs with 3 spaces for consistent rendering
|
|
48
68
|
const normalizedText = this.text.replace(/\t/g, " ");
|
|
49
69
|
// Parse markdown to HTML-like tokens
|
|
50
|
-
const tokens =
|
|
70
|
+
const tokens = markdownParser.lexer(normalizedText);
|
|
51
71
|
// Convert tokens to styled terminal output
|
|
52
72
|
const renderedLines = [];
|
|
53
73
|
for (let i = 0; i < tokens.length; i++) {
|
|
@@ -172,31 +192,36 @@ export class Markdown {
|
|
|
172
192
|
stylePrefix: this.getDefaultStylePrefix(),
|
|
173
193
|
};
|
|
174
194
|
}
|
|
175
|
-
renderToken(token, width, nextTokenType) {
|
|
195
|
+
renderToken(token, width, nextTokenType, styleContext) {
|
|
176
196
|
const lines = [];
|
|
177
197
|
switch (token.type) {
|
|
178
198
|
case "heading": {
|
|
179
199
|
const headingLevel = token.depth;
|
|
180
200
|
const headingPrefix = `${"#".repeat(headingLevel)} `;
|
|
181
|
-
|
|
182
|
-
|
|
201
|
+
// Build a heading-specific style context so inline tokens (codespan, bold, etc.)
|
|
202
|
+
// restore heading styling after their own ANSI resets instead of falling back to
|
|
203
|
+
// the default text style.
|
|
204
|
+
let headingStyleFn;
|
|
183
205
|
if (headingLevel === 1) {
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
else if (headingLevel === 2) {
|
|
187
|
-
styledHeading = this.theme.heading(this.theme.bold(headingText));
|
|
206
|
+
headingStyleFn = (text) => this.theme.heading(this.theme.bold(this.theme.underline(text)));
|
|
188
207
|
}
|
|
189
208
|
else {
|
|
190
|
-
|
|
209
|
+
headingStyleFn = (text) => this.theme.heading(this.theme.bold(text));
|
|
191
210
|
}
|
|
211
|
+
const headingStyleContext = {
|
|
212
|
+
applyText: headingStyleFn,
|
|
213
|
+
stylePrefix: this.getStylePrefix(headingStyleFn),
|
|
214
|
+
};
|
|
215
|
+
const headingText = this.renderInlineTokens(token.tokens || [], headingStyleContext);
|
|
216
|
+
const styledHeading = headingLevel >= 3 ? headingStyleFn(headingPrefix) + headingText : headingText;
|
|
192
217
|
lines.push(styledHeading);
|
|
193
|
-
if (nextTokenType !== "space") {
|
|
218
|
+
if (nextTokenType && nextTokenType !== "space") {
|
|
194
219
|
lines.push(""); // Add spacing after headings (unless space token follows)
|
|
195
220
|
}
|
|
196
221
|
break;
|
|
197
222
|
}
|
|
198
223
|
case "paragraph": {
|
|
199
|
-
const paragraphText = this.renderInlineTokens(token.tokens || []);
|
|
224
|
+
const paragraphText = this.renderInlineTokens(token.tokens || [], styleContext);
|
|
200
225
|
lines.push(paragraphText);
|
|
201
226
|
// Don't add spacing if next token is space or list
|
|
202
227
|
if (nextTokenType && nextTokenType !== "list" && nextTokenType !== "space") {
|
|
@@ -221,48 +246,69 @@ export class Markdown {
|
|
|
221
246
|
}
|
|
222
247
|
}
|
|
223
248
|
lines.push(this.theme.codeBlockBorder("```"));
|
|
224
|
-
if (nextTokenType !== "space") {
|
|
249
|
+
if (nextTokenType && nextTokenType !== "space") {
|
|
225
250
|
lines.push(""); // Add spacing after code blocks (unless space token follows)
|
|
226
251
|
}
|
|
227
252
|
break;
|
|
228
253
|
}
|
|
229
254
|
case "list": {
|
|
230
|
-
const listLines = this.renderList(token, 0);
|
|
255
|
+
const listLines = this.renderList(token, 0, styleContext);
|
|
231
256
|
lines.push(...listLines);
|
|
232
257
|
// Don't add spacing after lists if a space token follows
|
|
233
258
|
// (the space token will handle it)
|
|
234
259
|
break;
|
|
235
260
|
}
|
|
236
261
|
case "table": {
|
|
237
|
-
const tableLines = this.renderTable(token, width);
|
|
262
|
+
const tableLines = this.renderTable(token, width, nextTokenType, styleContext);
|
|
238
263
|
lines.push(...tableLines);
|
|
239
264
|
break;
|
|
240
265
|
}
|
|
241
266
|
case "blockquote": {
|
|
242
267
|
const quoteStyle = (text) => this.theme.quote(this.theme.italic(text));
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
268
|
+
const quoteStylePrefix = this.getStylePrefix(quoteStyle);
|
|
269
|
+
const applyQuoteStyle = (line) => {
|
|
270
|
+
if (!quoteStylePrefix) {
|
|
271
|
+
return quoteStyle(line);
|
|
272
|
+
}
|
|
273
|
+
const lineWithReappliedStyle = line.replace(/\x1b\[0m/g, `\x1b[0m${quoteStylePrefix}`);
|
|
274
|
+
return quoteStyle(lineWithReappliedStyle);
|
|
246
275
|
};
|
|
247
|
-
const quoteText = this.renderInlineTokens(token.tokens || [], quoteStyleContext);
|
|
248
|
-
const quoteLines = quoteText.split("\n");
|
|
249
276
|
// Calculate available width for quote content (subtract border "│ " = 2 chars)
|
|
250
277
|
const quoteContentWidth = Math.max(1, width - 2);
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
278
|
+
// Blockquotes contain block-level tokens (paragraph, list, code, etc.), so render
|
|
279
|
+
// children with renderToken() instead of renderInlineTokens().
|
|
280
|
+
// Default message style should not apply inside blockquotes.
|
|
281
|
+
const quoteInlineStyleContext = {
|
|
282
|
+
applyText: (text) => text,
|
|
283
|
+
stylePrefix: quoteStylePrefix,
|
|
284
|
+
};
|
|
285
|
+
const quoteTokens = token.tokens || [];
|
|
286
|
+
const renderedQuoteLines = [];
|
|
287
|
+
for (let i = 0; i < quoteTokens.length; i++) {
|
|
288
|
+
const quoteToken = quoteTokens[i];
|
|
289
|
+
const nextQuoteToken = quoteTokens[i + 1];
|
|
290
|
+
renderedQuoteLines.push(...this.renderToken(quoteToken, quoteContentWidth, nextQuoteToken?.type, quoteInlineStyleContext));
|
|
291
|
+
}
|
|
292
|
+
// Avoid rendering an extra empty quote line before the outer blockquote spacing.
|
|
293
|
+
while (renderedQuoteLines.length > 0 &&
|
|
294
|
+
renderedQuoteLines[renderedQuoteLines.length - 1] === "") {
|
|
295
|
+
renderedQuoteLines.pop();
|
|
296
|
+
}
|
|
297
|
+
for (const quoteLine of renderedQuoteLines) {
|
|
298
|
+
const styledLine = applyQuoteStyle(quoteLine);
|
|
299
|
+
const wrappedLines = wrapTextWithAnsi(styledLine, quoteContentWidth);
|
|
254
300
|
for (const wrappedLine of wrappedLines) {
|
|
255
301
|
lines.push(this.theme.quoteBorder("│ ") + wrappedLine);
|
|
256
302
|
}
|
|
257
303
|
}
|
|
258
|
-
if (nextTokenType !== "space") {
|
|
304
|
+
if (nextTokenType && nextTokenType !== "space") {
|
|
259
305
|
lines.push(""); // Add spacing after blockquotes (unless space token follows)
|
|
260
306
|
}
|
|
261
307
|
break;
|
|
262
308
|
}
|
|
263
309
|
case "hr":
|
|
264
310
|
lines.push(this.theme.hr("─".repeat(Math.min(width, 80))));
|
|
265
|
-
if (nextTokenType !== "space") {
|
|
311
|
+
if (nextTokenType && nextTokenType !== "space") {
|
|
266
312
|
lines.push(""); // Add spacing after horizontal rules (unless space token follows)
|
|
267
313
|
}
|
|
268
314
|
break;
|
|
@@ -322,21 +368,26 @@ export class Markdown {
|
|
|
322
368
|
break;
|
|
323
369
|
case "link": {
|
|
324
370
|
const linkText = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
? token.href.slice(7)
|
|
331
|
-
: token.href;
|
|
332
|
-
if (token.text === token.href || token.text === hrefForComparison) {
|
|
333
|
-
result += this.theme.link(this.theme.underline(linkText)) + stylePrefix;
|
|
371
|
+
const styledLink = this.theme.link(this.theme.underline(linkText));
|
|
372
|
+
if (getCapabilities().hyperlinks) {
|
|
373
|
+
// OSC 8: render as a clickable hyperlink. The URL is not printed inline,
|
|
374
|
+
// so we always show only the link text regardless of whether it matches href.
|
|
375
|
+
result += hyperlink(styledLink, token.href) + stylePrefix;
|
|
334
376
|
}
|
|
335
377
|
else {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
378
|
+
// Fallback: print URL in parentheses when text differs from href.
|
|
379
|
+
// Compare raw token.text (not styled) against href for the equality check.
|
|
380
|
+
// For mailto: links strip the prefix (autolinked emails use text="foo@bar.com"
|
|
381
|
+
// but href="mailto:foo@bar.com").
|
|
382
|
+
const hrefForComparison = token.href.startsWith("mailto:")
|
|
383
|
+
? token.href.slice(7)
|
|
384
|
+
: token.href;
|
|
385
|
+
if (token.text === token.href || token.text === hrefForComparison) {
|
|
386
|
+
result += styledLink + stylePrefix;
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
result += styledLink + this.theme.linkUrl(` (${token.href})`) + stylePrefix;
|
|
390
|
+
}
|
|
340
391
|
}
|
|
341
392
|
break;
|
|
342
393
|
}
|
|
@@ -361,12 +412,15 @@ export class Markdown {
|
|
|
361
412
|
}
|
|
362
413
|
}
|
|
363
414
|
}
|
|
415
|
+
while (stylePrefix && result.endsWith(stylePrefix)) {
|
|
416
|
+
result = result.slice(0, -stylePrefix.length);
|
|
417
|
+
}
|
|
364
418
|
return result;
|
|
365
419
|
}
|
|
366
420
|
/**
|
|
367
421
|
* Render a list with proper nesting support
|
|
368
422
|
*/
|
|
369
|
-
renderList(token, depth) {
|
|
423
|
+
renderList(token, depth, styleContext) {
|
|
370
424
|
const lines = [];
|
|
371
425
|
const indent = " ".repeat(depth);
|
|
372
426
|
// Use the list's start property (defaults to 1 for ordered lists)
|
|
@@ -375,7 +429,7 @@ export class Markdown {
|
|
|
375
429
|
const item = token.items[i];
|
|
376
430
|
const bullet = token.ordered ? `${startNumber + i}. ` : "- ";
|
|
377
431
|
// Process item tokens to handle nested lists
|
|
378
|
-
const itemLines = this.renderListItem(item.tokens || [], depth);
|
|
432
|
+
const itemLines = this.renderListItem(item.tokens || [], depth, styleContext);
|
|
379
433
|
if (itemLines.length > 0) {
|
|
380
434
|
// First line - check if it's a nested list
|
|
381
435
|
// A nested list will start with indent (spaces) followed by cyan bullet
|
|
@@ -413,25 +467,25 @@ export class Markdown {
|
|
|
413
467
|
* Render list item tokens, handling nested lists
|
|
414
468
|
* Returns lines WITHOUT the parent indent (renderList will add it)
|
|
415
469
|
*/
|
|
416
|
-
renderListItem(tokens, parentDepth) {
|
|
470
|
+
renderListItem(tokens, parentDepth, styleContext) {
|
|
417
471
|
const lines = [];
|
|
418
472
|
for (const token of tokens) {
|
|
419
473
|
if (token.type === "list") {
|
|
420
474
|
// Nested list - render with one additional indent level
|
|
421
475
|
// These lines will have their own indent, so we just add them as-is
|
|
422
|
-
const nestedLines = this.renderList(token, parentDepth + 1);
|
|
476
|
+
const nestedLines = this.renderList(token, parentDepth + 1, styleContext);
|
|
423
477
|
lines.push(...nestedLines);
|
|
424
478
|
}
|
|
425
479
|
else if (token.type === "text") {
|
|
426
480
|
// Text content (may have inline tokens)
|
|
427
481
|
const text = token.tokens && token.tokens.length > 0
|
|
428
|
-
? this.renderInlineTokens(token.tokens)
|
|
482
|
+
? this.renderInlineTokens(token.tokens, styleContext)
|
|
429
483
|
: token.text || "";
|
|
430
484
|
lines.push(text);
|
|
431
485
|
}
|
|
432
486
|
else if (token.type === "paragraph") {
|
|
433
487
|
// Paragraph in list item
|
|
434
|
-
const text = this.renderInlineTokens(token.tokens || []);
|
|
488
|
+
const text = this.renderInlineTokens(token.tokens || [], styleContext);
|
|
435
489
|
lines.push(text);
|
|
436
490
|
}
|
|
437
491
|
else if (token.type === "code") {
|
|
@@ -454,7 +508,7 @@ export class Markdown {
|
|
|
454
508
|
}
|
|
455
509
|
else {
|
|
456
510
|
// Other token types - try to render as inline
|
|
457
|
-
const text = this.renderInlineTokens([token]);
|
|
511
|
+
const text = this.renderInlineTokens([token], styleContext);
|
|
458
512
|
if (text) {
|
|
459
513
|
lines.push(text);
|
|
460
514
|
}
|
|
@@ -489,7 +543,7 @@ export class Markdown {
|
|
|
489
543
|
* Render a table with width-aware cell wrapping.
|
|
490
544
|
* Cells that don't fit are wrapped to multiple lines.
|
|
491
545
|
*/
|
|
492
|
-
renderTable(token, availableWidth) {
|
|
546
|
+
renderTable(token, availableWidth, nextTokenType, styleContext) {
|
|
493
547
|
const lines = [];
|
|
494
548
|
const numCols = token.header.length;
|
|
495
549
|
if (numCols === 0) {
|
|
@@ -502,7 +556,9 @@ export class Markdown {
|
|
|
502
556
|
if (availableForCells < numCols) {
|
|
503
557
|
// Too narrow to render a stable table. Fall back to raw markdown.
|
|
504
558
|
const fallbackLines = token.raw ? wrapTextWithAnsi(token.raw, availableWidth) : [];
|
|
505
|
-
|
|
559
|
+
if (nextTokenType && nextTokenType !== "space") {
|
|
560
|
+
fallbackLines.push("");
|
|
561
|
+
}
|
|
506
562
|
return fallbackLines;
|
|
507
563
|
}
|
|
508
564
|
const maxUnbrokenWordWidth = 30;
|
|
@@ -510,13 +566,13 @@ export class Markdown {
|
|
|
510
566
|
const naturalWidths = [];
|
|
511
567
|
const minWordWidths = [];
|
|
512
568
|
for (let i = 0; i < numCols; i++) {
|
|
513
|
-
const headerText = this.renderInlineTokens(token.header[i].tokens || []);
|
|
569
|
+
const headerText = this.renderInlineTokens(token.header[i].tokens || [], styleContext);
|
|
514
570
|
naturalWidths[i] = visibleWidth(headerText);
|
|
515
571
|
minWordWidths[i] = Math.max(1, this.getLongestWordWidth(headerText, maxUnbrokenWordWidth));
|
|
516
572
|
}
|
|
517
573
|
for (const row of token.rows) {
|
|
518
574
|
for (let i = 0; i < row.length; i++) {
|
|
519
|
-
const cellText = this.renderInlineTokens(row[i].tokens || []);
|
|
575
|
+
const cellText = this.renderInlineTokens(row[i].tokens || [], styleContext);
|
|
520
576
|
naturalWidths[i] = Math.max(naturalWidths[i] || 0, visibleWidth(cellText));
|
|
521
577
|
minWordWidths[i] = Math.max(minWordWidths[i] || 1, this.getLongestWordWidth(cellText, maxUnbrokenWordWidth));
|
|
522
578
|
}
|
|
@@ -588,7 +644,7 @@ export class Markdown {
|
|
|
588
644
|
lines.push(`┌─${topBorderCells.join("─┬─")}─┐`);
|
|
589
645
|
// Render header with wrapping
|
|
590
646
|
const headerCellLines = token.header.map((cell, i) => {
|
|
591
|
-
const text = this.renderInlineTokens(cell.tokens || []);
|
|
647
|
+
const text = this.renderInlineTokens(cell.tokens || [], styleContext);
|
|
592
648
|
return this.wrapCellText(text, columnWidths[i]);
|
|
593
649
|
});
|
|
594
650
|
const headerLineCount = Math.max(...headerCellLines.map((c) => c.length));
|
|
@@ -608,7 +664,7 @@ export class Markdown {
|
|
|
608
664
|
for (let rowIndex = 0; rowIndex < token.rows.length; rowIndex++) {
|
|
609
665
|
const row = token.rows[rowIndex];
|
|
610
666
|
const rowCellLines = row.map((cell, i) => {
|
|
611
|
-
const text = this.renderInlineTokens(cell.tokens || []);
|
|
667
|
+
const text = this.renderInlineTokens(cell.tokens || [], styleContext);
|
|
612
668
|
return this.wrapCellText(text, columnWidths[i]);
|
|
613
669
|
});
|
|
614
670
|
const rowLineCount = Math.max(...rowCellLines.map((c) => c.length));
|
|
@@ -626,7 +682,9 @@ export class Markdown {
|
|
|
626
682
|
// Render bottom border
|
|
627
683
|
const bottomBorderCells = columnWidths.map((w) => "─".repeat(w));
|
|
628
684
|
lines.push(`└─${bottomBorderCells.join("─┴─")}─┘`);
|
|
629
|
-
|
|
685
|
+
if (nextTokenType && nextTokenType !== "space") {
|
|
686
|
+
lines.push(""); // Add spacing after table
|
|
687
|
+
}
|
|
630
688
|
return lines;
|
|
631
689
|
}
|
|
632
690
|
}
|