@aemonge-dev/pi-stardeck 0.5.0 → 0.7.0

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.
Files changed (30) hide show
  1. package/README.md +3 -2
  2. package/docs/architecture.md +8 -5
  3. package/licenses/README.md +9 -7
  4. package/package.json +2 -2
  5. package/packages/footer/README.md +15 -0
  6. package/packages/footer/index.ts +37 -0
  7. package/packages/footer/package.json +32 -0
  8. package/packages/footer/src/protocol.ts +10 -0
  9. package/packages/footer/src/quota.ts +26 -0
  10. package/packages/footer/src/telemetry.ts +59 -0
  11. package/packages/pi-stardeck/README.md +7 -6
  12. package/packages/pi-stardeck/src/deck.ts +79 -44
  13. package/packages/status/package.json +1 -1
  14. package/src/health.ts +0 -1
  15. package/src/index.ts +3 -4
  16. package/licenses/pi-fancy-footer-LICENSE +0 -21
  17. package/packages/pi-fancy-footer-full-palette/LICENSE +0 -21
  18. package/packages/pi-fancy-footer-full-palette/LOCAL-CHANGES.md +0 -41
  19. package/packages/pi-fancy-footer-full-palette/README.md +0 -468
  20. package/packages/pi-fancy-footer-full-palette/package.json +0 -52
  21. package/packages/pi-fancy-footer-full-palette/src/api.ts +0 -204
  22. package/packages/pi-fancy-footer-full-palette/src/config-editor.ts +0 -634
  23. package/packages/pi-fancy-footer-full-palette/src/config.ts +0 -852
  24. package/packages/pi-fancy-footer-full-palette/src/data-widgets.ts +0 -259
  25. package/packages/pi-fancy-footer-full-palette/src/git.ts +0 -130
  26. package/packages/pi-fancy-footer-full-palette/src/index.ts +0 -479
  27. package/packages/pi-fancy-footer-full-palette/src/layout.ts +0 -309
  28. package/packages/pi-fancy-footer-full-palette/src/provider-status.ts +0 -1466
  29. package/packages/pi-fancy-footer-full-palette/src/render.ts +0 -1061
  30. package/packages/pi-fancy-footer-full-palette/src/shared.ts +0 -903
