pi-tui-footer 1.2.1 → 1.2.3
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/README.md +1 -1
- package/extensions/editor.ts +15 -3
- package/extensions/index.ts +1 -1
- package/extensions/rounded-tools.ts +3 -5
- package/extensions/utils.ts +28 -5
- package/package.json +1 -1
package/README.md
CHANGED
package/extensions/editor.ts
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
type ExtensionContext,
|
|
5
5
|
type KeybindingsManager,
|
|
6
6
|
} from "@earendil-works/pi-coding-agent";
|
|
7
|
-
import type { EditorTheme, TUI } from "@earendil-works/pi-tui";
|
|
7
|
+
import type { EditorTheme, TuiMouseEvent, TuiMouseEventResult, TUI } from "@earendil-works/pi-tui";
|
|
8
8
|
import { CURSOR_MARKER, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
9
9
|
import type { CursorStyle } from "./config.ts";
|
|
10
10
|
import {
|
|
@@ -24,6 +24,8 @@ const CURSOR_STYLE_SEQUENCES: Partial<Record<CursorStyle, string>> = {
|
|
|
24
24
|
underline: "\x1b[4 q",
|
|
25
25
|
};
|
|
26
26
|
const DEFAULT_CURSOR_STYLE_SEQUENCE = "\x1b[0 q";
|
|
27
|
+
const EDITOR_FRAME_LEFT_INSET = 2;
|
|
28
|
+
const EDITOR_FRAME_HORIZONTAL_CHROME = EDITOR_FRAME_LEFT_INSET * 2;
|
|
27
29
|
|
|
28
30
|
interface WorkingStatusIndicator {
|
|
29
31
|
renderInBorder(width: number): string;
|
|
@@ -221,6 +223,16 @@ export class OpenTuiEditor extends CustomEditor {
|
|
|
221
223
|
super.setPaddingX(0);
|
|
222
224
|
}
|
|
223
225
|
|
|
226
|
+
override handleMouse(event: TuiMouseEvent): TuiMouseEventResult | undefined {
|
|
227
|
+
if (event.width < EDITOR_FRAME_HORIZONTAL_CHROME) return super.handleMouse(event);
|
|
228
|
+
|
|
229
|
+
return super.handleMouse({
|
|
230
|
+
...event,
|
|
231
|
+
x: event.x - EDITOR_FRAME_LEFT_INSET,
|
|
232
|
+
width: event.width - EDITOR_FRAME_HORIZONTAL_CHROME,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
224
236
|
setWorkingStatusIndicator(indicator: WorkingStatusIndicator | undefined): void {
|
|
225
237
|
this.embeddedWorkingStatusIndicator = indicator;
|
|
226
238
|
this.tui.requestRender();
|
|
@@ -262,12 +274,12 @@ export class OpenTuiEditor extends CustomEditor {
|
|
|
262
274
|
}
|
|
263
275
|
|
|
264
276
|
render(width: number): string[] {
|
|
265
|
-
if (width <
|
|
277
|
+
if (width < EDITOR_FRAME_HORIZONTAL_CHROME) return this.renderBase(width);
|
|
266
278
|
|
|
267
279
|
const rail = this.getRail();
|
|
268
280
|
const borderPaint = this.getBorder;
|
|
269
281
|
// ponytail: 1-char rail + 1-char gap on each side = 4 chars of chrome.
|
|
270
|
-
const innerWidth = Math.max(0, width -
|
|
282
|
+
const innerWidth = Math.max(0, width - EDITOR_FRAME_HORIZONTAL_CHROME);
|
|
271
283
|
const baseLines = this.renderBase(innerWidth);
|
|
272
284
|
const bottomIdx = findBottomBorderIndex(baseLines);
|
|
273
285
|
|
package/extensions/index.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* thinking peek preview, rounded tool frames, and turn telemetry.
|
|
5
5
|
*
|
|
6
6
|
* Integrated from:
|
|
7
|
-
* - pi-open-tui (v0.3.
|
|
7
|
+
* - pi-open-tui (v0.3.9, MIT, by OldSun, https://github.com/OldSuns/pi-open-tui)
|
|
8
8
|
* - pi-rounded-tools (v0.1.3, MIT, by OrionPax, https://github.com/orionpax1997/pi-rounded-tools)
|
|
9
9
|
*
|
|
10
10
|
* Security audit notes:
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* Merged 2026-08 from the standalone local extension rounded-tools.ts (a
|
|
5
5
|
* localized copy of npm:pi-rounded-tools@0.1.3, MIT, by OrionPax,
|
|
6
6
|
* https://github.com/orionpax1997/pi-rounded-tools), integrated into pi-tui
|
|
7
|
-
* (based on https://github.com/OldSuns/pi-open-tui v0.3.
|
|
7
|
+
* (based on https://github.com/OldSuns/pi-open-tui v0.3.9, MIT, by
|
|
8
8
|
* OldSun) and gated behind `roundedTools` in pi-tui config
|
|
9
9
|
* (~/.pi/agent/pi-tui.json, default on).
|
|
10
10
|
*
|
|
11
|
-
* Re-registers the built-in tools (read, write, edit,
|
|
11
|
+
* Re-registers the built-in tools (read, write, edit, grep, find, ls)
|
|
12
12
|
* with `renderShell: "self"` and wraps each tool call / result in a frame
|
|
13
13
|
* drawn with Unicode rounded-corner characters (╭ ╮ ╰ ╯ ─ │).
|
|
14
14
|
*
|
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
|
|
27
27
|
import type { ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
28
28
|
import {
|
|
29
|
-
createBashToolDefinition,
|
|
30
29
|
createEditToolDefinition,
|
|
31
30
|
createFindToolDefinition,
|
|
32
31
|
createGrepToolDefinition,
|
|
@@ -229,7 +228,7 @@ function wrapBuiltin(def: ToolDef) {
|
|
|
229
228
|
}
|
|
230
229
|
|
|
231
230
|
/**
|
|
232
|
-
* Register the
|
|
231
|
+
* Register the 6 built-in file tools, either with rounded frames
|
|
233
232
|
* (`enabled`) or with their plain stock definitions (`!enabled`, restores
|
|
234
233
|
* original rendering). Registration refreshes the active tool set in the
|
|
235
234
|
* current session, so toggling the setting takes effect immediately.
|
|
@@ -239,7 +238,6 @@ export function registerRoundedTools(pi: ExtensionAPI, enabled: boolean, cwd: st
|
|
|
239
238
|
createReadToolDefinition(cwd),
|
|
240
239
|
createWriteToolDefinition(cwd),
|
|
241
240
|
createEditToolDefinition(cwd),
|
|
242
|
-
createBashToolDefinition(cwd),
|
|
243
241
|
createGrepToolDefinition(cwd),
|
|
244
242
|
createFindToolDefinition(cwd),
|
|
245
243
|
createLsToolDefinition(cwd),
|
package/extensions/utils.ts
CHANGED
|
@@ -43,23 +43,28 @@ export function truncateBranch(branch: string, maxLen: number): string {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
export function truncatePath(path: string, maxLen: number): string {
|
|
46
|
-
|
|
46
|
+
// `maxLen` is a terminal-column budget, so every comparison here must use
|
|
47
|
+
// display width. Comparing String.length let wide (CJK) paths stay wider than
|
|
48
|
+
// the budget: for a basename of 4 characters but 8 columns, `truncatePath`
|
|
49
|
+
// returned it unchanged, so fitSegmentsByPriority's `while (totalW() > maxW)`
|
|
50
|
+
// loop never made progress and livelocked the renderer at 100% CPU.
|
|
51
|
+
if (visibleWidth(path) <= maxLen) return path;
|
|
47
52
|
if (maxLen <= 3) return "...".slice(0, maxLen);
|
|
48
53
|
const sepChar = path.includes("/") ? "/" : "\\";
|
|
49
54
|
const parts = path.split(/[\\/]/);
|
|
50
|
-
if (parts.length <= 2) return path
|
|
55
|
+
if (parts.length <= 2) return truncateToWidth(path, maxLen, "...");
|
|
51
56
|
// Keep first segment (e.g. ~) and as many trailing segments as fit.
|
|
52
57
|
const tail: string[] = [];
|
|
53
58
|
let tailLen = 0;
|
|
54
59
|
for (let i = parts.length - 1; i >= 1; i--) {
|
|
55
60
|
const seg = parts[i]!;
|
|
56
|
-
if (tailLen + seg
|
|
61
|
+
if (tailLen + visibleWidth(seg) + 4 > maxLen) break;
|
|
57
62
|
tail.unshift(seg);
|
|
58
|
-
tailLen += seg
|
|
63
|
+
tailLen += visibleWidth(seg) + 1;
|
|
59
64
|
}
|
|
60
65
|
const head = parts[0]!;
|
|
61
66
|
const result = `${head}${sepChar}...${sepChar}${tail.join(sepChar)}`;
|
|
62
|
-
return result
|
|
67
|
+
return visibleWidth(result) > maxLen ? truncateToWidth(result, maxLen, "...") : result;
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
export function finiteOrZero(value: unknown): number {
|
|
@@ -158,7 +163,25 @@ export function fitSegmentsByPriority(
|
|
|
158
163
|
if (totalW() <= maxW) break;
|
|
159
164
|
}
|
|
160
165
|
}
|
|
166
|
+
// A segment whose `truncate` cannot actually shrink would otherwise spin here
|
|
167
|
+
// forever and block the render timer. Require each pass to make progress, and
|
|
168
|
+
// drop the worst segment when it does not, so layout always terminates.
|
|
169
|
+
let lastTotal = Infinity;
|
|
161
170
|
while (totalW() > maxW) {
|
|
171
|
+
const nowTotal = totalW();
|
|
172
|
+
if (nowTotal >= lastTotal) {
|
|
173
|
+
let worst = -1;
|
|
174
|
+
for (let i = 0; i < items.length; i++) {
|
|
175
|
+
if (items[i].text !== "" && (worst === -1 || items[i].priority < items[worst].priority)) {
|
|
176
|
+
worst = i;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (worst === -1) break;
|
|
180
|
+
items[worst].text = "";
|
|
181
|
+
items[worst].w = 0;
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
lastTotal = nowTotal;
|
|
162
185
|
let target = -1;
|
|
163
186
|
for (let i = 0; i < items.length; i++) {
|
|
164
187
|
if (items[i].text !== "" && (target === -1 || items[i].priority < items[target].priority)) {
|