pi-cc-extensions 0.8.21 → 0.8.22
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.
|
@@ -29,12 +29,6 @@ import {
|
|
|
29
29
|
wrapTextWithAnsi,
|
|
30
30
|
} from "@earendil-works/pi-tui";
|
|
31
31
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
32
|
-
import {
|
|
33
|
-
bottomDialogBounds,
|
|
34
|
-
isDialogCloseClick,
|
|
35
|
-
renderDialogHeader,
|
|
36
|
-
renderDialogTopBorder,
|
|
37
|
-
} from "./closable-dialog.ts";
|
|
38
32
|
import { homedir } from "node:os";
|
|
39
33
|
import { join } from "node:path";
|
|
40
34
|
|
|
@@ -1992,8 +1986,6 @@ async function showCcstylePanel(ctx: any, compactStyle: CompactStyleHooks): Prom
|
|
|
1992
1986
|
];
|
|
1993
1987
|
|
|
1994
1988
|
let activeSection = 0;
|
|
1995
|
-
let lastWidth = 0;
|
|
1996
|
-
let lastHeight = 0;
|
|
1997
1989
|
const settingsTheme = getSettingsListTheme();
|
|
1998
1990
|
const lists = sections.map(
|
|
1999
1991
|
(section) =>
|
|
@@ -2030,15 +2022,8 @@ async function showCcstylePanel(ctx: any, compactStyle: CompactStyleHooks): Prom
|
|
|
2030
2022
|
while (listBody.length > 0 && listBody[listBody.length - 1] === "") listBody.pop();
|
|
2031
2023
|
|
|
2032
2024
|
// Frame: top rule · tabs · mid rule · settings · mid rule · footer · bottom rule
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
renderDialogHeader(
|
|
2036
|
-
" CC Style",
|
|
2037
|
-
safeWidth,
|
|
2038
|
-
(text) => theme.fg("border", text),
|
|
2039
|
-
(text) => theme.fg("toolTitle", text),
|
|
2040
|
-
(text) => theme.fg("muted", text),
|
|
2041
|
-
),
|
|
2025
|
+
return [
|
|
2026
|
+
rule,
|
|
2042
2027
|
renderSectionTabBar(theme, sections, activeSection, safeWidth),
|
|
2043
2028
|
rule,
|
|
2044
2029
|
...listBody,
|
|
@@ -2052,22 +2037,11 @@ async function showCcstylePanel(ctx: any, compactStyle: CompactStyleHooks): Prom
|
|
|
2052
2037
|
),
|
|
2053
2038
|
rule,
|
|
2054
2039
|
];
|
|
2055
|
-
lastWidth = safeWidth;
|
|
2056
|
-
lastHeight = lines.length;
|
|
2057
|
-
return lines;
|
|
2058
2040
|
},
|
|
2059
2041
|
invalidate() {
|
|
2060
2042
|
for (const list of lists) list.invalidate();
|
|
2061
2043
|
},
|
|
2062
2044
|
handleInput(data: string) {
|
|
2063
|
-
if (
|
|
2064
|
-
!excludeSubmenuOpen &&
|
|
2065
|
-
tui.terminal &&
|
|
2066
|
-
isDialogCloseClick(data, bottomDialogBounds(tui.terminal, lastWidth, lastHeight))
|
|
2067
|
-
) {
|
|
2068
|
-
done();
|
|
2069
|
-
return;
|
|
2070
|
-
}
|
|
2071
2045
|
if (!excludeSubmenuOpen && isForwardTabKey(data)) {
|
|
2072
2046
|
switchSection(1);
|
|
2073
2047
|
tui.requestRender();
|
|
@@ -2118,15 +2092,22 @@ function toolCallArgument(args: any): { key: string; value: string } | undefined
|
|
|
2118
2092
|
: undefined;
|
|
2119
2093
|
}
|
|
2120
2094
|
|
|
2121
|
-
function
|
|
2095
|
+
export function middleTruncateToWidth(text: string, width: number): string {
|
|
2122
2096
|
if (visibleWidth(text) <= width) return text;
|
|
2123
2097
|
if (width <= 1) return "…";
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2098
|
+
const chars = Array.from(text);
|
|
2099
|
+
const leftWidth = Math.ceil((width - 1) / 2);
|
|
2100
|
+
let left = "";
|
|
2101
|
+
let right = "";
|
|
2102
|
+
for (const char of chars) {
|
|
2103
|
+
if (visibleWidth(left + char) > leftWidth) break;
|
|
2104
|
+
left += char;
|
|
2105
|
+
}
|
|
2106
|
+
for (const char of chars.reverse()) {
|
|
2107
|
+
if (visibleWidth(left + "…" + char + right) > width) break;
|
|
2108
|
+
right = char + right;
|
|
2128
2109
|
}
|
|
2129
|
-
return
|
|
2110
|
+
return `${left}…${right}`;
|
|
2130
2111
|
}
|
|
2131
2112
|
|
|
2132
2113
|
export function shouldRenderRichDiff(
|
|
@@ -2170,11 +2151,7 @@ function createCcstyleTool(
|
|
|
2170
2151
|
return {
|
|
2171
2152
|
render(width: number) {
|
|
2172
2153
|
const argumentWidth = Math.max(1, width - visibleWidth(`${rawIcon} ${label}()`));
|
|
2173
|
-
const shown = argument
|
|
2174
|
-
? argument.key === "path"
|
|
2175
|
-
? tailToWidth(argument.value, argumentWidth)
|
|
2176
|
-
: truncateToWidth(argument.value, argumentWidth, "…")
|
|
2177
|
-
: undefined;
|
|
2154
|
+
const shown = argument ? middleTruncateToWidth(argument.value, argumentWidth) : undefined;
|
|
2178
2155
|
const call = shown === undefined ? label : `${label}(${shown})`;
|
|
2179
2156
|
// Leave one cell unused so the host shell never performs a second,
|
|
2180
2157
|
// unthemed truncation after this renderer has applied toolTitle.
|
package/extensions/context.ts
CHANGED
|
@@ -10,12 +10,6 @@ import {
|
|
|
10
10
|
visibleWidth,
|
|
11
11
|
wrapTextWithAnsi,
|
|
12
12
|
} from "@earendil-works/pi-tui";
|
|
13
|
-
import {
|
|
14
|
-
centeredDialogBounds,
|
|
15
|
-
isDialogCloseClick,
|
|
16
|
-
renderDialogHeader,
|
|
17
|
-
renderDialogTopBorder,
|
|
18
|
-
} from "./closable-dialog.ts";
|
|
19
13
|
|
|
20
14
|
export type ContextPart = {
|
|
21
15
|
label: string;
|
|
@@ -71,8 +65,6 @@ export async function showTextPreview(
|
|
|
71
65
|
let scrollOffset = 0;
|
|
72
66
|
let pageSize = 1;
|
|
73
67
|
let totalLines = 1;
|
|
74
|
-
let lastWidth = 0;
|
|
75
|
-
let lastHeight = 0;
|
|
76
68
|
const wrappedContent = createWrappedTextCache(content);
|
|
77
69
|
|
|
78
70
|
const scrollTo = (nextOffset: number): void => {
|
|
@@ -85,10 +77,6 @@ export async function showTextPreview(
|
|
|
85
77
|
wrappedContent.invalidate();
|
|
86
78
|
},
|
|
87
79
|
handleInput(data: string) {
|
|
88
|
-
if (isDialogCloseClick(data, centeredDialogBounds(tui.terminal, lastWidth, lastHeight))) {
|
|
89
|
-
done(undefined);
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
80
|
if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c"))) {
|
|
93
81
|
done(undefined);
|
|
94
82
|
return;
|
|
@@ -150,24 +138,15 @@ export async function showTextPreview(
|
|
|
150
138
|
const end = Math.min(totalLines, scrollOffset + pageSize);
|
|
151
139
|
const status = `${start}-${end} / ${totalLines} lines · ↑↓ PgUp/PgDn Home/End · Esc close`;
|
|
152
140
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
` ${title}`,
|
|
157
|
-
width,
|
|
158
|
-
border,
|
|
159
|
-
(text) => theme.bold(theme.fg("accent", text)),
|
|
160
|
-
(text) => theme.fg("muted", text),
|
|
161
|
-
),
|
|
141
|
+
return [
|
|
142
|
+
border(`╭${"─".repeat(inner)}╮`),
|
|
143
|
+
`${border("│")}${padLine(` ${theme.bold(theme.fg("accent", title))}`)}${border("│")}`,
|
|
162
144
|
`${border("├")}${border("─".repeat(inner))}${border("┤")}`,
|
|
163
145
|
...bodyRows,
|
|
164
146
|
`${border("├")}${border("─".repeat(inner))}${border("┤")}`,
|
|
165
147
|
`${border("│")}${padLine(theme.fg("dim", ` ${status}`))}${border("│")}`,
|
|
166
148
|
border(`╰${"─".repeat(inner)}╯`),
|
|
167
149
|
];
|
|
168
|
-
lastWidth = width;
|
|
169
|
-
lastHeight = lines.length;
|
|
170
|
-
return lines;
|
|
171
150
|
},
|
|
172
151
|
};
|
|
173
152
|
},
|
package/package.json
CHANGED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
2
|
-
|
|
3
|
-
export type DialogBounds = { left: number; top: number; width: number };
|
|
4
|
-
|
|
5
|
-
export function renderDialogTopBorder(width: number, color: (text: string) => string): string {
|
|
6
|
-
const safeWidth = Math.max(4, Math.floor(width));
|
|
7
|
-
return color(`╭${"─".repeat(safeWidth - 2)}╮`);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/** Render title and a larger [ × ] target on the row below the top border. */
|
|
11
|
-
export function renderDialogHeader(
|
|
12
|
-
title: string,
|
|
13
|
-
width: number,
|
|
14
|
-
color: (text: string) => string,
|
|
15
|
-
titleColor: (text: string) => string,
|
|
16
|
-
closeColor: (text: string) => string,
|
|
17
|
-
): string {
|
|
18
|
-
const safeWidth = Math.max(8, Math.floor(width));
|
|
19
|
-
const innerWidth = safeWidth - 2;
|
|
20
|
-
const button = "[ × ]";
|
|
21
|
-
const titleWidth = Math.max(0, innerWidth - visibleWidth(button) - 2);
|
|
22
|
-
const shownTitle = truncateToWidth(title, titleWidth, "…");
|
|
23
|
-
const gap = " ".repeat(Math.max(1, innerWidth - visibleWidth(shownTitle) - visibleWidth(button)));
|
|
24
|
-
return `${color("│")}${titleColor(shownTitle)}${gap}${closeColor(button)}${color("│")}`;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Match a left-button press anywhere on the [ × ] target. */
|
|
28
|
-
export function isDialogCloseClick(data: string, bounds: DialogBounds): boolean {
|
|
29
|
-
const match = data.match(/^\x1b\[<(\d+);(\d+);(\d+)([Mm])$/);
|
|
30
|
-
if (!match || match[4] !== "M") return false;
|
|
31
|
-
const code = Number(match[1]);
|
|
32
|
-
if ((code & 3) !== 0 || (code & 32) !== 0) return false;
|
|
33
|
-
const col = Number(match[2]);
|
|
34
|
-
const firstButtonCol = bounds.left + bounds.width - 7;
|
|
35
|
-
const lastButtonCol = bounds.left + bounds.width - 3;
|
|
36
|
-
return col >= firstButtonCol && col <= lastButtonCol && Number(match[3]) === bounds.top + 1;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function centeredDialogBounds(
|
|
40
|
-
terminal: { columns: number; rows: number },
|
|
41
|
-
width: number,
|
|
42
|
-
height: number,
|
|
43
|
-
): DialogBounds {
|
|
44
|
-
return {
|
|
45
|
-
left: Math.floor((terminal.columns - width) / 2) + 1,
|
|
46
|
-
top: Math.floor((terminal.rows - height) / 2) + 1,
|
|
47
|
-
width,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function bottomDialogBounds(
|
|
52
|
-
terminal: { rows: number },
|
|
53
|
-
width: number,
|
|
54
|
-
height: number,
|
|
55
|
-
): DialogBounds {
|
|
56
|
-
return { left: 1, top: Math.max(1, terminal.rows - height + 1), width };
|
|
57
|
-
}
|