@@ -1,634 +0,0 @@
1
- import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
- import {
3
- Key,
4
- matchesKey,
5
- truncateToWidth,
6
- visibleWidth,
7
- wrapTextWithAnsi,
8
- type Component,
9
- } from "@earendil-works/pi-tui";
10
- import {
11
- buildConfigurableWidgets,
12
- genericFooterSettingsItems,
13
- plainSettingValue,
14
- widgetSettingsSubmenu,
15
- type ConfigurableWidgetMeta,
16
- } from "./config.ts";
17
- import {
18
- buildLayoutModel,
19
- cycleAlign,
20
- moveHorizontal,
21
- moveVertical,
22
- setBenched,
23
- toggleFill,
24
- type LayoutChip,
25
- type LayoutModel,
26
- type LayoutRow,
27
- } from "./layout.ts";
28
- import {
29
- isGaugeStyleId,
30
- MIN_GAUGE_WIDTH,
31
- MAX_GAUGE_WIDTH,
32
- isFooterIconFamily,
33
- isFooterWidgetColor,
34
- type FooterConfigSnapshot,
35
- } from "./shared.ts";
36
- import type { NormalizedFancyFooterDataWidget } from "./data-widgets.ts";
37
-
38
- interface OpenFooterConfigEditorOptions {
39
- ctx: ExtensionContext;
40
- configPath: string;
41
- draft: FooterConfigSnapshot;
42
- extensionWidgets: readonly NormalizedFancyFooterDataWidget[];
43
- applyDraft: () => void;
44
- }
45
-
46
- type Selection =
47
- { area: "grid" | "bench"; widgetId: string } | { area: "globals"; index: number };
48
-
49
- interface ChipSpan {
50
- start: number;
51
- end: number;
52
- }
53
-
54
- // Each chip row independently degrades until it fits: full widget names,
55
- // then short names, then icons only. The status line under the preview
56
- // always shows the selected widget's full name.
57
- type ChipMode = "full" | "short" | "icon";
58
- const CHIP_MODES: readonly ChipMode[] = ["full", "short", "icon"];
59
- const CHIP_GAP = 2;
60
-
61
- export async function openFooterConfigEditor({
62
- ctx,
63
- configPath,
64
- draft,
65
- extensionWidgets,
66
- applyDraft,
67
- }: OpenFooterConfigEditorOptions): Promise<void> {
68
- await ctx.ui.custom((tui, theme, keybindings, done) => {
69
- let submenu: Component | undefined;
70
- // Screen columns of the last selected chip's center, used to pick the
71
- // nearest chip when moving between rows.
72
- let preferredColumn = 0;
73
- let chipSpans = new Map<string, ChipSpan>();
74
-
75
- const widgets = (): ConfigurableWidgetMeta[] =>
76
- buildConfigurableWidgets(draft, extensionWidgets);
77
-
78
- const model = (): LayoutModel => buildLayoutModel(draft, widgets());
79
-
80
- const globalsItems = () => genericFooterSettingsItems(draft, theme);
81
-
82
- const initialSelection = (): Selection => {
83
- const current = model();
84
- for (const row of current.rows) {
85
- if (row.ordered.length > 0) {
86
- return { area: "grid", widgetId: row.ordered[0]!.widget.id };
87
- }
88
- }
89
- if (current.bench.length > 0) {
90
- return { area: "bench", widgetId: current.bench[0]!.widget.id };
91
- }
92
- return { area: "globals", index: 0 };
93
- };
94
-
95
- let selection: Selection = initialSelection();
96
-
97
- // ── selection helpers ────────────────────────────────────────────
98
-
99
- // Non-empty chip rows in navigation order: grid rows, then the bench.
100
- type NavRow =
101
- { kind: "grid"; row: LayoutRow } | { kind: "bench"; chips: LayoutChip[] };
102
-
103
- const navRows = (current: LayoutModel): NavRow[] => {
104
- const rows: NavRow[] = current.rows
105
- .filter((row) => row.ordered.length > 0)
106
- .map((row) => ({ kind: "grid" as const, row }));
107
- if (current.bench.length > 0) {
108
- rows.push({ kind: "bench", chips: current.bench });
109
- }
110
- return rows;
111
- };
112
-
113
- const navRowChips = (row: NavRow): LayoutChip[] =>
114
- row.kind === "grid" ? row.row.ordered : row.chips;
115
-
116
- const findNavIndex = (rows: NavRow[], widgetId: string): number =>
117
- rows.findIndex((row) =>
118
- navRowChips(row).some((chip) => chip.widget.id === widgetId),
119
- );
120
-
121
- const chipCenter = (widgetId: string): number => {
122
- const span = chipSpans.get(widgetId);
123
- if (!span) return preferredColumn;
124
- return Math.floor((span.start + span.end) / 2);
125
- };
126
-
127
- const nearestChip = (row: NavRow, column: number): LayoutChip => {
128
- const chips = navRowChips(row);
129
- let best = chips[0]!;
130
- let bestDistance = Infinity;
131
- for (const chip of chips) {
132
- const distance = Math.abs(chipCenter(chip.widget.id) - column);
133
- if (distance < bestDistance) {
134
- best = chip;
135
- bestDistance = distance;
136
- }
137
- }
138
- return best;
139
- };
140
-
141
- const selectChip = (chip: LayoutChip) => {
142
- selection = {
143
- area: chip.placement.benched ? "bench" : "grid",
144
- widgetId: chip.widget.id,
145
- };
146
- preferredColumn = chipCenter(chip.widget.id);
147
- };
148
-
149
- // After a mutation the selected widget may have changed rows or moved
150
- // between the grid and the bench; recompute which area it lives in.
151
- const syncSelection = () => {
152
- if (selection.area === "globals") return;
153
- const widgetId = selection.widgetId;
154
- const current = model();
155
- const benched = current.bench.some((chip) => chip.widget.id === widgetId);
156
- selection = { area: benched ? "bench" : "grid", widgetId };
157
- };
158
-
159
- const moveSelectionHorizontal = (direction: -1 | 1) => {
160
- if (selection.area === "globals") return;
161
- const rows = navRows(model());
162
- const index = findNavIndex(rows, selection.widgetId);
163
- if (index < 0) return;
164
- const chips = navRowChips(rows[index]!);
165
- const chipIndex = chips.findIndex(
166
- (chip) => chip.widget.id === (selection as { widgetId: string }).widgetId,
167
- );
168
- const next = chips[chipIndex + direction];
169
- if (next) selectChip(next);
170
- };
171
-
172
- const moveSelectionVertical = (direction: -1 | 1) => {
173
- const current = model();
174
- const rows = navRows(current);
175
- const globals = globalsItems();
176
-
177
- if (selection.area === "globals") {
178
- const next = selection.index + direction;
179
- if (next >= 0 && next < globals.length) {
180
- selection = { area: "globals", index: next };
181
- } else if (next < 0 && rows.length > 0) {
182
- selectChip(nearestChip(rows[rows.length - 1]!, preferredColumn));
183
- }
184
- return;
185
- }
186
-
187
- const index = findNavIndex(rows, selection.widgetId);
188
- if (index < 0) return;
189
- const target = index + direction;
190
- if (target >= 0 && target < rows.length) {
191
- preferredColumn = chipCenter(selection.widgetId);
192
- selectChip(nearestChip(rows[target]!, preferredColumn));
193
- } else if (target >= rows.length && globals.length > 0) {
194
- preferredColumn = chipCenter(selection.widgetId);
195
- selection = { area: "globals", index: 0 };
196
- }
197
- };
198
-
199
- // ── widget actions ───────────────────────────────────────────────
200
-
201
- const chipActions: {
202
- keys: string[];
203
- hint?: string;
204
- run: (widgetId: string) => void;
205
- }[] = [
206
- {
207
- keys: ["l"],
208
- run: (id) => moveHorizontal(draft, widgets(), id, -1),
209
- },
210
- {
211
- keys: ["r"],
212
- hint: "l/r move",
213
- run: (id) => moveHorizontal(draft, widgets(), id, 1),
214
- },
215
- {
216
- keys: ["u"],
217
- run: (id) => moveVertical(draft, widgets(), id, -1),
218
- },
219
- {
220
- keys: ["d"],
221
- hint: "u/d row",
222
- run: (id) => moveVertical(draft, widgets(), id, 1),
223
- },
224
- {
225
- keys: ["a"],
226
- hint: "a align",
227
- run: (id) => cycleAlign(draft, widgets(), id),
228
- },
229
- {
230
- keys: ["f"],
231
- hint: "f fill",
232
- run: (id) => toggleFill(draft, widgets(), id),
233
- },
234
- {
235
- keys: ["x", " "],
236
- hint: "x hide",
237
- run: (id) => {
238
- const benched = model().bench.some((chip) => chip.widget.id === id);
239
- setBenched(draft, widgets(), id, !benched);
240
- },
241
- },
242
- ];
243
-
244
- const chipHints = [
245
- "←→↑↓ select",
246
- ...chipActions.map((action) => action.hint).filter(Boolean),
247
- "⏎ settings",
248
- "esc close",
249
- ].join(" · ");
250
-
251
- const globalsHints = "↑↓ navigate · ⏎/space change · esc close";
252
-
253
- // ── globals mutation (value cycling) ─────────────────────────────
254
-
255
- const setGenericField = (fieldId: string, newValue: string) => {
256
- switch (fieldId) {
257
- case "refreshMs": {
258
- const parsed = Number(newValue);
259
- if (Number.isInteger(parsed)) draft.refreshMs = parsed;
260
- break;
261
- }
262
- case "iconFamily":
263
- if (isFooterIconFamily(newValue)) draft.iconFamily = newValue;
264
- break;
265
- case "gaugeStyle": {
266
- const style = plainSettingValue(newValue);
267
- if (isGaugeStyleId(style)) draft.gaugeStyle = style;
268
- break;
269
- }
270
- case "gaugeColorOk": {
271
- const color = plainSettingValue(newValue);
272
- if (isFooterWidgetColor(color)) draft.gaugeColors.ok = color;
273
- break;
274
- }
275
- case "gaugeColorWarning": {
276
- const color = plainSettingValue(newValue);
277
- if (isFooterWidgetColor(color)) draft.gaugeColors.warning = color;
278
- break;
279
- }
280
- case "gaugeColorError": {
281
- const color = plainSettingValue(newValue);
282
- if (isFooterWidgetColor(color)) draft.gaugeColors.error = color;
283
- break;
284
- }
285
- case "gaugeWidth": {
286
- const parsed = Number(newValue);
287
- if (
288
- Number.isInteger(parsed) &&
289
- parsed >= MIN_GAUGE_WIDTH &&
290
- parsed <= MAX_GAUGE_WIDTH
291
- ) {
292
- draft.gaugeWidth = parsed;
293
- }
294
- break;
295
- }
296
- case "defaultTextColor": {
297
- const color = plainSettingValue(newValue);
298
- if (isFooterWidgetColor(color)) draft.defaultTextColor = color;
299
- break;
300
- }
301
- case "defaultIconColor": {
302
- const color = plainSettingValue(newValue);
303
- if (isFooterWidgetColor(color)) draft.defaultIconColor = color;
304
- break;
305
- }
306
- }
307
- };
308
-
309
- const cycleGlobalValue = () => {
310
- if (selection.area !== "globals") return;
311
- const item = globalsItems()[selection.index];
312
- if (!item?.values || item.values.length === 0) return;
313
- const currentIndex = item.values.indexOf(item.currentValue);
314
- const nextValue =
315
- item.values[(currentIndex + 1 + item.values.length) % item.values.length];
316
- if (nextValue === undefined) return;
317
- setGenericField(item.id, nextValue);
318
- applyDraft();
319
- };
320
-
321
- const activateSelection = () => {
322
- if (selection.area === "globals") {
323
- cycleGlobalValue();
324
- return;
325
- }
326
- const widget = widgets().find(
327
- (entry) => entry.id === (selection as { widgetId: string }).widgetId,
328
- );
329
- if (!widget) return;
330
- submenu = widgetSettingsSubmenu(draft, theme, widget, () => {
331
- applyDraft();
332
- tui.requestRender();
333
- })("", () => {
334
- submenu = undefined;
335
- tui.requestRender();
336
- });
337
- };
338
-
339
- // ── preview rendering ────────────────────────────────────────────
340
-
341
- const chipText = (chip: LayoutChip, mode: ChipMode): string => {
342
- const icon = chip.widget.defaultIcon?.text ?? "◌";
343
- if (mode === "icon") return icon;
344
- const label = mode === "full" ? chip.widget.label : chip.widget.shortLabel;
345
- const grow = chip.placement.fill === "grow" ? " ↔" : "";
346
- return `${icon} ${label}${grow}`;
347
- };
348
-
349
- const styledChip = (
350
- chip: LayoutChip,
351
- mode: ChipMode,
352
- selected: boolean,
353
- ): string => {
354
- const plain = chipText(chip, mode);
355
- if (selected) return theme.inverse(plain);
356
- if (chip.placement.benched) return theme.fg("dim", plain);
357
-
358
- const icon = chip.widget.defaultIcon?.text ?? "◌";
359
- const iconColor = chip.widget.defaultIcon ? draft.defaultIconColor : "dim";
360
- if (mode === "icon") return theme.fg(iconColor, icon);
361
- const label = mode === "full" ? chip.widget.label : chip.widget.shortLabel;
362
- const grow = chip.placement.fill === "grow" ? theme.fg("dim", " ↔") : "";
363
- return `${theme.fg(iconColor, icon)} ${label}${grow}`;
364
- };
365
-
366
- interface PlacedChip {
367
- chip: LayoutChip;
368
- column: number;
369
- width: number;
370
- }
371
-
372
- const groupWidth = (chips: LayoutChip[], mode: ChipMode) =>
373
- chips.reduce(
374
- (acc, chip, index) =>
375
- acc + visibleWidth(chipText(chip, mode)) + (index > 0 ? CHIP_GAP : 0),
376
- 0,
377
- );
378
-
379
- const rowFits = (contentWidth: number, row: LayoutRow, mode: ChipMode): boolean => {
380
- const blocks = [
381
- groupWidth(row.groups.left, mode),
382
- groupWidth(row.groups.middle, mode),
383
- groupWidth(row.groups.right, mode),
384
- ].filter((width) => width > 0);
385
- return (
386
- blocks.reduce((acc, width) => acc + width, 0) +
387
- (blocks.length - 1) * CHIP_GAP <=
388
- contentWidth
389
- );
390
- };
391
-
392
- // The widest mode in which the row fits; icons-only as a last resort.
393
- const rowChipMode = (contentWidth: number, row: LayoutRow): ChipMode =>
394
- CHIP_MODES.find((mode) => rowFits(contentWidth, row, mode)) ?? "icon";
395
-
396
- // Mirrors composeAlignedRow() in render.ts: left group flush left, right
397
- // group flush right, middle group centered. Falls back to a flat join
398
- // when the row overflows even icons-only.
399
- const placeRowChips = (
400
- contentWidth: number,
401
- row: LayoutRow,
402
- mode: ChipMode,
403
- ): PlacedChip[] => {
404
- const leftWidth = groupWidth(row.groups.left, mode);
405
- const middleWidth = groupWidth(row.groups.middle, mode);
406
- const rightWidth = groupWidth(row.groups.right, mode);
407
-
408
- const placed: PlacedChip[] = [];
409
- const placeGroup = (chips: LayoutChip[], start: number) => {
410
- let column = start;
411
- for (const chip of chips) {
412
- const width = visibleWidth(chipText(chip, mode));
413
- placed.push({ chip, column, width });
414
- column += width + CHIP_GAP;
415
- }
416
- };
417
-
418
- if (!rowFits(contentWidth, row, mode)) {
419
- placeGroup(row.ordered, 0);
420
- return placed;
421
- }
422
-
423
- placeGroup(row.groups.left, 0);
424
- const rightStart = contentWidth - rightWidth;
425
- let middleStart = Math.floor((contentWidth - middleWidth) / 2);
426
- middleStart = Math.max(
427
- leftWidth > 0 ? leftWidth + CHIP_GAP : 0,
428
- Math.min(
429
- middleStart,
430
- rightWidth > 0
431
- ? rightStart - CHIP_GAP - middleWidth
432
- : contentWidth - middleWidth,
433
- ),
434
- );
435
- placeGroup(row.groups.middle, middleStart);
436
- placeGroup(row.groups.right, rightStart);
437
- return placed;
438
- };
439
-
440
- const renderChipLine = (
441
- width: number,
442
- gutter: string,
443
- placed: PlacedChip[],
444
- mode: ChipMode,
445
- selectedId: string | undefined,
446
- ): string => {
447
- const gutterWidth = visibleWidth(gutter);
448
- let line = gutter;
449
- let column = 0;
450
- for (const entry of placed) {
451
- if (entry.column > column) {
452
- line += " ".repeat(entry.column - column);
453
- column = entry.column;
454
- }
455
- line += styledChip(entry.chip, mode, entry.chip.widget.id === selectedId);
456
- chipSpans.set(entry.chip.widget.id, {
457
- start: gutterWidth + entry.column,
458
- end: gutterWidth + entry.column + entry.width,
459
- });
460
- column += entry.width;
461
- }
462
- return truncateToWidth(line, width);
463
- };
464
-
465
- const selectedDescription = (): string | undefined => {
466
- if (selection.area === "globals") {
467
- return globalsItems()[selection.index]?.description;
468
- }
469
- const widgetId = selection.widgetId;
470
- return widgets().find((entry) => entry.id === widgetId)?.description;
471
- };
472
-
473
- return {
474
- render(width: number) {
475
- if (submenu) return submenu.render(width);
476
-
477
- const current = model();
478
- const selectedId =
479
- selection.area === "globals" ? undefined : selection.widgetId;
480
- chipSpans = new Map();
481
-
482
- const lines = [
483
- truncateToWidth(
484
- theme.fg("accent", theme.bold("Fancy Footer Configuration")),
485
- width,
486
- ),
487
- truncateToWidth(theme.fg("dim", configPath), width),
488
- "",
489
- truncateToWidth(theme.bold("Widgets"), width),
490
- ];
491
-
492
- const gutterDigits = String(current.rows.length - 1).length;
493
- for (const row of current.rows) {
494
- const gutter = theme.fg("dim", `${String(row.row).padStart(gutterDigits)}│ `);
495
- if (row.ordered.length === 0) {
496
- lines.push(
497
- truncateToWidth(`${gutter}${theme.fg("dim", "(empty)")}`, width),
498
- );
499
- continue;
500
- }
501
- const contentWidth = Math.max(10, width - gutterDigits - 2);
502
- const mode = rowChipMode(contentWidth, row);
503
- const placed = placeRowChips(contentWidth, row, mode);
504
- lines.push(renderChipLine(width, gutter, placed, mode, selectedId));
505
- }
506
-
507
- if (current.bench.length > 0) {
508
- lines.push(truncateToWidth(theme.fg("dim", "hidden"), width));
509
- const gutter = " ".repeat(gutterDigits + 2);
510
- const contentWidth = Math.max(10, width - gutterDigits - 2);
511
- const mode =
512
- CHIP_MODES.find(
513
- (candidate) => groupWidth(current.bench, candidate) <= contentWidth,
514
- ) ?? "icon";
515
- const placedBench: PlacedChip[] = [];
516
- let column = 0;
517
- for (const chip of current.bench) {
518
- const chipWidth = visibleWidth(chipText(chip, mode));
519
- placedBench.push({ chip, column, width: chipWidth });
520
- column += chipWidth + CHIP_GAP;
521
- }
522
- lines.push(renderChipLine(width, gutter, placedBench, mode, selectedId));
523
- }
524
-
525
- if (selection.area !== "globals") {
526
- const widgetId = selection.widgetId;
527
- const chip =
528
- current.rows
529
- .flatMap((row) => row.ordered)
530
- .find((entry) => entry.widget.id === widgetId) ??
531
- current.bench.find((entry) => entry.widget.id === widgetId);
532
- if (chip) {
533
- const placement = chip.placement;
534
- const group = placement.benched
535
- ? current.bench
536
- : current.rows[placement.row]!.groups[placement.align];
537
- const index = group.findIndex((entry) => entry.widget.id === widgetId);
538
- const info = placement.benched
539
- ? "hidden"
540
- : `row ${placement.row} · ${placement.align} · pos ${index}${
541
- placement.fill === "grow" ? " · grow" : ""
542
- }`;
543
- lines.push("");
544
- lines.push(
545
- truncateToWidth(
546
- `${theme.inverse(chip.widget.label)} ${theme.fg("dim", `— ${info}`)}`,
547
- width,
548
- ),
549
- );
550
- }
551
- }
552
-
553
- lines.push("");
554
- lines.push(truncateToWidth(theme.bold("General"), width));
555
- const globals = globalsItems();
556
- const labelWidth = Math.min(
557
- Math.max(...globals.map((item) => visibleWidth(item.label)), 0),
558
- Math.max(8, width - 12),
559
- );
560
- for (const [index, item] of globals.entries()) {
561
- const selected = selection.area === "globals" && selection.index === index;
562
- const prefix = selected ? theme.fg("accent", "→ ") : " ";
563
- const label = truncateToWidth(item.label, labelWidth, "");
564
- const paddedLabel =
565
- label + " ".repeat(Math.max(0, labelWidth - visibleWidth(label)));
566
- const valueWidth = Math.max(4, width - 2 - labelWidth - 2);
567
- const value = truncateToWidth(item.currentValue, valueWidth, "");
568
- lines.push(
569
- truncateToWidth(
570
- `${prefix}${selected ? theme.fg("accent", paddedLabel) : paddedLabel} ${selected ? theme.fg("accent", value) : theme.fg("dim", value)}`,
571
- width,
572
- ),
573
- );
574
- }
575
-
576
- const description = selectedDescription();
577
- if (description) {
578
- lines.push("");
579
- for (const line of wrapTextWithAnsi(description, Math.max(10, width - 2))) {
580
- lines.push(truncateToWidth(theme.fg("dim", line), width));
581
- }
582
- }
583
-
584
- lines.push("");
585
- lines.push(
586
- truncateToWidth(
587
- theme.fg("dim", selection.area === "globals" ? globalsHints : chipHints),
588
- width,
589
- ),
590
- );
591
-
592
- return lines;
593
- },
594
- invalidate() {
595
- submenu?.invalidate?.();
596
- },
597
- handleInput(data: string) {
598
- if (submenu) {
599
- submenu.handleInput?.(data);
600
- tui.requestRender();
601
- return;
602
- }
603
-
604
- if (keybindings.matches(data, "tui.select.cancel")) {
605
- done(undefined);
606
- return;
607
- }
608
-
609
- if (matchesKey(data, Key.left)) {
610
- moveSelectionHorizontal(-1);
611
- } else if (matchesKey(data, Key.right)) {
612
- moveSelectionHorizontal(1);
613
- } else if (keybindings.matches(data, "tui.select.up")) {
614
- moveSelectionVertical(-1);
615
- } else if (keybindings.matches(data, "tui.select.down")) {
616
- moveSelectionVertical(1);
617
- } else if (keybindings.matches(data, "tui.select.confirm")) {
618
- activateSelection();
619
- } else if (selection.area === "globals" && data === " ") {
620
- cycleGlobalValue();
621
- } else if (selection.area !== "globals") {
622
- const action = chipActions.find((entry) => entry.keys.includes(data));
623
- if (action) {
624
- action.run(selection.widgetId);
625
- applyDraft();
626
- syncSelection();
627
- }
628
- }
629
-
630
- tui.requestRender();
631
- },
632
- };
633
- });
634
- }