pi-ui-extend 0.1.15 → 0.1.17
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/app/app.d.ts +2 -0
- package/dist/app/app.js +21 -6
- package/dist/app/commands/command-controller.js +1 -0
- package/dist/app/commands/command-host.d.ts +2 -0
- package/dist/app/commands/command-navigation-actions.d.ts +9 -0
- package/dist/app/commands/command-navigation-actions.js +62 -3
- package/dist/app/commands/command-registry.d.ts +1 -0
- package/dist/app/commands/command-registry.js +8 -0
- package/dist/app/constants.d.ts +0 -1
- package/dist/app/constants.js +0 -1
- package/dist/app/icons.d.ts +1 -0
- package/dist/app/icons.js +2 -0
- package/dist/app/input/input-action-controller.d.ts +1 -0
- package/dist/app/input/input-action-controller.js +5 -4
- package/dist/app/popup/menu-items-controller.d.ts +2 -0
- package/dist/app/popup/menu-items-controller.js +37 -14
- package/dist/app/popup/popup-menu-controller.js +30 -5
- package/dist/app/rendering/editor-panels.js +20 -9
- package/dist/app/rendering/popup-menu-renderer.d.ts +12 -0
- package/dist/app/rendering/popup-menu-renderer.js +151 -53
- package/dist/app/rendering/render-controller.js +25 -15
- package/dist/app/rendering/render-text.js +5 -2
- package/dist/app/rendering/status-line-renderer.d.ts +7 -0
- package/dist/app/rendering/status-line-renderer.js +191 -94
- package/dist/app/rendering/toast-controller.d.ts +1 -0
- package/dist/app/rendering/toast-controller.js +17 -0
- package/dist/app/screen/mouse-controller.js +4 -4
- package/dist/app/screen/scroll-controller.d.ts +1 -0
- package/dist/app/screen/scroll-controller.js +6 -0
- package/dist/app/screen/status-controller.js +2 -1
- package/dist/app/session/request-history.d.ts +4 -0
- package/dist/app/session/request-history.js +11 -0
- package/dist/app/session/session-search.js +10 -0
- package/dist/app/session/tabs-controller.d.ts +4 -4
- package/dist/app/session/tabs-controller.js +64 -6
- package/dist/app/todo/todo-model.d.ts +2 -2
- package/dist/app/todo/todo-model.js +15 -17
- package/dist/app/types.d.ts +12 -4
- package/dist/config.d.ts +1 -0
- package/dist/config.js +10 -1
- package/dist/default-pix-config.js +2 -0
- package/dist/fuzzy.d.ts +2 -0
- package/dist/fuzzy.js +27 -7
- package/dist/input-editor.d.ts +9 -0
- package/dist/input-editor.js +52 -0
- package/dist/schemas/pix-schema.d.ts +1 -0
- package/dist/schemas/pix-schema.js +1 -0
- package/dist/theme.js +6 -6
- package/dist/ui.d.ts +8 -0
- package/external/pi-tools-suite/README.md +2 -2
- package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +40 -5
- package/external/pi-tools-suite/src/antigravity-auth/commands.ts +1 -37
- package/external/pi-tools-suite/src/antigravity-auth/constants.ts +0 -2
- package/external/pi-tools-suite/src/antigravity-auth/index.ts +3 -16
- package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +33 -17
- package/external/pi-tools-suite/src/antigravity-auth/status.ts +1 -1
- package/external/pi-tools-suite/src/antigravity-auth/stream.ts +4 -12
- package/external/pi-tools-suite/src/antigravity-auth/types.ts +21 -0
- package/external/pi-tools-suite/src/todo/index.ts +3 -64
- package/external/pi-tools-suite/src/todo/state/persistence.ts +0 -1
- package/external/pi-tools-suite/src/todo/state/state-reducer.ts +7 -37
- package/external/pi-tools-suite/src/todo/todo.ts +2 -18
- package/external/pi-tools-suite/src/todo/tool/response-envelope.ts +2 -11
- package/external/pi-tools-suite/src/todo/tool/types.ts +0 -29
- package/external/pi-tools-suite/src/todo/view/format.ts +1 -3
- package/external/pi-tools-suite/src/tool-descriptions.ts +5 -4
- package/external/pi-tools-suite/src/usage/lib/google.ts +50 -30
- package/external/pi-tools-suite/src/usage/lib/types.ts +12 -2
- package/package.json +1 -1
- package/schemas/pix.json +5 -0
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { colorLine } from "../../theme.js";
|
|
2
2
|
import { stringDisplayWidth } from "../../terminal-width.js";
|
|
3
|
+
import { resolveColor, resolveModelColor } from "../../config.js";
|
|
3
4
|
import { SLASH_COMMAND_DESCRIPTION_COLUMN, } from "../constants.js";
|
|
4
5
|
import { APP_ICONS } from "../icons.js";
|
|
5
6
|
import { ellipsizeDisplay, padOrTrimPlain, sanitizeText } from "./render-text.js";
|
|
7
|
+
import { modelProviderThemeColor, thinkingLevelThemeColor } from "./status-line-renderer.js";
|
|
6
8
|
const POPUP_MENU_ESCAPE_BUTTON = "Esc";
|
|
9
|
+
const POPUP_MENU_DESCRIPTION_GAP = " ";
|
|
10
|
+
const POPUP_MENU_HEADER_SIDE_PADDING = 2;
|
|
7
11
|
export class PopupMenuRenderer {
|
|
8
12
|
host;
|
|
9
13
|
constructor(host) {
|
|
@@ -25,7 +29,7 @@ export class PopupMenuRenderer {
|
|
|
25
29
|
const menuWidth = this.effectivePopupMenuWidth(width);
|
|
26
30
|
const rightMargin = Math.max(0, width - margin - menuWidth);
|
|
27
31
|
const selected = line.target?.kind === "popup-menu" && activeMenu.selectedIndex === line.target.index;
|
|
28
|
-
const foreground = this.popupLineForeground(line
|
|
32
|
+
const foreground = this.popupLineForeground(line);
|
|
29
33
|
const background = this.popupLineBackground(line, selected);
|
|
30
34
|
const plain = `${" ".repeat(margin)}${padOrTrimPlain(line.text, menuWidth)}${" ".repeat(rightMargin)}`;
|
|
31
35
|
if (this.host.screenStyler.selectionRangeForRow(row, width)) {
|
|
@@ -59,7 +63,7 @@ export class PopupMenuRenderer {
|
|
|
59
63
|
for (const item of menu.visibleItems()) {
|
|
60
64
|
const label = item.label.padEnd(18, " ");
|
|
61
65
|
const description = item.description ?? "";
|
|
62
|
-
const marker = item.selected ? "
|
|
66
|
+
const marker = item.selected ? "▶" : " ";
|
|
63
67
|
const rawText = `${marker} ${label}${description}`;
|
|
64
68
|
const text = ellipsizeDisplay(rawText, options.userContentWidth);
|
|
65
69
|
const line = options.userLine(text);
|
|
@@ -73,7 +77,7 @@ export class PopupMenuRenderer {
|
|
|
73
77
|
{
|
|
74
78
|
start: labelStart,
|
|
75
79
|
end: labelEnd,
|
|
76
|
-
foreground: this.userMessageActionForeground(item.
|
|
80
|
+
foreground: this.userMessageActionForeground(item.value),
|
|
77
81
|
bold: item.selected,
|
|
78
82
|
},
|
|
79
83
|
...(descriptionStart < contentStart + text.length
|
|
@@ -91,11 +95,12 @@ export class PopupMenuRenderer {
|
|
|
91
95
|
lines.push({ text: " No matching slash commands", variant: "muted" });
|
|
92
96
|
}
|
|
93
97
|
for (const item of visibleItems) {
|
|
94
|
-
const
|
|
95
|
-
const
|
|
98
|
+
const marker = item.selected ? "▶ " : " ";
|
|
99
|
+
const text = `${marker}${this.labelDescriptionText(item.label, item.description, width - 2)}`;
|
|
96
100
|
lines.push({
|
|
97
|
-
text
|
|
98
|
-
variant:
|
|
101
|
+
text,
|
|
102
|
+
variant: "normal",
|
|
103
|
+
segments: this.itemHighlightSegments(item, text),
|
|
99
104
|
target: { kind: "popup-menu", index: item.index },
|
|
100
105
|
});
|
|
101
106
|
}
|
|
@@ -111,11 +116,12 @@ export class PopupMenuRenderer {
|
|
|
111
116
|
});
|
|
112
117
|
}
|
|
113
118
|
for (const item of visibleItems) {
|
|
114
|
-
const
|
|
115
|
-
const
|
|
119
|
+
const marker = item.selected ? "▶ " : " ";
|
|
120
|
+
const text = `${marker}${this.labelDescriptionText(item.label, item.description, width - 2)}`;
|
|
116
121
|
lines.push({
|
|
117
|
-
text
|
|
118
|
-
variant: this.selectableItemVariant(item.
|
|
122
|
+
text,
|
|
123
|
+
variant: this.selectableItemVariant(item.value),
|
|
124
|
+
segments: [...this.modelMenuItemSegments(item.value), ...this.itemHighlightSegments(item, text)],
|
|
119
125
|
target: { kind: "popup-menu", index: item.index },
|
|
120
126
|
});
|
|
121
127
|
}
|
|
@@ -128,11 +134,12 @@ export class PopupMenuRenderer {
|
|
|
128
134
|
lines.push({ text: " No matching thinking levels", variant: "muted" });
|
|
129
135
|
}
|
|
130
136
|
for (const item of visibleItems) {
|
|
131
|
-
const
|
|
132
|
-
const
|
|
137
|
+
const marker = item.selected ? "▶ " : " ";
|
|
138
|
+
const text = `${marker}${this.labelDescriptionText(item.label, item.description, width - 2)}`;
|
|
133
139
|
lines.push({
|
|
134
|
-
text
|
|
135
|
-
variant: this.selectableItemVariant(item.
|
|
140
|
+
text,
|
|
141
|
+
variant: this.selectableItemVariant(item.value),
|
|
142
|
+
segments: this.thinkingMenuItemSegments(item.value),
|
|
136
143
|
target: { kind: "popup-menu", index: item.index },
|
|
137
144
|
});
|
|
138
145
|
}
|
|
@@ -151,12 +158,13 @@ export class PopupMenuRenderer {
|
|
|
151
158
|
for (const item of visibleItems) {
|
|
152
159
|
const label = item.label;
|
|
153
160
|
const description = item.description ?? "";
|
|
154
|
-
const
|
|
155
|
-
const
|
|
161
|
+
const marker = item.selected ? "▶ " : " ";
|
|
162
|
+
const text = `${marker}${label} ${description}`;
|
|
163
|
+
const segments = [...(this.resumeMenuItemSegments(item.value, label, description, text) ?? []), ...this.itemHighlightSegments(item, text)];
|
|
156
164
|
lines.push({
|
|
157
165
|
text,
|
|
158
|
-
variant:
|
|
159
|
-
...(segments ? {
|
|
166
|
+
variant: "normal",
|
|
167
|
+
...(segments.length === 0 ? {} : { segments }),
|
|
160
168
|
target: { kind: "popup-menu", index: item.index },
|
|
161
169
|
});
|
|
162
170
|
}
|
|
@@ -170,18 +178,24 @@ export class PopupMenuRenderer {
|
|
|
170
178
|
}
|
|
171
179
|
renderUserMessageJumpMenu(width, menu, directQuery) {
|
|
172
180
|
const lines = [this.popupMenuHeader("Jump to user message", width)];
|
|
173
|
-
if (
|
|
181
|
+
if (this.host.userMessageJumpLoading) {
|
|
182
|
+
lines.push({ text: ` ${APP_ICONS.timerSand} Loading user messages`, variant: "muted" });
|
|
183
|
+
}
|
|
184
|
+
else if (!this.hasPopupActionItems(menu.items)) {
|
|
174
185
|
lines.push({
|
|
175
186
|
text: this.host.entries.some((entry) => entry.kind === "user") ? " No matching user messages" : " No user messages yet",
|
|
176
187
|
variant: "muted",
|
|
177
188
|
});
|
|
178
189
|
}
|
|
179
|
-
const labelWidth = Math.max(1, width);
|
|
190
|
+
const labelWidth = Math.max(1, width - 2);
|
|
180
191
|
for (const item of menu.visibleItems()) {
|
|
181
192
|
const label = ellipsizeDisplay(item.label, labelWidth);
|
|
193
|
+
const marker = item.selected ? "▶ " : " ";
|
|
194
|
+
const text = `${marker}${label}`;
|
|
182
195
|
lines.push({
|
|
183
|
-
text
|
|
184
|
-
variant:
|
|
196
|
+
text,
|
|
197
|
+
variant: "normal",
|
|
198
|
+
segments: this.itemHighlightSegments(item, text),
|
|
185
199
|
target: { kind: "popup-menu", index: item.index },
|
|
186
200
|
});
|
|
187
201
|
}
|
|
@@ -193,11 +207,10 @@ export class PopupMenuRenderer {
|
|
|
193
207
|
renderQueueMessageMenu(width, menu) {
|
|
194
208
|
const lines = [this.popupMenuHeader("Queued message", width)];
|
|
195
209
|
for (const item of menu.visibleItems()) {
|
|
196
|
-
const
|
|
197
|
-
const description = item.description ?? "";
|
|
210
|
+
const marker = item.selected ? "▶ " : " ";
|
|
198
211
|
lines.push({
|
|
199
|
-
text: `${
|
|
200
|
-
variant: this.queueMessageItemVariant(item.
|
|
212
|
+
text: `${marker}${this.labelDescriptionText(item.label, item.description, width - 2, 16)}`,
|
|
213
|
+
variant: this.queueMessageItemVariant(item.value),
|
|
201
214
|
target: { kind: "popup-menu", index: item.index },
|
|
202
215
|
});
|
|
203
216
|
}
|
|
@@ -209,11 +222,13 @@ export class PopupMenuRenderer {
|
|
|
209
222
|
lines.push({ text: ` ${request?.options.emptyText ?? "No matching items"}`, variant: "muted" });
|
|
210
223
|
}
|
|
211
224
|
for (const item of menu.visibleItems()) {
|
|
212
|
-
const
|
|
213
|
-
const
|
|
225
|
+
const marker = item.selected ? "▶ " : " ";
|
|
226
|
+
const text = `${marker}${this.labelDescriptionText(item.label, item.description, width - 2)}`;
|
|
227
|
+
const segments = this.sdkMenuItemSegments(item, text);
|
|
214
228
|
lines.push({
|
|
215
|
-
text
|
|
216
|
-
variant: this.sdkItemVariant(item.
|
|
229
|
+
text,
|
|
230
|
+
variant: this.sdkItemVariant(item.value),
|
|
231
|
+
...(segments.length === 0 ? {} : { segments }),
|
|
217
232
|
target: { kind: "popup-menu", index: item.index },
|
|
218
233
|
});
|
|
219
234
|
}
|
|
@@ -225,39 +240,117 @@ export class PopupMenuRenderer {
|
|
|
225
240
|
hasPopupActionItems(items) {
|
|
226
241
|
return items.length > 0;
|
|
227
242
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
243
|
+
labelDescriptionText(label, description, width, labelColumn = SLASH_COMMAND_DESCRIPTION_COLUMN) {
|
|
244
|
+
const safeLabel = sanitizeText(label).replace(/\s+/gu, " ");
|
|
245
|
+
const safeDescription = description ? sanitizeText(description).replace(/\s+/gu, " ") : "";
|
|
246
|
+
if (!safeDescription)
|
|
247
|
+
return ellipsizeDisplay(safeLabel, width);
|
|
248
|
+
const gapWidth = stringDisplayWidth(POPUP_MENU_DESCRIPTION_GAP);
|
|
249
|
+
const labelDisplayWidth = stringDisplayWidth(safeLabel);
|
|
250
|
+
const descriptionDisplayWidth = stringDisplayWidth(safeDescription);
|
|
251
|
+
if (width <= gapWidth + 1)
|
|
252
|
+
return ellipsizeDisplay(safeLabel, width);
|
|
253
|
+
if (labelDisplayWidth <= labelColumn && labelColumn + gapWidth + descriptionDisplayWidth <= width) {
|
|
254
|
+
return `${safeLabel}${" ".repeat(labelColumn - labelDisplayWidth)}${POPUP_MENU_DESCRIPTION_GAP}${safeDescription}`;
|
|
255
|
+
}
|
|
256
|
+
if (labelDisplayWidth + gapWidth + descriptionDisplayWidth <= width) {
|
|
257
|
+
return `${safeLabel}${POPUP_MENU_DESCRIPTION_GAP}${safeDescription}`;
|
|
258
|
+
}
|
|
259
|
+
const labelWidth = descriptionDisplayWidth < width - gapWidth - 1
|
|
260
|
+
? Math.max(1, width - gapWidth - descriptionDisplayWidth)
|
|
261
|
+
: Math.max(1, Math.min(labelColumn, width - gapWidth - 1));
|
|
262
|
+
const visibleLabel = ellipsizeDisplay(safeLabel, labelWidth);
|
|
263
|
+
const padding = " ".repeat(Math.max(0, labelWidth - stringDisplayWidth(visibleLabel)));
|
|
264
|
+
return `${visibleLabel}${padding}${POPUP_MENU_DESCRIPTION_GAP}${safeDescription}`;
|
|
265
|
+
}
|
|
266
|
+
userMessageActionForeground(value) {
|
|
231
267
|
if (value === "undo")
|
|
232
268
|
return this.host.theme.colors.error;
|
|
233
269
|
return this.host.theme.colors.inputForeground;
|
|
234
270
|
}
|
|
235
|
-
selectableItemVariant(
|
|
236
|
-
if (selected)
|
|
237
|
-
return "accent";
|
|
271
|
+
selectableItemVariant(value) {
|
|
238
272
|
return value.current ? "muted" : "normal";
|
|
239
273
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
274
|
+
thinkingMenuItemSegments(value) {
|
|
275
|
+
const markerOffset = 2; // "▶ " or " "
|
|
276
|
+
return [{
|
|
277
|
+
start: markerOffset,
|
|
278
|
+
end: markerOffset + value.level.length,
|
|
279
|
+
foreground: thinkingLevelThemeColor(value.level, this.host.theme.colors, this.availableThinkingLevels()),
|
|
280
|
+
}];
|
|
281
|
+
}
|
|
282
|
+
modelMenuItemSegments(value) {
|
|
283
|
+
const markerOffset = 2; // "▶ " or " "
|
|
284
|
+
return [{
|
|
285
|
+
start: markerOffset,
|
|
286
|
+
end: markerOffset + value.ref.length,
|
|
287
|
+
foreground: this.modelMenuItemColor(value),
|
|
288
|
+
}];
|
|
289
|
+
}
|
|
290
|
+
modelMenuItemColor(value) {
|
|
291
|
+
const configuredColor = this.host.modelColors
|
|
292
|
+
? resolveModelColor(value.ref, this.host.modelColors)
|
|
293
|
+
: undefined;
|
|
294
|
+
return configuredColor
|
|
295
|
+
? resolveColor(configuredColor, this.host.theme.colors)
|
|
296
|
+
: modelProviderThemeColor(value.model.provider, this.host.theme.colors);
|
|
297
|
+
}
|
|
298
|
+
availableThinkingLevels() {
|
|
299
|
+
const levels = this.host.session?.getAvailableThinkingLevels();
|
|
300
|
+
return Array.isArray(levels) && levels.length > 0 ? levels.map(String) : ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
301
|
+
}
|
|
302
|
+
queueMessageItemVariant(value) {
|
|
243
303
|
return value === "cancel" ? "error" : "normal";
|
|
244
304
|
}
|
|
245
|
-
sdkItemVariant(
|
|
246
|
-
if (selected)
|
|
247
|
-
return "accent";
|
|
305
|
+
sdkItemVariant(value) {
|
|
248
306
|
return value.variant ?? "normal";
|
|
249
307
|
}
|
|
308
|
+
sdkMenuItemSegments(item, text) {
|
|
309
|
+
return [
|
|
310
|
+
...this.highlightSegments(item.labelHighlightRanges ?? item.value.labelHighlightRanges ?? [], text, 2),
|
|
311
|
+
...this.descriptionHighlightSegments(item.description, item.descriptionHighlightRanges ?? item.value.descriptionHighlightRanges ?? [], text),
|
|
312
|
+
];
|
|
313
|
+
}
|
|
314
|
+
itemHighlightSegments(item, text) {
|
|
315
|
+
return this.highlightSegments(item.labelHighlightRanges ?? [], text, 2);
|
|
316
|
+
}
|
|
317
|
+
highlightSegments(ranges, text, markerOffset) {
|
|
318
|
+
if (ranges.length === 0)
|
|
319
|
+
return [];
|
|
320
|
+
return ranges.flatMap((range) => {
|
|
321
|
+
const start = Math.max(markerOffset, markerOffset + range.start);
|
|
322
|
+
const end = Math.min(text.length, markerOffset + range.end);
|
|
323
|
+
if (end <= start)
|
|
324
|
+
return [];
|
|
325
|
+
return [{
|
|
326
|
+
start,
|
|
327
|
+
end,
|
|
328
|
+
foreground: this.host.theme.colors.accent,
|
|
329
|
+
bold: true,
|
|
330
|
+
}];
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
descriptionHighlightSegments(description, ranges, text) {
|
|
334
|
+
if (!description || ranges.length === 0)
|
|
335
|
+
return [];
|
|
336
|
+
const safeDescription = sanitizeText(description).replace(/\s+/gu, " ");
|
|
337
|
+
const descriptionStart = text.indexOf(safeDescription, 2);
|
|
338
|
+
if (descriptionStart < 0)
|
|
339
|
+
return [];
|
|
340
|
+
return this.highlightSegments(ranges, text, descriptionStart);
|
|
341
|
+
}
|
|
250
342
|
resumeMenuItemSegments(value, label, description, text) {
|
|
251
343
|
if (value.kind !== "session")
|
|
252
344
|
return undefined;
|
|
253
345
|
const sessionLabel = value.session.name ?? value.session.firstMessage.slice(0, 50);
|
|
254
|
-
const
|
|
346
|
+
const markerOffset = 2; // "▶ " or " "
|
|
347
|
+
const sessionLabelStart = Math.max(0, label.length - sessionLabel.length) + markerOffset;
|
|
255
348
|
const muted = this.host.theme.colors.popupMuted;
|
|
256
349
|
const segments = [];
|
|
257
|
-
if (sessionLabelStart >
|
|
258
|
-
segments.push({ start:
|
|
350
|
+
if (sessionLabelStart > markerOffset)
|
|
351
|
+
segments.push({ start: markerOffset, end: sessionLabelStart, foreground: muted });
|
|
259
352
|
if (description.length > 0)
|
|
260
|
-
segments.push({ start: label.length, end: text.length, foreground: muted });
|
|
353
|
+
segments.push({ start: markerOffset + label.length, end: text.length, foreground: muted });
|
|
261
354
|
return segments.length > 0 ? segments : undefined;
|
|
262
355
|
}
|
|
263
356
|
popupMenuHeader(title, width) {
|
|
@@ -268,10 +361,8 @@ export class PopupMenuRenderer {
|
|
|
268
361
|
target: { kind: "popup-menu-close" },
|
|
269
362
|
};
|
|
270
363
|
}
|
|
271
|
-
popupLineForeground(line
|
|
364
|
+
popupLineForeground(line) {
|
|
272
365
|
const colors = this.host.theme.colors;
|
|
273
|
-
if (selected)
|
|
274
|
-
return colors.popupSelectedForeground;
|
|
275
366
|
if (line.colorOverride)
|
|
276
367
|
return line.colorOverride;
|
|
277
368
|
switch (line.variant) {
|
|
@@ -300,8 +391,15 @@ export function formatPopupMenuHeader(title, width) {
|
|
|
300
391
|
const buttonWidth = stringDisplayWidth(POPUP_MENU_ESCAPE_BUTTON);
|
|
301
392
|
if (safeWidth <= buttonWidth + 1)
|
|
302
393
|
return padOrTrimPlain(POPUP_MENU_ESCAPE_BUTTON, safeWidth);
|
|
303
|
-
const
|
|
394
|
+
const sidePadding = safeWidth >= buttonWidth + POPUP_MENU_HEADER_SIDE_PADDING * 2 + 2
|
|
395
|
+
? POPUP_MENU_HEADER_SIDE_PADDING
|
|
396
|
+
: 1;
|
|
397
|
+
const contentWidth = Math.max(1, safeWidth - sidePadding * 2);
|
|
398
|
+
if (contentWidth <= buttonWidth + 1) {
|
|
399
|
+
return padOrTrimPlain(`${" ".repeat(sidePadding)}${POPUP_MENU_ESCAPE_BUTTON}`, safeWidth);
|
|
400
|
+
}
|
|
401
|
+
const titleWidth = contentWidth - buttonWidth - 1;
|
|
304
402
|
const titleText = ellipsizeDisplay(sanitizedTitle, titleWidth);
|
|
305
|
-
const gapWidth = Math.max(1,
|
|
306
|
-
return `${titleText}${" ".repeat(gapWidth)}${POPUP_MENU_ESCAPE_BUTTON}`;
|
|
403
|
+
const gapWidth = Math.max(1, contentWidth - stringDisplayWidth(titleText) - buttonWidth);
|
|
404
|
+
return `${" ".repeat(sidePadding)}${titleText}${" ".repeat(gapWidth)}${POPUP_MENU_ESCAPE_BUTTON}${" ".repeat(sidePadding)}`;
|
|
307
405
|
}
|
|
@@ -189,18 +189,26 @@ export class AppRenderController {
|
|
|
189
189
|
setRenderedBackground(row, rendered.line?.backgroundOverride);
|
|
190
190
|
appendFrameOutput("inputStatus", row, this.renderFrameRow(row, rendered.output(row)));
|
|
191
191
|
}
|
|
192
|
+
const statusLayout = this.deps.statusLineRenderer.layout(columns);
|
|
193
|
+
const statusLineRenderer = this.deps.statusLineRenderer;
|
|
194
|
+
const inputBorderWidgetsLayout = statusLineRenderer.inputBorderWidgetsLayout?.(columns);
|
|
192
195
|
if (inputBottomSeparatorRow > 1) {
|
|
193
196
|
const separatorText = inputFrameLine(columns, "bottom");
|
|
194
197
|
const row = toScreenRow(inputBottomSeparatorRow);
|
|
195
198
|
if (row < statusRow) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
199
|
+
const text = inputBorderWidgetsLayout
|
|
200
|
+
? overlayText(separatorText, inputBorderWidgetsLayout.inputBorderWidgetStartColumn ?? 1, inputBorderWidgetsLayout.text)
|
|
201
|
+
: separatorText;
|
|
202
|
+
this.deps.mouseController.renderedRowTexts.set(row, text);
|
|
203
|
+
const output = inputBorderWidgetsLayout && statusLineRenderer.renderInputBorderWidgets
|
|
204
|
+
? statusLineRenderer.renderInputBorderWidgets(row, inputBorderWidgetsLayout, separatorText, columns)
|
|
205
|
+
: this.deps.screenStyler.styleLine(row, separatorText, columns, {
|
|
206
|
+
foreground: this.deps.theme.colors.inputBorder,
|
|
207
|
+
});
|
|
208
|
+
appendFrameOutput("inputStatus", row, this.renderFrameRow(row, output));
|
|
200
209
|
}
|
|
201
210
|
}
|
|
202
|
-
|
|
203
|
-
this.updateStatusMouseState(statusLayout, statusRow);
|
|
211
|
+
this.updateStatusMouseState(statusLayout, statusRow, inputBorderWidgetsLayout, toScreenRow(inputBottomSeparatorRow));
|
|
204
212
|
appendFrameOutput("inputStatus", statusRow, this.renderFrameRow(statusRow, this.deps.statusLineRenderer.render(statusRow, statusLayout, columns)));
|
|
205
213
|
const voiceProgressOverlay = this.renderVoiceProgressOverlay(this.deps.voiceProgressOverlayText(), columns, statusRow);
|
|
206
214
|
if (voiceProgressOverlay) {
|
|
@@ -278,20 +286,22 @@ export class AppRenderController {
|
|
|
278
286
|
const text = fixedCellText(flash.text, width);
|
|
279
287
|
return `\x1b[${flash.y};${flash.startColumn}H\x1b[7m${text}${ANSI_RESET}`;
|
|
280
288
|
}
|
|
281
|
-
updateStatusMouseState(statusLayout, statusRow) {
|
|
289
|
+
updateStatusMouseState(statusLayout, statusRow, inputBorderWidgetsLayout, inputBorderWidgetsRow) {
|
|
290
|
+
const widgetLayout = inputBorderWidgetsLayout;
|
|
291
|
+
const widgetRow = inputBorderWidgetsRow ?? statusRow;
|
|
282
292
|
this.deps.mouseController.statusModelTarget = this.deps.statusLineRenderer.modelTarget(statusLayout.text, statusRow);
|
|
283
293
|
this.deps.mouseController.statusThinkingTarget = this.deps.statusLineRenderer.thinkingTarget(statusLayout.text, statusRow);
|
|
284
294
|
this.deps.mouseController.statusContextTarget = this.deps.statusLineRenderer.contextTarget(statusLayout.text, statusRow, statusLayout);
|
|
285
295
|
this.deps.mouseController.statusModelUsageTarget = this.deps.statusLineRenderer.modelUsageTarget(statusLayout.text, statusRow, statusLayout);
|
|
286
|
-
this.deps.mouseController.statusDraftQueueTarget = this.deps.statusLineRenderer.draftQueueTarget?.(
|
|
287
|
-
this.deps.mouseController.statusUserJumpTarget = this.deps.statusLineRenderer.userJumpTarget?.(
|
|
288
|
-
this.deps.mouseController.statusThinkingExpandTarget = this.deps.statusLineRenderer.thinkingExpandTarget?.(
|
|
289
|
-
this.deps.mouseController.statusCompactToolsTarget = this.deps.statusLineRenderer.compactToolsTarget?.(
|
|
290
|
-
this.deps.mouseController.statusTerminalBellSoundTarget = this.deps.statusLineRenderer.terminalBellSoundTarget?.(
|
|
296
|
+
this.deps.mouseController.statusDraftQueueTarget = widgetLayout ? this.deps.statusLineRenderer.draftQueueTarget?.(widgetLayout, widgetRow) : undefined;
|
|
297
|
+
this.deps.mouseController.statusUserJumpTarget = widgetLayout ? this.deps.statusLineRenderer.userJumpTarget?.(widgetLayout, widgetRow) : undefined;
|
|
298
|
+
this.deps.mouseController.statusThinkingExpandTarget = widgetLayout ? this.deps.statusLineRenderer.thinkingExpandTarget?.(widgetLayout, widgetRow) : undefined;
|
|
299
|
+
this.deps.mouseController.statusCompactToolsTarget = widgetLayout ? this.deps.statusLineRenderer.compactToolsTarget?.(widgetLayout, widgetRow) : undefined;
|
|
300
|
+
this.deps.mouseController.statusTerminalBellSoundTarget = widgetLayout ? this.deps.statusLineRenderer.terminalBellSoundTarget?.(widgetLayout, widgetRow) : undefined;
|
|
291
301
|
this.deps.mouseController.statusSessionTarget = this.deps.statusLineRenderer.sessionTarget(statusLayout.text, statusRow, statusLayout.sessionLabel, statusLayout.workspaceLabel);
|
|
292
|
-
this.deps.mouseController.statusPromptEnhancerTarget = this.deps.statusLineRenderer.promptEnhancerTarget(
|
|
293
|
-
this.deps.mouseController.statusVoiceMicTarget = this.deps.statusLineRenderer.voiceMicTarget(
|
|
294
|
-
this.deps.mouseController.statusVoiceLanguageTarget = this.deps.statusLineRenderer.voiceLanguageTarget(
|
|
302
|
+
this.deps.mouseController.statusPromptEnhancerTarget = widgetLayout ? this.deps.statusLineRenderer.promptEnhancerTarget(widgetLayout, widgetRow) : undefined;
|
|
303
|
+
this.deps.mouseController.statusVoiceMicTarget = widgetLayout ? this.deps.statusLineRenderer.voiceMicTarget(widgetLayout, widgetRow) : undefined;
|
|
304
|
+
this.deps.mouseController.statusVoiceLanguageTarget = widgetLayout ? this.deps.statusLineRenderer.voiceLanguageTarget(widgetLayout, widgetRow) : undefined;
|
|
295
305
|
this.deps.mouseController.renderedRowTexts.set(statusRow, statusLayout.text);
|
|
296
306
|
}
|
|
297
307
|
renderVoiceProgressOverlay(message, width, rows) {
|
|
@@ -21,9 +21,12 @@ export function shortHash(text) {
|
|
|
21
21
|
export function hasLspDiagnosticsAfterMutation(output) {
|
|
22
22
|
return /lsp\s+(?:errors?|warnings?|diagnostics?)\s+after\s+mutation/i.test(output) || /lsp\s+diagnostics\s*:/i.test(output);
|
|
23
23
|
}
|
|
24
|
-
const LSP_DIAGNOSTIC_MUTATION_TOOLS = new Set(["apply_patch", "ast_apply"]);
|
|
24
|
+
const LSP_DIAGNOSTIC_MUTATION_TOOLS = new Set(["apply_patch", "ast_apply", "edit", "write"]);
|
|
25
25
|
export function hasToolLspDiagnosticsAfterMutation(entry) {
|
|
26
|
-
return LSP_DIAGNOSTIC_MUTATION_TOOLS.has(entry.toolName
|
|
26
|
+
return LSP_DIAGNOSTIC_MUTATION_TOOLS.has(normalizedToolName(entry.toolName)) && hasLspDiagnosticsAfterMutation(entry.output);
|
|
27
|
+
}
|
|
28
|
+
function normalizedToolName(toolName) {
|
|
29
|
+
return toolName.split(/[.:/]/).filter(Boolean).at(-1)?.trim().toLowerCase() ?? toolName.toLowerCase();
|
|
27
30
|
}
|
|
28
31
|
export function lspDiagnosticSeverityForLine(line) {
|
|
29
32
|
const counts = lspDiagnosticCounts(line);
|
|
@@ -35,7 +35,10 @@ export declare class StatusLineRenderer {
|
|
|
35
35
|
private readonly host;
|
|
36
36
|
constructor(host: StatusLineRendererHost);
|
|
37
37
|
layout(width: number): StatusLineLayout;
|
|
38
|
+
inputBorderWidgetsLayout(width: number): StatusLineLayout | undefined;
|
|
38
39
|
render(row: number, layout: StatusLineLayout, width: number): string;
|
|
40
|
+
renderInputBorderWidgets(row: number, layout: StatusLineLayout, borderText: string, width: number): string;
|
|
41
|
+
private inputBorderWidgetSegments;
|
|
39
42
|
modelTarget(statusText: string, row: number): StatusModelTarget | undefined;
|
|
40
43
|
thinkingTarget(statusText: string, row: number): StatusThinkingTarget | undefined;
|
|
41
44
|
contextTarget(statusText: string, row: number, layout: StatusLineLayout): StatusContextTarget | undefined;
|
|
@@ -66,10 +69,14 @@ export declare class StatusLineRenderer {
|
|
|
66
69
|
private modelUsageProgressColor;
|
|
67
70
|
private modelProviderColor;
|
|
68
71
|
private thinkingLevelColor;
|
|
72
|
+
private statusThinkingDisplayLabel;
|
|
69
73
|
private availableThinkingLevels;
|
|
70
74
|
private contextBarLabel;
|
|
71
75
|
private widgetLayout;
|
|
76
|
+
private iconButtonText;
|
|
77
|
+
private voiceBorderWidgetText;
|
|
72
78
|
private voiceWidgetLayout;
|
|
79
|
+
private voiceBorderWidgetParts;
|
|
73
80
|
private statusDotColor;
|
|
74
81
|
}
|
|
75
82
|
export declare function thinkingLevelThemeColor(label: string, colors: Theme["colors"], availableLevels?: readonly string[]): string;
|