@nmakarov/cli-toolkit 0.69.0 → 0.70.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.
- package/dist/cli-runner.cjs +312 -181
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +312 -181
- package/dist/cli-runner.js.map +1 -1
- package/dist/index.cjs +350 -197
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +344 -197
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +129 -91
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +129 -91
- package/dist/init.js.map +1 -1
- package/dist/screen.cjs +124 -90
- package/dist/screen.cjs.map +1 -1
- package/dist/screen.js +121 -90
- package/dist/screen.js.map +1 -1
- package/dist/tasks.cjs +218 -106
- package/dist/tasks.cjs.map +1 -1
- package/dist/tasks.js +215 -106
- package/dist/tasks.js.map +1 -1
- package/package.json +2 -2
package/dist/init.js
CHANGED
|
@@ -93,9 +93,48 @@ var init_components = __esm({
|
|
|
93
93
|
}
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
+
// src/screen/scrollbar.js
|
|
97
|
+
function scrollbarGlyphs(viewportRows, totalLines, scrollTop) {
|
|
98
|
+
const view = Math.max(1, Math.floor(viewportRows));
|
|
99
|
+
const total = Math.max(0, Math.floor(totalLines));
|
|
100
|
+
if (total <= view) return null;
|
|
101
|
+
const maxScroll = total - view;
|
|
102
|
+
const thumbSize = Math.max(1, Math.round(view / total * view));
|
|
103
|
+
const travel = Math.max(0, view - thumbSize);
|
|
104
|
+
const s = Math.min(Math.max(0, Math.floor(scrollTop)), maxScroll);
|
|
105
|
+
const thumbStart = maxScroll === 0 ? 0 : Math.round(s / maxScroll * travel);
|
|
106
|
+
const glyphs = [];
|
|
107
|
+
for (let i = 0; i < view; i++) {
|
|
108
|
+
glyphs.push(i >= thumbStart && i < thumbStart + thumbSize ? BAR_THUMB : BAR_TRACK);
|
|
109
|
+
}
|
|
110
|
+
return glyphs;
|
|
111
|
+
}
|
|
112
|
+
var BAR_THUMB, BAR_TRACK, PAGE_SCROLL_KEY_BINDINGS;
|
|
113
|
+
var init_scrollbar = __esm({
|
|
114
|
+
"src/screen/scrollbar.js"() {
|
|
115
|
+
BAR_THUMB = "#";
|
|
116
|
+
BAR_TRACK = "|";
|
|
117
|
+
PAGE_SCROLL_KEY_BINDINGS = [
|
|
118
|
+
{ key: "upArrow", meta: true, caption: "page", action: "pageUp", order: 0 },
|
|
119
|
+
{ key: "downArrow", meta: true, caption: "page", action: "pageDown", order: 0 },
|
|
120
|
+
{ key: "upArrow", ctrl: true, caption: "page", action: "pageUp", order: 0 },
|
|
121
|
+
{ key: "downArrow", ctrl: true, caption: "page", action: "pageDown", order: 0 },
|
|
122
|
+
{ key: "pageUp", caption: "page", action: "pageUp", order: 0 },
|
|
123
|
+
{ key: "pageDown", caption: "page", action: "pageDown", order: 0 }
|
|
124
|
+
];
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
96
128
|
// src/screen/list-components.js
|
|
97
129
|
import React, { useState, useEffect, useRef, createElement } from "react";
|
|
98
130
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
131
|
+
function clipNameForScrollbar(name, needsBar) {
|
|
132
|
+
if (!needsBar || name == null) return name;
|
|
133
|
+
const s = String(name);
|
|
134
|
+
if (s.length <= 1) return s;
|
|
135
|
+
if (/\s$/.test(s)) return s.slice(0, -1);
|
|
136
|
+
return s;
|
|
137
|
+
}
|
|
99
138
|
function MultiColumnListComponent({ items, ctx, selectedIndexRef }) {
|
|
100
139
|
const [, forceUpdate] = useState({});
|
|
101
140
|
const termWidth = (process.stdout.columns || 80) - 8;
|
|
@@ -309,17 +348,42 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
|
|
|
309
348
|
});
|
|
310
349
|
ctx.setAction("scrollUp", () => {
|
|
311
350
|
const { scrollOffset: currentScrollOffset } = scrollStateRef.current;
|
|
312
|
-
|
|
313
|
-
setScrollOffset(newScrollOffset);
|
|
351
|
+
setScrollOffset(Math.max(0, currentScrollOffset - 1));
|
|
314
352
|
forceUpdate({});
|
|
315
353
|
});
|
|
316
354
|
ctx.setAction("scrollDown", () => {
|
|
317
355
|
const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;
|
|
318
356
|
const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);
|
|
319
|
-
|
|
320
|
-
|
|
357
|
+
setScrollOffset(Math.min(currentMaxScrollOffset, currentScrollOffset + 1));
|
|
358
|
+
forceUpdate({});
|
|
359
|
+
});
|
|
360
|
+
ctx.setAction("pageUp", () => {
|
|
361
|
+
const { maxHeight: vh } = scrollStateRef.current;
|
|
362
|
+
const page = Math.max(1, vh || 1);
|
|
363
|
+
const newIndex = Math.max(0, selectedIndexRef.current - page);
|
|
364
|
+
selectedIndexRef.current = newIndex;
|
|
365
|
+
const list = displayItemsRef.current;
|
|
366
|
+
onSelectionChangeRef.current?.(newIndex, list[newIndex]);
|
|
367
|
+
setScrollOffset(newIndex);
|
|
321
368
|
forceUpdate({});
|
|
322
369
|
});
|
|
370
|
+
ctx.setAction("pageDown", () => {
|
|
371
|
+
const { maxHeight: vh, totalItems } = scrollStateRef.current;
|
|
372
|
+
const page = Math.max(1, vh || 1);
|
|
373
|
+
const maxIndex = Math.max(0, totalItems - 1);
|
|
374
|
+
const newIndex = Math.min(maxIndex, selectedIndexRef.current + page);
|
|
375
|
+
selectedIndexRef.current = newIndex;
|
|
376
|
+
const list = displayItemsRef.current;
|
|
377
|
+
onSelectionChangeRef.current?.(newIndex, list[newIndex]);
|
|
378
|
+
const maxScroll = Math.max(0, totalItems - page);
|
|
379
|
+
setScrollOffset(Math.min(maxScroll, Math.max(0, newIndex - page + 1)));
|
|
380
|
+
forceUpdate({});
|
|
381
|
+
});
|
|
382
|
+
const navBindings = [
|
|
383
|
+
{ key: "upArrow", caption: "navigate", action: "moveUp", order: 0 },
|
|
384
|
+
{ key: "downArrow", caption: "navigate", action: "moveDown", order: 0 },
|
|
385
|
+
...PAGE_SCROLL_KEY_BINDINGS
|
|
386
|
+
];
|
|
323
387
|
if (sortable) {
|
|
324
388
|
ctx.setAction("toggleSort", () => {
|
|
325
389
|
const nextSort = sortOrder === "none" ? "asc" : sortOrder === "asc" ? "desc" : "none";
|
|
@@ -366,8 +430,7 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
|
|
|
366
430
|
}
|
|
367
431
|
};
|
|
368
432
|
ctx.setKeyBinding([
|
|
369
|
-
|
|
370
|
-
{ key: "downArrow", caption: "navigate", action: "moveDown", order: 0 },
|
|
433
|
+
...navBindings,
|
|
371
434
|
{
|
|
372
435
|
key: "s",
|
|
373
436
|
caption: sortCaption,
|
|
@@ -377,47 +440,47 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
|
|
|
377
440
|
]);
|
|
378
441
|
ctx.update();
|
|
379
442
|
} else {
|
|
380
|
-
ctx.setKeyBinding(
|
|
381
|
-
{ key: "upArrow", caption: "navigate", action: "moveUp", order: 0 },
|
|
382
|
-
{ key: "downArrow", caption: "navigate", action: "moveDown", order: 0 }
|
|
383
|
-
]);
|
|
443
|
+
ctx.setKeyBinding(navBindings);
|
|
384
444
|
}
|
|
385
445
|
}, [sortOrder, sortable]);
|
|
386
446
|
const selectedIndex = selectedIndexRef.current;
|
|
447
|
+
const needsBar = displayItems.length > effectiveMaxHeight;
|
|
448
|
+
const barGlyphs = needsBar ? scrollbarGlyphs(effectiveMaxHeight, displayItems.length, clampedScrollOffset) : null;
|
|
449
|
+
const appendBar = (rowContent, displayIndex) => {
|
|
450
|
+
if (!barGlyphs) return rowContent;
|
|
451
|
+
const glyph = barGlyphs[displayIndex] ?? BAR_TRACK;
|
|
452
|
+
return h2(
|
|
453
|
+
Box2,
|
|
454
|
+
{ flexDirection: "row" },
|
|
455
|
+
rowContent,
|
|
456
|
+
h2(Text2, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph)
|
|
457
|
+
);
|
|
458
|
+
};
|
|
387
459
|
const defaultRenderItem = (item, isSelected, displayIndex, actualIndex) => {
|
|
388
460
|
const isFirstVisible = displayIndex === 0;
|
|
389
461
|
const isLastVisible = displayIndex === visibleItems.length - 1;
|
|
390
|
-
let arrowPrefix = "";
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
arrowPrefix = "\
|
|
394
|
-
} else if (isLastVisible && canScrollDown) {
|
|
395
|
-
arrowPrefix = "\u2193 ";
|
|
396
|
-
} else {
|
|
397
|
-
arrowPrefix = " ";
|
|
398
|
-
}
|
|
399
|
-
if (isSelected) {
|
|
400
|
-
selectionPrefix = selectionMarker;
|
|
401
|
-
} else {
|
|
402
|
-
selectionPrefix = " ".repeat(selectionMarker.length);
|
|
462
|
+
let arrowPrefix = " ";
|
|
463
|
+
if (!needsBar) {
|
|
464
|
+
if (isFirstVisible && canScrollUp) arrowPrefix = "\u2191 ";
|
|
465
|
+
else if (isLastVisible && canScrollDown) arrowPrefix = "\u2193 ";
|
|
403
466
|
}
|
|
467
|
+
const selectionPrefix = isSelected ? selectionMarker : " ".repeat(selectionMarker.length);
|
|
468
|
+
const label = clipNameForScrollbar(item.name, needsBar);
|
|
404
469
|
return h2(
|
|
405
470
|
Box2,
|
|
406
471
|
{ flexDirection: "row" },
|
|
407
|
-
|
|
408
|
-
h2(Text2, {
|
|
409
|
-
key: `arrow-${actualIndex}`,
|
|
410
|
-
color: "white"
|
|
411
|
-
}, arrowPrefix),
|
|
412
|
-
// Selection marker space (always same width, not highlighted)
|
|
472
|
+
h2(Text2, { key: `arrow-${actualIndex}`, color: "white" }, arrowPrefix),
|
|
413
473
|
h2(Text2, { key: `marker-${actualIndex}`, color: "white" }, selectionPrefix),
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
474
|
+
h2(
|
|
475
|
+
Text2,
|
|
476
|
+
{
|
|
477
|
+
key: `name-${actualIndex}`,
|
|
478
|
+
color: isSelected ? "black" : "white",
|
|
479
|
+
backgroundColor: isSelected ? "cyan" : void 0,
|
|
480
|
+
bold: isSelected
|
|
481
|
+
},
|
|
482
|
+
label
|
|
483
|
+
)
|
|
421
484
|
);
|
|
422
485
|
};
|
|
423
486
|
const itemRenderer = renderItem || defaultRenderItem;
|
|
@@ -430,42 +493,32 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
|
|
|
430
493
|
if (renderItem) {
|
|
431
494
|
const isFirstVisible = displayIndex === 0;
|
|
432
495
|
const isLastVisible = displayIndex === visibleItems.length - 1;
|
|
433
|
-
let arrowPrefix = "";
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
arrowPrefix = "\
|
|
437
|
-
} else if (isLastVisible && canScrollDown) {
|
|
438
|
-
arrowPrefix = "\u2193 ";
|
|
439
|
-
} else {
|
|
440
|
-
arrowPrefix = " ";
|
|
441
|
-
}
|
|
442
|
-
if (isSelected) {
|
|
443
|
-
selectionPrefix = selectionMarker;
|
|
444
|
-
} else {
|
|
445
|
-
selectionPrefix = " ".repeat(selectionMarker.length);
|
|
496
|
+
let arrowPrefix = " ";
|
|
497
|
+
if (!needsBar) {
|
|
498
|
+
if (isFirstVisible && canScrollUp) arrowPrefix = "\u2191 ";
|
|
499
|
+
else if (isLastVisible && canScrollDown) arrowPrefix = "\u2193 ";
|
|
446
500
|
}
|
|
501
|
+
const selectionPrefix = isSelected ? selectionMarker : " ".repeat(selectionMarker.length);
|
|
502
|
+
const clipped = needsBar ? { ...item, name: clipNameForScrollbar(item.name, true) } : item;
|
|
503
|
+
const row = h2(
|
|
504
|
+
Box2,
|
|
505
|
+
{ flexDirection: "row" },
|
|
506
|
+
h2(Text2, { key: `arrow-${actualIndex}`, color: "white" }, arrowPrefix),
|
|
507
|
+
h2(Text2, { key: `marker-${actualIndex}`, color: "white" }, selectionPrefix),
|
|
508
|
+
renderItem(clipped, isSelected, displayIndex)
|
|
509
|
+
);
|
|
447
510
|
return h2(ScreenRow, {
|
|
448
511
|
key: `item-${actualIndex}`,
|
|
449
|
-
children:
|
|
450
|
-
Box2,
|
|
451
|
-
{ flexDirection: "row" },
|
|
452
|
-
// Arrow (clickable if functional, not highlighted)
|
|
453
|
-
h2(Text2, {
|
|
454
|
-
key: `arrow-${actualIndex}`,
|
|
455
|
-
color: "white"
|
|
456
|
-
}, arrowPrefix),
|
|
457
|
-
// Selection marker space (always same width, not highlighted)
|
|
458
|
-
h2(Text2, { key: `marker-${actualIndex}`, color: "white" }, selectionPrefix),
|
|
459
|
-
// Custom rendered content
|
|
460
|
-
renderItem(item, isSelected, displayIndex)
|
|
461
|
-
)
|
|
462
|
-
});
|
|
463
|
-
} else {
|
|
464
|
-
return h2(ScreenRow, {
|
|
465
|
-
key: `item-${actualIndex}`,
|
|
466
|
-
children: itemRenderer(item, isSelected, displayIndex, actualIndex)
|
|
512
|
+
children: appendBar(row, displayIndex)
|
|
467
513
|
});
|
|
468
514
|
}
|
|
515
|
+
return h2(ScreenRow, {
|
|
516
|
+
key: `item-${actualIndex}`,
|
|
517
|
+
children: appendBar(
|
|
518
|
+
itemRenderer(item, isSelected, displayIndex, actualIndex),
|
|
519
|
+
displayIndex
|
|
520
|
+
)
|
|
521
|
+
});
|
|
469
522
|
})
|
|
470
523
|
);
|
|
471
524
|
}
|
|
@@ -473,6 +526,7 @@ var h2;
|
|
|
473
526
|
var init_list_components = __esm({
|
|
474
527
|
"src/screen/list-components.js"() {
|
|
475
528
|
init_components();
|
|
529
|
+
init_scrollbar();
|
|
476
530
|
h2 = createElement;
|
|
477
531
|
}
|
|
478
532
|
});
|
|
@@ -967,21 +1021,6 @@ function wrapTextLines(text, cols) {
|
|
|
967
1021
|
}
|
|
968
1022
|
return out;
|
|
969
1023
|
}
|
|
970
|
-
function scrollbarGlyphs(viewportRows, totalLines, scrollTop) {
|
|
971
|
-
const view = Math.max(1, Math.floor(viewportRows));
|
|
972
|
-
const total = Math.max(0, Math.floor(totalLines));
|
|
973
|
-
if (total <= view) return null;
|
|
974
|
-
const maxScroll = total - view;
|
|
975
|
-
const thumbSize = Math.max(1, Math.round(view / total * view));
|
|
976
|
-
const travel = Math.max(0, view - thumbSize);
|
|
977
|
-
const s = Math.min(Math.max(0, Math.floor(scrollTop)), maxScroll);
|
|
978
|
-
const thumbStart = maxScroll === 0 ? 0 : Math.round(s / maxScroll * travel);
|
|
979
|
-
const glyphs = [];
|
|
980
|
-
for (let i = 0; i < view; i++) {
|
|
981
|
-
glyphs.push(i >= thumbStart && i < thumbStart + thumbSize ? BAR_THUMB : BAR_TRACK);
|
|
982
|
-
}
|
|
983
|
-
return glyphs;
|
|
984
|
-
}
|
|
985
1024
|
function padEndVisible(s, w) {
|
|
986
1025
|
const t = String(s ?? "");
|
|
987
1026
|
if (t.length >= w) return t.slice(0, w);
|
|
@@ -1082,22 +1121,17 @@ function ScrollableText({
|
|
|
1082
1121
|
...rowNodes
|
|
1083
1122
|
);
|
|
1084
1123
|
}
|
|
1085
|
-
var h5,
|
|
1124
|
+
var h5, SCROLL_KEYS;
|
|
1086
1125
|
var init_scrollable_text = __esm({
|
|
1087
1126
|
"src/screen/scrollable-text.js"() {
|
|
1088
1127
|
init_components();
|
|
1128
|
+
init_scrollbar();
|
|
1129
|
+
init_scrollbar();
|
|
1089
1130
|
h5 = createElement2;
|
|
1090
|
-
BAR_THUMB = "#";
|
|
1091
|
-
BAR_TRACK = "|";
|
|
1092
1131
|
SCROLL_KEYS = [
|
|
1093
1132
|
{ key: "upArrow", caption: "scroll", action: "scrollUp", order: 0 },
|
|
1094
1133
|
{ key: "downArrow", caption: "scroll", action: "scrollDown", order: 0 },
|
|
1095
|
-
|
|
1096
|
-
{ key: "downArrow", meta: true, caption: "page", action: "pageDown", order: 0 },
|
|
1097
|
-
{ key: "upArrow", ctrl: true, caption: "page", action: "pageUp", order: 0 },
|
|
1098
|
-
{ key: "downArrow", ctrl: true, caption: "page", action: "pageDown", order: 0 },
|
|
1099
|
-
{ key: "pageUp", caption: "page", action: "pageUp", order: 0 },
|
|
1100
|
-
{ key: "pageDown", caption: "page", action: "pageDown", order: 0 }
|
|
1134
|
+
...PAGE_SCROLL_KEY_BINDINGS
|
|
1101
1135
|
];
|
|
1102
1136
|
}
|
|
1103
1137
|
});
|
|
@@ -1233,6 +1267,8 @@ var init_footer_builder = __esm({
|
|
|
1233
1267
|
// src/screen/index.js
|
|
1234
1268
|
var screen_exports = {};
|
|
1235
1269
|
__export(screen_exports, {
|
|
1270
|
+
BAR_THUMB: () => BAR_THUMB,
|
|
1271
|
+
BAR_TRACK: () => BAR_TRACK,
|
|
1236
1272
|
Box: () => Box5,
|
|
1237
1273
|
Divider: () => Divider,
|
|
1238
1274
|
FooterPresets: () => FooterPresets,
|
|
@@ -1242,6 +1278,7 @@ __export(screen_exports, {
|
|
|
1242
1278
|
ListItem: () => ListItem,
|
|
1243
1279
|
MultiColumnListComponent: () => MultiColumnListComponent,
|
|
1244
1280
|
MultiColumnListWithPreviewComponent: () => MultiColumnListWithPreviewComponent,
|
|
1281
|
+
PAGE_SCROLL_KEY_BINDINGS: () => PAGE_SCROLL_KEY_BINDINGS,
|
|
1245
1282
|
React: () => React2,
|
|
1246
1283
|
ScreenBody: () => ScreenBody,
|
|
1247
1284
|
ScreenContainer: () => ScreenContainer,
|
|
@@ -1297,6 +1334,7 @@ var init_screen = __esm({
|
|
|
1297
1334
|
init_components();
|
|
1298
1335
|
init_ui_elements();
|
|
1299
1336
|
init_scrollable_text();
|
|
1337
|
+
init_scrollbar();
|
|
1300
1338
|
init_key_bindings();
|
|
1301
1339
|
init_utils();
|
|
1302
1340
|
init_footer_builder();
|