@dungle-scrubs/tallow 0.9.4 → 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 -12
- package/dist/interactive-mode-patch.d.ts.map +1 -1
- package/dist/interactive-mode-patch.js +229 -146
- 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 +4 -5
- 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/terminal-links.ts +22 -0
- package/extensions/ask-user-question-tool/index.ts +0 -3
- package/extensions/clear/__tests__/clear.test.ts +269 -2
- 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/random-spinner/index.ts +7 -642
- package/extensions/read-tool-enhanced/index.ts +6 -8
- package/extensions/render-stabilizer/__tests__/render-stabilizer.test.ts +2 -3
- package/extensions/render-stabilizer/index.ts +6 -6
- 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/model-resolver.ts +274 -7
- package/extensions/tasks/commands/register-tasks-extension.ts +9 -9
- package/extensions/teams-tool/tools/register-extension.ts +1 -3
- package/extensions/web-search-tool/index.ts +2 -1
- 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 +1 -25
- 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 +13 -50
- 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 +12 -51
- 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/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 -81
- 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,8 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getKeybindings } from "../keybindings.js";
|
|
2
2
|
import type { Component } from "../tui.js";
|
|
3
|
-
import { truncateToWidth } from "../utils.js";
|
|
3
|
+
import { truncateToWidth, visibleWidth } from "../utils.js";
|
|
4
|
+
|
|
5
|
+
const DEFAULT_PRIMARY_COLUMN_WIDTH = 32;
|
|
6
|
+
const PRIMARY_COLUMN_GAP = 2;
|
|
7
|
+
const MIN_DESCRIPTION_WIDTH = 10;
|
|
4
8
|
|
|
5
9
|
const normalizeToSingleLine = (text: string): string => text.replace(/[\r\n]+/g, " ").trim();
|
|
10
|
+
const clamp = (value: number, min: number, max: number): number =>
|
|
11
|
+
Math.max(min, Math.min(value, max));
|
|
6
12
|
|
|
7
13
|
export interface SelectItem {
|
|
8
14
|
value: string;
|
|
@@ -18,22 +24,43 @@ export interface SelectListTheme {
|
|
|
18
24
|
noMatch: (text: string) => string;
|
|
19
25
|
}
|
|
20
26
|
|
|
27
|
+
export interface SelectListTruncatePrimaryContext {
|
|
28
|
+
text: string;
|
|
29
|
+
maxWidth: number;
|
|
30
|
+
columnWidth: number;
|
|
31
|
+
item: SelectItem;
|
|
32
|
+
isSelected: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface SelectListLayoutOptions {
|
|
36
|
+
minPrimaryColumnWidth?: number;
|
|
37
|
+
maxPrimaryColumnWidth?: number;
|
|
38
|
+
truncatePrimary?: (context: SelectListTruncatePrimaryContext) => string;
|
|
39
|
+
}
|
|
40
|
+
|
|
21
41
|
export class SelectList implements Component {
|
|
22
42
|
private items: SelectItem[] = [];
|
|
23
43
|
private filteredItems: SelectItem[] = [];
|
|
24
44
|
private selectedIndex: number = 0;
|
|
25
45
|
private maxVisible: number = 5;
|
|
26
46
|
private theme: SelectListTheme;
|
|
47
|
+
private layout: SelectListLayoutOptions;
|
|
27
48
|
|
|
28
49
|
public onSelect?: (item: SelectItem) => void;
|
|
29
50
|
public onCancel?: () => void;
|
|
30
51
|
public onSelectionChange?: (item: SelectItem) => void;
|
|
31
52
|
|
|
32
|
-
constructor(
|
|
53
|
+
constructor(
|
|
54
|
+
items: SelectItem[],
|
|
55
|
+
maxVisible: number,
|
|
56
|
+
theme: SelectListTheme,
|
|
57
|
+
layout: SelectListLayoutOptions = {}
|
|
58
|
+
) {
|
|
33
59
|
this.items = items;
|
|
34
60
|
this.filteredItems = items;
|
|
35
61
|
this.maxVisible = maxVisible;
|
|
36
62
|
this.theme = theme;
|
|
63
|
+
this.layout = layout;
|
|
37
64
|
}
|
|
38
65
|
|
|
39
66
|
setFilter(filter: string): void {
|
|
@@ -61,6 +88,8 @@ export class SelectList implements Component {
|
|
|
61
88
|
return lines;
|
|
62
89
|
}
|
|
63
90
|
|
|
91
|
+
const primaryColumnWidth = this.getPrimaryColumnWidth();
|
|
92
|
+
|
|
64
93
|
// Calculate visible range with scrolling
|
|
65
94
|
const startIndex = Math.max(
|
|
66
95
|
0,
|
|
@@ -80,68 +109,9 @@ export class SelectList implements Component {
|
|
|
80
109
|
const descriptionSingleLine = item.description
|
|
81
110
|
? normalizeToSingleLine(item.description)
|
|
82
111
|
: undefined;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// Use arrow indicator for selection - entire line uses selectedText color
|
|
87
|
-
const prefixWidth = 2; // "↗ " is 2 characters visually
|
|
88
|
-
const displayValue = item.label || item.value;
|
|
89
|
-
|
|
90
|
-
if (descriptionSingleLine && width > 40) {
|
|
91
|
-
// Calculate how much space we have for value + description
|
|
92
|
-
const maxValueWidth = Math.min(30, width - prefixWidth - 4);
|
|
93
|
-
const truncatedValue = truncateToWidth(displayValue, maxValueWidth, "");
|
|
94
|
-
const spacing = " ".repeat(Math.max(1, 32 - truncatedValue.length));
|
|
95
|
-
|
|
96
|
-
// Calculate remaining space for description using visible widths
|
|
97
|
-
const descriptionStart = prefixWidth + truncatedValue.length + spacing.length;
|
|
98
|
-
const remainingWidth = width - descriptionStart - 2; // -2 for safety
|
|
99
|
-
|
|
100
|
-
if (remainingWidth > 10) {
|
|
101
|
-
const truncatedDesc = truncateToWidth(descriptionSingleLine, remainingWidth, "");
|
|
102
|
-
// Apply selectedText to entire line content
|
|
103
|
-
line = this.theme.selectedText(`↗ ${truncatedValue}${spacing}${truncatedDesc}`);
|
|
104
|
-
} else {
|
|
105
|
-
// Not enough space for description
|
|
106
|
-
const maxWidth = width - prefixWidth - 2;
|
|
107
|
-
line = this.theme.selectedText(`↗ ${truncateToWidth(displayValue, maxWidth, "")}`);
|
|
108
|
-
}
|
|
109
|
-
} else {
|
|
110
|
-
// No description or not enough width
|
|
111
|
-
const maxWidth = width - prefixWidth - 2;
|
|
112
|
-
line = this.theme.selectedText(`↗ ${truncateToWidth(displayValue, maxWidth, "")}`);
|
|
113
|
-
}
|
|
114
|
-
} else {
|
|
115
|
-
const displayValue = item.label || item.value;
|
|
116
|
-
const prefix = " ";
|
|
117
|
-
|
|
118
|
-
if (descriptionSingleLine && width > 40) {
|
|
119
|
-
// Calculate how much space we have for value + description
|
|
120
|
-
const maxValueWidth = Math.min(30, width - prefix.length - 4);
|
|
121
|
-
const truncatedValue = truncateToWidth(displayValue, maxValueWidth, "");
|
|
122
|
-
const spacing = " ".repeat(Math.max(1, 32 - truncatedValue.length));
|
|
123
|
-
|
|
124
|
-
// Calculate remaining space for description
|
|
125
|
-
const descriptionStart = prefix.length + truncatedValue.length + spacing.length;
|
|
126
|
-
const remainingWidth = width - descriptionStart - 2; // -2 for safety
|
|
127
|
-
|
|
128
|
-
if (remainingWidth > 10) {
|
|
129
|
-
const truncatedDesc = truncateToWidth(descriptionSingleLine, remainingWidth, "");
|
|
130
|
-
const descText = this.theme.description(spacing + truncatedDesc);
|
|
131
|
-
line = prefix + truncatedValue + descText;
|
|
132
|
-
} else {
|
|
133
|
-
// Not enough space for description
|
|
134
|
-
const maxWidth = width - prefix.length - 2;
|
|
135
|
-
line = prefix + truncateToWidth(displayValue, maxWidth, "");
|
|
136
|
-
}
|
|
137
|
-
} else {
|
|
138
|
-
// No description or not enough width
|
|
139
|
-
const maxWidth = width - prefix.length - 2;
|
|
140
|
-
line = prefix + truncateToWidth(displayValue, maxWidth, "");
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
lines.push(line);
|
|
112
|
+
lines.push(
|
|
113
|
+
this.renderItem(item, isSelected, width, descriptionSingleLine, primaryColumnWidth)
|
|
114
|
+
);
|
|
145
115
|
}
|
|
146
116
|
|
|
147
117
|
// Add scroll indicators if needed
|
|
@@ -155,34 +125,130 @@ export class SelectList implements Component {
|
|
|
155
125
|
}
|
|
156
126
|
|
|
157
127
|
handleInput(keyData: string): void {
|
|
158
|
-
const kb =
|
|
128
|
+
const kb = getKeybindings();
|
|
159
129
|
// Up arrow - wrap to bottom when at top
|
|
160
|
-
if (kb.matches(keyData, "
|
|
130
|
+
if (kb.matches(keyData, "tui.select.up")) {
|
|
161
131
|
this.selectedIndex =
|
|
162
132
|
this.selectedIndex === 0 ? this.filteredItems.length - 1 : this.selectedIndex - 1;
|
|
163
133
|
this.notifySelectionChange();
|
|
164
134
|
}
|
|
165
135
|
// Down arrow - wrap to top when at bottom
|
|
166
|
-
else if (kb.matches(keyData, "
|
|
136
|
+
else if (kb.matches(keyData, "tui.select.down")) {
|
|
167
137
|
this.selectedIndex =
|
|
168
138
|
this.selectedIndex === this.filteredItems.length - 1 ? 0 : this.selectedIndex + 1;
|
|
169
139
|
this.notifySelectionChange();
|
|
170
140
|
}
|
|
171
141
|
// Enter
|
|
172
|
-
else if (kb.matches(keyData, "
|
|
142
|
+
else if (kb.matches(keyData, "tui.select.confirm")) {
|
|
173
143
|
const selectedItem = this.filteredItems[this.selectedIndex];
|
|
174
144
|
if (selectedItem && this.onSelect) {
|
|
175
145
|
this.onSelect(selectedItem);
|
|
176
146
|
}
|
|
177
147
|
}
|
|
178
148
|
// Escape or Ctrl+C
|
|
179
|
-
else if (kb.matches(keyData, "
|
|
149
|
+
else if (kb.matches(keyData, "tui.select.cancel")) {
|
|
180
150
|
if (this.onCancel) {
|
|
181
151
|
this.onCancel();
|
|
182
152
|
}
|
|
183
153
|
}
|
|
184
154
|
}
|
|
185
155
|
|
|
156
|
+
private renderItem(
|
|
157
|
+
item: SelectItem,
|
|
158
|
+
isSelected: boolean,
|
|
159
|
+
width: number,
|
|
160
|
+
descriptionSingleLine: string | undefined,
|
|
161
|
+
primaryColumnWidth: number
|
|
162
|
+
): string {
|
|
163
|
+
const prefix = isSelected ? "→ " : " ";
|
|
164
|
+
const prefixWidth = visibleWidth(prefix);
|
|
165
|
+
|
|
166
|
+
if (descriptionSingleLine && width > 40) {
|
|
167
|
+
const effectivePrimaryColumnWidth = Math.max(
|
|
168
|
+
1,
|
|
169
|
+
Math.min(primaryColumnWidth, width - prefixWidth - 4)
|
|
170
|
+
);
|
|
171
|
+
const maxPrimaryWidth = Math.max(1, effectivePrimaryColumnWidth - PRIMARY_COLUMN_GAP);
|
|
172
|
+
const truncatedValue = this.truncatePrimary(
|
|
173
|
+
item,
|
|
174
|
+
isSelected,
|
|
175
|
+
maxPrimaryWidth,
|
|
176
|
+
effectivePrimaryColumnWidth
|
|
177
|
+
);
|
|
178
|
+
const truncatedValueWidth = visibleWidth(truncatedValue);
|
|
179
|
+
const spacing = " ".repeat(Math.max(1, effectivePrimaryColumnWidth - truncatedValueWidth));
|
|
180
|
+
const descriptionStart = prefixWidth + truncatedValueWidth + spacing.length;
|
|
181
|
+
const remainingWidth = width - descriptionStart - 2; // -2 for safety
|
|
182
|
+
|
|
183
|
+
if (remainingWidth > MIN_DESCRIPTION_WIDTH) {
|
|
184
|
+
const truncatedDesc = truncateToWidth(descriptionSingleLine, remainingWidth, "");
|
|
185
|
+
if (isSelected) {
|
|
186
|
+
return this.theme.selectedText(`${prefix}${truncatedValue}${spacing}${truncatedDesc}`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const descText = this.theme.description(spacing + truncatedDesc);
|
|
190
|
+
return prefix + truncatedValue + descText;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const maxWidth = width - prefixWidth - 2;
|
|
195
|
+
const truncatedValue = this.truncatePrimary(item, isSelected, maxWidth, maxWidth);
|
|
196
|
+
if (isSelected) {
|
|
197
|
+
return this.theme.selectedText(`${prefix}${truncatedValue}`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return prefix + truncatedValue;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
private getPrimaryColumnWidth(): number {
|
|
204
|
+
const { min, max } = this.getPrimaryColumnBounds();
|
|
205
|
+
const widestPrimary = this.filteredItems.reduce((widest, item) => {
|
|
206
|
+
return Math.max(widest, visibleWidth(this.getDisplayValue(item)) + PRIMARY_COLUMN_GAP);
|
|
207
|
+
}, 0);
|
|
208
|
+
|
|
209
|
+
return clamp(widestPrimary, min, max);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private getPrimaryColumnBounds(): { min: number; max: number } {
|
|
213
|
+
const rawMin =
|
|
214
|
+
this.layout.minPrimaryColumnWidth ??
|
|
215
|
+
this.layout.maxPrimaryColumnWidth ??
|
|
216
|
+
DEFAULT_PRIMARY_COLUMN_WIDTH;
|
|
217
|
+
const rawMax =
|
|
218
|
+
this.layout.maxPrimaryColumnWidth ??
|
|
219
|
+
this.layout.minPrimaryColumnWidth ??
|
|
220
|
+
DEFAULT_PRIMARY_COLUMN_WIDTH;
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
min: Math.max(1, Math.min(rawMin, rawMax)),
|
|
224
|
+
max: Math.max(1, Math.max(rawMin, rawMax)),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private truncatePrimary(
|
|
229
|
+
item: SelectItem,
|
|
230
|
+
isSelected: boolean,
|
|
231
|
+
maxWidth: number,
|
|
232
|
+
columnWidth: number
|
|
233
|
+
): string {
|
|
234
|
+
const displayValue = this.getDisplayValue(item);
|
|
235
|
+
const truncatedValue = this.layout.truncatePrimary
|
|
236
|
+
? this.layout.truncatePrimary({
|
|
237
|
+
text: displayValue,
|
|
238
|
+
maxWidth,
|
|
239
|
+
columnWidth,
|
|
240
|
+
item,
|
|
241
|
+
isSelected,
|
|
242
|
+
})
|
|
243
|
+
: truncateToWidth(displayValue, maxWidth, "");
|
|
244
|
+
|
|
245
|
+
return truncateToWidth(truncatedValue, maxWidth, "");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private getDisplayValue(item: SelectItem): string {
|
|
249
|
+
return item.label || item.value;
|
|
250
|
+
}
|
|
251
|
+
|
|
186
252
|
private notifySelectionChange(): void {
|
|
187
253
|
const selectedItem = this.filteredItems[this.selectedIndex];
|
|
188
254
|
if (selectedItem && this.onSelectionChange) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { fuzzyFilter } from "../fuzzy.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getKeybindings } from "../keybindings.js";
|
|
3
3
|
import type { Component } from "../tui.js";
|
|
4
4
|
import { truncateToWidth, visibleWidth, wrapTextWithAnsi } from "../utils.js";
|
|
5
5
|
import { Input } from "./input.js";
|
|
@@ -45,9 +45,6 @@ export class SettingsList implements Component {
|
|
|
45
45
|
// Submenu state
|
|
46
46
|
private submenuComponent: Component | null = null;
|
|
47
47
|
private submenuItemIndex: number | null = null;
|
|
48
|
-
private lastRenderLineCount = 0;
|
|
49
|
-
private nextMinLineCount = 0;
|
|
50
|
-
private layoutTransitionCallback?: () => void;
|
|
51
48
|
|
|
52
49
|
constructor(
|
|
53
50
|
items: SettingItem[],
|
|
@@ -69,13 +66,7 @@ export class SettingsList implements Component {
|
|
|
69
66
|
}
|
|
70
67
|
}
|
|
71
68
|
|
|
72
|
-
/**
|
|
73
|
-
* Update an item's current value.
|
|
74
|
-
*
|
|
75
|
-
* @param id - Setting identifier
|
|
76
|
-
* @param newValue - New value to display
|
|
77
|
-
* @returns Nothing
|
|
78
|
-
*/
|
|
69
|
+
/** Update an item's currentValue */
|
|
79
70
|
updateValue(id: string, newValue: string): void {
|
|
80
71
|
const item = this.items.find((i) => i.id === id);
|
|
81
72
|
if (item) {
|
|
@@ -83,35 +74,17 @@ export class SettingsList implements Component {
|
|
|
83
74
|
}
|
|
84
75
|
}
|
|
85
76
|
|
|
86
|
-
/**
|
|
87
|
-
* Set a callback fired before submenu-driven layout transitions.
|
|
88
|
-
*
|
|
89
|
-
* Callers can use this to reset TUI render-grace state before the settings
|
|
90
|
-
* list expands into, or collapses out of, a submenu.
|
|
91
|
-
*
|
|
92
|
-
* @param callback - Transition callback, or undefined to clear it
|
|
93
|
-
* @returns Nothing
|
|
94
|
-
*/
|
|
95
|
-
setLayoutTransitionCallback(callback?: () => void): void {
|
|
96
|
-
this.layoutTransitionCallback = callback;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
77
|
invalidate(): void {
|
|
100
78
|
this.submenuComponent?.invalidate?.();
|
|
101
79
|
}
|
|
102
80
|
|
|
103
81
|
render(width: number): string[] {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (this.nextMinLineCount > lines.length) {
|
|
109
|
-
lines.push(...Array.from({ length: this.nextMinLineCount - lines.length }, () => ""));
|
|
82
|
+
// If submenu is active, render it instead
|
|
83
|
+
if (this.submenuComponent) {
|
|
84
|
+
return this.submenuComponent.render(width);
|
|
110
85
|
}
|
|
111
86
|
|
|
112
|
-
this.
|
|
113
|
-
this.lastRenderLineCount = lines.length;
|
|
114
|
-
return lines;
|
|
87
|
+
return this.renderMainList(width);
|
|
115
88
|
}
|
|
116
89
|
|
|
117
90
|
private renderMainList(width: number): string[] {
|
|
@@ -211,19 +184,19 @@ export class SettingsList implements Component {
|
|
|
211
184
|
}
|
|
212
185
|
|
|
213
186
|
// Main list input handling
|
|
214
|
-
const kb =
|
|
187
|
+
const kb = getKeybindings();
|
|
215
188
|
const displayItems = this.searchEnabled ? this.filteredItems : this.items;
|
|
216
|
-
if (kb.matches(data, "
|
|
189
|
+
if (kb.matches(data, "tui.select.up")) {
|
|
217
190
|
if (displayItems.length === 0) return;
|
|
218
191
|
this.selectedIndex =
|
|
219
192
|
this.selectedIndex === 0 ? displayItems.length - 1 : this.selectedIndex - 1;
|
|
220
|
-
} else if (kb.matches(data, "
|
|
193
|
+
} else if (kb.matches(data, "tui.select.down")) {
|
|
221
194
|
if (displayItems.length === 0) return;
|
|
222
195
|
this.selectedIndex =
|
|
223
196
|
this.selectedIndex === displayItems.length - 1 ? 0 : this.selectedIndex + 1;
|
|
224
|
-
} else if (kb.matches(data, "
|
|
197
|
+
} else if (kb.matches(data, "tui.select.confirm") || data === " ") {
|
|
225
198
|
this.activateItem();
|
|
226
|
-
} else if (kb.matches(data, "
|
|
199
|
+
} else if (kb.matches(data, "tui.select.cancel")) {
|
|
227
200
|
this.onCancel();
|
|
228
201
|
} else if (this.searchEnabled && this.searchInput) {
|
|
229
202
|
const sanitized = data.replace(/ /g, "");
|
|
@@ -242,10 +215,7 @@ export class SettingsList implements Component {
|
|
|
242
215
|
if (!item) return;
|
|
243
216
|
|
|
244
217
|
if (item.submenu) {
|
|
245
|
-
//
|
|
246
|
-
// the editor→submenu swap as a destructive shrink/expand transition.
|
|
247
|
-
this.nextMinLineCount = this.lastRenderLineCount;
|
|
248
|
-
this.layoutTransitionCallback?.();
|
|
218
|
+
// Open submenu, passing current value so it can pre-select correctly
|
|
249
219
|
this.submenuItemIndex = this.selectedIndex;
|
|
250
220
|
this.submenuComponent = item.submenu(item.currentValue, (selectedValue?: string) => {
|
|
251
221
|
if (selectedValue !== undefined) {
|
|
@@ -264,16 +234,7 @@ export class SettingsList implements Component {
|
|
|
264
234
|
}
|
|
265
235
|
}
|
|
266
236
|
|
|
267
|
-
/**
|
|
268
|
-
* Close the active submenu and restore the main settings list.
|
|
269
|
-
*
|
|
270
|
-
* @returns Nothing
|
|
271
|
-
*/
|
|
272
237
|
private closeSubmenu(): void {
|
|
273
|
-
// Preserve one frame of the submenu height so the transition back to the
|
|
274
|
-
// main settings list doesn't trigger a screen-clearing shrink redraw.
|
|
275
|
-
this.nextMinLineCount = this.lastRenderLineCount;
|
|
276
|
-
this.layoutTransitionCallback?.();
|
|
277
238
|
this.submenuComponent = null;
|
|
278
239
|
// Restore selection to the item that opened the submenu
|
|
279
240
|
if (this.submenuItemIndex !== null) {
|
|
@@ -4,33 +4,25 @@
|
|
|
4
4
|
export {
|
|
5
5
|
type AutocompleteItem,
|
|
6
6
|
type AutocompleteProvider,
|
|
7
|
+
type AutocompleteSuggestions,
|
|
7
8
|
CombinedAutocompleteProvider,
|
|
8
9
|
type SlashCommand,
|
|
9
10
|
} from "./autocomplete.js";
|
|
10
|
-
// Border styles
|
|
11
|
-
export {
|
|
12
|
-
type BorderStyle,
|
|
13
|
-
defaultBorderStyle,
|
|
14
|
-
FLAT,
|
|
15
|
-
ROUNDED,
|
|
16
|
-
SHARP,
|
|
17
|
-
setDefaultBorderStyle,
|
|
18
|
-
} from "./border-styles.js";
|
|
19
11
|
// Components
|
|
20
|
-
export { BorderedBox, type BorderedBoxOptions } from "./components/bordered-box.js";
|
|
21
12
|
export { Box } from "./components/box.js";
|
|
22
13
|
export { CancellableLoader } from "./components/cancellable-loader.js";
|
|
23
14
|
export { Editor, type EditorOptions, type EditorTheme } from "./components/editor.js";
|
|
24
|
-
export {
|
|
25
|
-
Image,
|
|
26
|
-
type ImageOptions,
|
|
27
|
-
type ImageTheme,
|
|
28
|
-
setNextImageFilePath,
|
|
29
|
-
} from "./components/image.js";
|
|
15
|
+
export { Image, type ImageOptions, type ImageTheme } from "./components/image.js";
|
|
30
16
|
export { Input } from "./components/input.js";
|
|
31
|
-
export { Loader
|
|
17
|
+
export { Loader } from "./components/loader.js";
|
|
32
18
|
export { type DefaultTextStyle, Markdown, type MarkdownTheme } from "./components/markdown.js";
|
|
33
|
-
export {
|
|
19
|
+
export {
|
|
20
|
+
type SelectItem,
|
|
21
|
+
SelectList,
|
|
22
|
+
type SelectListLayoutOptions,
|
|
23
|
+
type SelectListTheme,
|
|
24
|
+
type SelectListTruncatePrimaryContext,
|
|
25
|
+
} from "./components/select-list.js";
|
|
34
26
|
export {
|
|
35
27
|
type SettingItem,
|
|
36
28
|
SettingsList,
|
|
@@ -45,34 +37,28 @@ export type { EditorComponent } from "./editor-component.js";
|
|
|
45
37
|
export { type FuzzyMatch, fuzzyFilter, fuzzyMatch } from "./fuzzy.js";
|
|
46
38
|
// Keybindings
|
|
47
39
|
export {
|
|
48
|
-
DEFAULT_EDITOR_KEYBINDINGS,
|
|
49
|
-
type EditorAction,
|
|
50
|
-
type EditorKeybindingsConfig,
|
|
51
|
-
EditorKeybindingsManager,
|
|
52
|
-
getEditorKeybindings,
|
|
53
40
|
getKeybindings,
|
|
54
41
|
type Keybinding,
|
|
42
|
+
type KeybindingConflict,
|
|
55
43
|
type KeybindingDefinition,
|
|
44
|
+
type KeybindingDefinitions,
|
|
56
45
|
type Keybindings,
|
|
57
46
|
type KeybindingsConfig,
|
|
58
47
|
KeybindingsManager,
|
|
59
|
-
setEditorKeybindings,
|
|
60
48
|
setKeybindings,
|
|
61
49
|
TUI_KEYBINDINGS,
|
|
62
50
|
} from "./keybindings.js";
|
|
63
51
|
// Keyboard input handling
|
|
64
52
|
export {
|
|
53
|
+
decodeKittyPrintable,
|
|
65
54
|
isKeyRelease,
|
|
66
55
|
isKeyRepeat,
|
|
67
56
|
isKittyProtocolActive,
|
|
68
|
-
isMouseEvent,
|
|
69
57
|
Key,
|
|
70
58
|
type KeyEventType,
|
|
71
59
|
type KeyId,
|
|
72
|
-
type MouseEvent,
|
|
73
60
|
matchesKey,
|
|
74
61
|
parseKey,
|
|
75
|
-
parseMouseEvent,
|
|
76
62
|
setKittyProtocolActive,
|
|
77
63
|
} from "./keys.js";
|
|
78
64
|
// Input buffering for batch splitting
|
|
@@ -83,15 +69,12 @@ export { ProcessTerminal, type Terminal } from "./terminal.js";
|
|
|
83
69
|
export {
|
|
84
70
|
allocateImageId,
|
|
85
71
|
type CellDimensions,
|
|
86
|
-
|
|
87
|
-
createImageMetadata,
|
|
72
|
+
calculateImageRows,
|
|
88
73
|
deleteAllKittyImages,
|
|
89
74
|
deleteKittyImage,
|
|
90
75
|
detectCapabilities,
|
|
91
|
-
detectImageFormat,
|
|
92
76
|
encodeITerm2,
|
|
93
77
|
encodeKitty,
|
|
94
|
-
formatImageDimensions,
|
|
95
78
|
getCapabilities,
|
|
96
79
|
getCellDimensions,
|
|
97
80
|
getGifDimensions,
|
|
@@ -99,16 +82,14 @@ export {
|
|
|
99
82
|
getJpegDimensions,
|
|
100
83
|
getPngDimensions,
|
|
101
84
|
getWebpDimensions,
|
|
85
|
+
hyperlink,
|
|
102
86
|
type ImageDimensions,
|
|
103
|
-
type ImageFormat,
|
|
104
|
-
type ImageLayout,
|
|
105
|
-
type ImageMetadata,
|
|
106
87
|
type ImageProtocol,
|
|
107
88
|
type ImageRenderOptions,
|
|
108
89
|
imageFallback,
|
|
109
|
-
imageFormatToMime,
|
|
110
90
|
renderImage,
|
|
111
91
|
resetCapabilitiesCache,
|
|
92
|
+
setCapabilities,
|
|
112
93
|
setCellDimensions,
|
|
113
94
|
type TerminalCapabilities,
|
|
114
95
|
} from "./terminal-image.js";
|
|
@@ -126,4 +107,4 @@ export {
|
|
|
126
107
|
TUI,
|
|
127
108
|
} from "./tui.js";
|
|
128
109
|
// Utilities
|
|
129
|
-
export {
|
|
110
|
+
export { truncateToWidth, visibleWidth, wrapTextWithAnsi } from "./utils.js";
|