@danypops/pi-packed 0.12.0 → 0.13.1
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/extension/src/tui.ts +46 -16
- package/package.json +1 -1
package/extension/src/tui.ts
CHANGED
|
@@ -12,13 +12,18 @@
|
|
|
12
12
|
* only the footer moves as content height changes. Enter opens a second,
|
|
13
13
|
* smaller overlay action menu on top of it. U's batch update stays on
|
|
14
14
|
* this same package list -- progress renders inline next to the row
|
|
15
|
-
* currently being updated, not as a separate screen.
|
|
16
|
-
*
|
|
15
|
+
* currently being updated, not as a separate screen. Rows render through
|
|
16
|
+
* Malevich's Table (real column-aligned Package/Version/status cells,
|
|
17
|
+
* per-row selection styling baked into each cell since Table's own
|
|
18
|
+
* cellStyle is column-wide, not row-wide) inside this panel's own
|
|
19
|
+
* scroll-window slice -- Table deliberately owns no pagination of its
|
|
20
|
+
* own, so the visible-window-around-selectedIndex math stays here. All
|
|
21
|
+
* data flows through the packed CLI (thin seam).
|
|
17
22
|
*/
|
|
18
23
|
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
19
24
|
import { DynamicBorder, rawKeyHint } from "@earendil-works/pi-coding-agent";
|
|
20
|
-
import { Container, Input, Spacer, truncateToWidth } from "@earendil-works/pi-tui";
|
|
21
|
-
import { Envelope, Menu, ProgressBar, type MenuItem } from "malevich-tui-components";
|
|
25
|
+
import { Container, Input, Spacer, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
26
|
+
import { Envelope, Menu, ProgressBar, Table, type MenuItem, type TableColumn, type TextMeasure } from "malevich-tui-components";
|
|
22
27
|
import { filterRows, mergeRows, nextMode, visibleRows } from "./model.js";
|
|
23
28
|
import type { Row, ViewMode } from "./model.js";
|
|
24
29
|
import type { Natives, PackageResources } from "./packed.js";
|
|
@@ -409,6 +414,19 @@ function renderPanel(ctx: ExtensionCommandContext, natives: Natives, initialRows
|
|
|
409
414
|
},
|
|
410
415
|
};
|
|
411
416
|
|
|
417
|
+
// pi-tui's own visibleWidth/truncateToWidth are ANSI-aware (they strip
|
|
418
|
+
// escape codes for measurement, matching the pair Malevich's TextMeasure
|
|
419
|
+
// port expects) -- rows below bake selection/status styling directly
|
|
420
|
+
// into each cell's text since Table's own cellStyle is column-wide, not
|
|
421
|
+
// per-row.
|
|
422
|
+
const measure: TextMeasure = { visibleWidth, truncateToWidth };
|
|
423
|
+
const columns: TableColumn[] = [
|
|
424
|
+
{ header: "Package", key: "name" },
|
|
425
|
+
{ header: "Version", key: "version" },
|
|
426
|
+
{ header: "", key: "status" },
|
|
427
|
+
];
|
|
428
|
+
const table = new Table({ columns, rows: [], measure, headerStyle: (s) => theme.fg("muted", s) });
|
|
429
|
+
|
|
412
430
|
const list = {
|
|
413
431
|
invalidate() {},
|
|
414
432
|
render(width: number): string[] {
|
|
@@ -419,20 +437,25 @@ function renderPanel(ctx: ExtensionCommandContext, natives: Natives, initialRows
|
|
|
419
437
|
lines.push(theme.fg("muted", " No packages"));
|
|
420
438
|
return lines;
|
|
421
439
|
}
|
|
440
|
+
// No scrolling of its own (Malevich's Table is deliberately
|
|
441
|
+
// unopinionated about pagination) -- the visible window around
|
|
442
|
+
// selectedIndex stays this panel's own job, same as before.
|
|
422
443
|
const start = Math.max(0, Math.min(selectedIndex - Math.floor(maxVisible / 2), filtered.length - maxVisible));
|
|
423
444
|
const end = Math.min(start + maxVisible, filtered.length);
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
445
|
+
table.setRows(
|
|
446
|
+
filtered.slice(start, end).map((row, offset) => {
|
|
447
|
+
const i = start + offset;
|
|
448
|
+
const selected = i === selectedIndex;
|
|
449
|
+
const cursor = selected ? theme.fg("accent", "❯ ") : " ";
|
|
450
|
+
const name = selected ? theme.bold(row.name) : row.name;
|
|
451
|
+
const isUpdating = updatingRowName === row.name;
|
|
452
|
+
const status = isUpdating
|
|
453
|
+
? theme.fg("accent", `${updatingBar.format(10)} updating…`)
|
|
454
|
+
: row.hasUpdate ? theme.fg("warning", `↑${row.latest}`) : "";
|
|
455
|
+
return { name: `${cursor}${name}`, version: theme.fg("dim", row.version), status };
|
|
456
|
+
}),
|
|
457
|
+
);
|
|
458
|
+
lines.push(...table.render(width));
|
|
436
459
|
const hasScroll = start > 0 || end < filtered.length;
|
|
437
460
|
lines.push(theme.fg("dim", ` ${hasScroll ? `${selectedIndex + 1}/${filtered.length} ` : ""}${mode}`));
|
|
438
461
|
return lines;
|
|
@@ -441,11 +464,18 @@ function renderPanel(ctx: ExtensionCommandContext, natives: Natives, initialRows
|
|
|
441
464
|
|
|
442
465
|
// Real bordered box (rounded corners), not just a horizontal rule --
|
|
443
466
|
// title carries the live update badge/status instead of a header line.
|
|
467
|
+
// measure must be explicit: Envelope's own default is ASCII-only (raw
|
|
468
|
+
// .length, blind to ANSI escape codes) and every line below is styled
|
|
469
|
+
// through theme.fg/theme.bold -- without this, Envelope pads each line
|
|
470
|
+
// against its own escape-code-inflated "length" instead of its real
|
|
471
|
+
// visible width, so the right border lands at a different column on
|
|
472
|
+
// every line depending on how much styling that particular line has.
|
|
444
473
|
const envelope = new Envelope({
|
|
445
474
|
title: panelTitle(),
|
|
446
475
|
borderStyle: "rounded",
|
|
447
476
|
style: (s) => theme.fg("border", s),
|
|
448
477
|
titleStyle: (s) => theme.bold(theme.fg("accent", s)),
|
|
478
|
+
measure,
|
|
449
479
|
});
|
|
450
480
|
const body = {
|
|
451
481
|
invalidate() { header.invalidate(); list.invalidate(); },
|