@nmakarov/cli-toolkit 0.80.0 → 0.82.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 +132 -44
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +134 -46
- package/dist/cli-runner.js.map +1 -1
- package/dist/index.cjs +140 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +134 -46
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +132 -44
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +134 -46
- package/dist/init.js.map +1 -1
- package/dist/screen.cjs +128 -44
- package/dist/screen.cjs.map +1 -1
- package/dist/screen.js +120 -44
- package/dist/screen.js.map +1 -1
- package/package.json +1 -1
package/dist/cli-runner.js
CHANGED
|
@@ -1002,9 +1002,68 @@ var init_ui_elements = __esm({
|
|
|
1002
1002
|
}
|
|
1003
1003
|
});
|
|
1004
1004
|
|
|
1005
|
-
// src/screen/
|
|
1006
|
-
|
|
1007
|
-
|
|
1005
|
+
// src/screen/follow-scroll.js
|
|
1006
|
+
function clampScroll(scrollTop, maxScroll) {
|
|
1007
|
+
const max = Math.max(0, Number(maxScroll) || 0);
|
|
1008
|
+
const top = Number(scrollTop) || 0;
|
|
1009
|
+
return Math.min(Math.max(0, top), max);
|
|
1010
|
+
}
|
|
1011
|
+
function isScrolledToBottom(scrollTop, maxScroll) {
|
|
1012
|
+
return clampScroll(scrollTop, maxScroll) >= Math.max(0, Number(maxScroll) || 0);
|
|
1013
|
+
}
|
|
1014
|
+
function nextScrollAfterUserMove(scrollTop, maxScroll, delta) {
|
|
1015
|
+
const next = clampScroll((Number(scrollTop) || 0) + (Number(delta) || 0), maxScroll);
|
|
1016
|
+
return { scrollTop: next, following: isScrolledToBottom(next, maxScroll) };
|
|
1017
|
+
}
|
|
1018
|
+
function nextScrollAfterContentChange({ following, scrollTop, maxScroll }) {
|
|
1019
|
+
const max = Math.max(0, Number(maxScroll) || 0);
|
|
1020
|
+
if (following) return { scrollTop: max, following: true };
|
|
1021
|
+
const next = clampScroll(scrollTop, max);
|
|
1022
|
+
return { scrollTop: next, following: isScrolledToBottom(next, max) };
|
|
1023
|
+
}
|
|
1024
|
+
var init_follow_scroll = __esm({
|
|
1025
|
+
"src/screen/follow-scroll.js"() {
|
|
1026
|
+
}
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
// src/screen/visible-text.js
|
|
1030
|
+
function stripAnsi(text) {
|
|
1031
|
+
return String(text ?? "").replace(ANSI_RE, "");
|
|
1032
|
+
}
|
|
1033
|
+
function visibleWidth(text) {
|
|
1034
|
+
return [...stripAnsi(text)].length;
|
|
1035
|
+
}
|
|
1036
|
+
function sliceVisible(text, cols) {
|
|
1037
|
+
const w = Math.max(0, Math.floor(Number(cols) || 0));
|
|
1038
|
+
const s = String(text ?? "");
|
|
1039
|
+
if (w === 0) return "";
|
|
1040
|
+
let vis = 0;
|
|
1041
|
+
let out = "";
|
|
1042
|
+
let i = 0;
|
|
1043
|
+
while (i < s.length && vis < w) {
|
|
1044
|
+
ANSI_RE.lastIndex = i;
|
|
1045
|
+
const m = ANSI_RE.exec(s);
|
|
1046
|
+
if (m && m.index === i) {
|
|
1047
|
+
out += m[0];
|
|
1048
|
+
i += m[0].length;
|
|
1049
|
+
continue;
|
|
1050
|
+
}
|
|
1051
|
+
const cp = s.codePointAt(i);
|
|
1052
|
+
const ch = String.fromCodePoint(cp);
|
|
1053
|
+
out += ch;
|
|
1054
|
+
i += ch.length;
|
|
1055
|
+
vis += 1;
|
|
1056
|
+
}
|
|
1057
|
+
return out;
|
|
1058
|
+
}
|
|
1059
|
+
function padEndVisible(text, cols) {
|
|
1060
|
+
const w = Math.max(0, Math.floor(Number(cols) || 0));
|
|
1061
|
+
const s = String(text ?? "");
|
|
1062
|
+
const vis = visibleWidth(s);
|
|
1063
|
+
if (vis === w) return s;
|
|
1064
|
+
if (vis > w) return sliceVisible(s, w);
|
|
1065
|
+
return s + " ".repeat(w - vis);
|
|
1066
|
+
}
|
|
1008
1067
|
function wrapTextLines(text, cols) {
|
|
1009
1068
|
const w = Math.max(1, Math.floor(Number(cols) || 1));
|
|
1010
1069
|
const out = [];
|
|
@@ -1013,20 +1072,30 @@ function wrapTextLines(text, cols) {
|
|
|
1013
1072
|
out.push("");
|
|
1014
1073
|
continue;
|
|
1015
1074
|
}
|
|
1075
|
+
if (visibleWidth(raw) <= w) {
|
|
1076
|
+
out.push(raw);
|
|
1077
|
+
continue;
|
|
1078
|
+
}
|
|
1016
1079
|
let rest = raw;
|
|
1017
|
-
while (rest
|
|
1018
|
-
|
|
1019
|
-
|
|
1080
|
+
while (visibleWidth(rest) > w) {
|
|
1081
|
+
const head = sliceVisible(rest, w);
|
|
1082
|
+
out.push(head);
|
|
1083
|
+
rest = rest.slice(head.length);
|
|
1020
1084
|
}
|
|
1021
1085
|
if (rest.length > 0) out.push(rest);
|
|
1022
1086
|
}
|
|
1023
1087
|
return out;
|
|
1024
1088
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
}
|
|
1089
|
+
var ANSI_RE;
|
|
1090
|
+
var init_visible_text = __esm({
|
|
1091
|
+
"src/screen/visible-text.js"() {
|
|
1092
|
+
ANSI_RE = /\u001b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
|
|
1093
|
+
}
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
// src/screen/scrollable-text.js
|
|
1097
|
+
import { useState as useState3, useEffect as useEffect2, useMemo, useRef as useRef2, createElement as createElement2 } from "react";
|
|
1098
|
+
import { Box as Box4, Text as Text5 } from "ink";
|
|
1030
1099
|
function ScrollableText({
|
|
1031
1100
|
ctx,
|
|
1032
1101
|
text = "",
|
|
@@ -1036,9 +1105,11 @@ function ScrollableText({
|
|
|
1036
1105
|
showScrollbar = true,
|
|
1037
1106
|
showStatus = true,
|
|
1038
1107
|
bindKeys = true,
|
|
1039
|
-
header = null
|
|
1108
|
+
header = null,
|
|
1109
|
+
followBottom = false
|
|
1040
1110
|
}) {
|
|
1041
1111
|
const [scrollTop, setScrollTop] = useState3(0);
|
|
1112
|
+
const [following, setFollowing] = useState3(() => !!followBottom);
|
|
1042
1113
|
const [, bump] = useState3(0);
|
|
1043
1114
|
const termRows = process.stdout.rows || 24;
|
|
1044
1115
|
const viewportRows = Math.max(
|
|
@@ -1057,48 +1128,52 @@ function ScrollableText({
|
|
|
1057
1128
|
const clamped = Math.min(Math.max(0, scrollTop), maxScroll);
|
|
1058
1129
|
const visible = allLines.slice(clamped, clamped + viewportRows);
|
|
1059
1130
|
const bar = needsBar ? scrollbarGlyphs(viewportRows, allLines.length, clamped) : null;
|
|
1060
|
-
useEffect2(() => {
|
|
1061
|
-
setScrollTop((s) => Math.min(s, maxScroll));
|
|
1062
|
-
}, [maxScroll]);
|
|
1063
1131
|
const maxScrollRef = useRef2(maxScroll);
|
|
1064
1132
|
const pageSizeRef = useRef2(viewportRows);
|
|
1133
|
+
const scrollTopRef = useRef2(scrollTop);
|
|
1134
|
+
const followingRef = useRef2(following);
|
|
1065
1135
|
maxScrollRef.current = maxScroll;
|
|
1066
1136
|
pageSizeRef.current = viewportRows;
|
|
1137
|
+
scrollTopRef.current = scrollTop;
|
|
1138
|
+
followingRef.current = following;
|
|
1139
|
+
useEffect2(() => {
|
|
1140
|
+
const next = nextScrollAfterContentChange({
|
|
1141
|
+
following: followBottom && followingRef.current,
|
|
1142
|
+
scrollTop: scrollTopRef.current,
|
|
1143
|
+
maxScroll
|
|
1144
|
+
});
|
|
1145
|
+
if (next.scrollTop !== scrollTopRef.current) setScrollTop(next.scrollTop);
|
|
1146
|
+
if (followBottom && next.following !== followingRef.current) setFollowing(next.following);
|
|
1147
|
+
}, [maxScroll, followBottom]);
|
|
1148
|
+
const applyUserScroll = (delta) => {
|
|
1149
|
+
const next = nextScrollAfterUserMove(scrollTopRef.current, maxScrollRef.current, delta);
|
|
1150
|
+
setScrollTop(next.scrollTop);
|
|
1151
|
+
if (followBottom) setFollowing(next.following);
|
|
1152
|
+
bump((n) => n + 1);
|
|
1153
|
+
ctx?.update?.();
|
|
1154
|
+
};
|
|
1067
1155
|
useEffect2(() => {
|
|
1068
1156
|
if (!ctx || !bindKeys) return void 0;
|
|
1069
1157
|
ctx.setKeyBinding(SCROLL_KEYS);
|
|
1070
|
-
ctx.setAction("scrollUp", () =>
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
});
|
|
1075
|
-
ctx.setAction("scrollDown", () => {
|
|
1076
|
-
setScrollTop((s) => Math.min(maxScrollRef.current, s + 1));
|
|
1077
|
-
bump((n) => n + 1);
|
|
1078
|
-
ctx.update?.();
|
|
1079
|
-
});
|
|
1080
|
-
ctx.setAction("pageUp", () => {
|
|
1081
|
-
setScrollTop((s) => Math.max(0, s - pageSizeRef.current));
|
|
1082
|
-
bump((n) => n + 1);
|
|
1083
|
-
ctx.update?.();
|
|
1084
|
-
});
|
|
1085
|
-
ctx.setAction("pageDown", () => {
|
|
1086
|
-
setScrollTop((s) => Math.min(maxScrollRef.current, s + pageSizeRef.current));
|
|
1087
|
-
bump((n) => n + 1);
|
|
1088
|
-
ctx.update?.();
|
|
1089
|
-
});
|
|
1158
|
+
ctx.setAction("scrollUp", () => applyUserScroll(-1));
|
|
1159
|
+
ctx.setAction("scrollDown", () => applyUserScroll(1));
|
|
1160
|
+
ctx.setAction("pageUp", () => applyUserScroll(-pageSizeRef.current));
|
|
1161
|
+
ctx.setAction("pageDown", () => applyUserScroll(pageSizeRef.current));
|
|
1090
1162
|
return void 0;
|
|
1091
|
-
}, [ctx, bindKeys]);
|
|
1092
|
-
const status = allLines.length === 0 ? "empty" : `lines ${clamped + 1}-${Math.min(clamped + visible.length, allLines.length)} of ${allLines.length}` + (needsBar ? " \xB7 \u2325\u2191/\u2193 or PgUp/Dn page" : "");
|
|
1163
|
+
}, [ctx, bindKeys, followBottom]);
|
|
1164
|
+
const status = allLines.length === 0 ? "empty" : `lines ${clamped + 1}-${Math.min(clamped + visible.length, allLines.length)} of ${allLines.length}` + (needsBar ? " \xB7 \u2325\u2191/\u2193 or PgUp/Dn page" : "") + (followBottom && following ? " \xB7 follow" : followBottom ? " \xB7 follow off" : "");
|
|
1093
1165
|
const rowNodes = visible.map((line, i) => {
|
|
1094
|
-
const body = padEndVisible(line, textWidth);
|
|
1095
1166
|
const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? " " : "";
|
|
1096
1167
|
const isThumb = glyph === BAR_THUMB;
|
|
1097
1168
|
return h5(
|
|
1098
|
-
|
|
1099
|
-
{ key: `L${clamped + i}
|
|
1100
|
-
|
|
1101
|
-
|
|
1169
|
+
Box4,
|
|
1170
|
+
{ key: `L${clamped + i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
|
|
1171
|
+
h5(
|
|
1172
|
+
Box4,
|
|
1173
|
+
{ width: textWidth, flexShrink: 0 },
|
|
1174
|
+
h5(Text5, { wrap: "truncate" }, padEndVisible(line, textWidth))
|
|
1175
|
+
),
|
|
1176
|
+
showScrollbar ? h5(Box4, { width: 1, flexShrink: 0 }, h5(Text5, { color: isThumb ? "cyan" : "gray" }, glyph)) : null
|
|
1102
1177
|
);
|
|
1103
1178
|
});
|
|
1104
1179
|
if (bar && visible.length < viewportRows) {
|
|
@@ -1106,10 +1181,10 @@ function ScrollableText({
|
|
|
1106
1181
|
const glyph = bar[i] ?? BAR_TRACK;
|
|
1107
1182
|
rowNodes.push(
|
|
1108
1183
|
h5(
|
|
1109
|
-
|
|
1110
|
-
{ key: `pad${i}
|
|
1111
|
-
padEndVisible("", textWidth),
|
|
1112
|
-
h5(Text5, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph)
|
|
1184
|
+
Box4,
|
|
1185
|
+
{ key: `pad${i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
|
|
1186
|
+
h5(Box4, { width: textWidth, flexShrink: 0 }, h5(Text5, {}, padEndVisible("", textWidth))),
|
|
1187
|
+
h5(Box4, { width: 1, flexShrink: 0 }, h5(Text5, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph))
|
|
1113
1188
|
)
|
|
1114
1189
|
);
|
|
1115
1190
|
}
|
|
@@ -1127,7 +1202,10 @@ var init_scrollable_text = __esm({
|
|
|
1127
1202
|
"src/screen/scrollable-text.js"() {
|
|
1128
1203
|
init_components();
|
|
1129
1204
|
init_scrollbar();
|
|
1205
|
+
init_follow_scroll();
|
|
1206
|
+
init_visible_text();
|
|
1130
1207
|
init_scrollbar();
|
|
1208
|
+
init_visible_text();
|
|
1131
1209
|
h5 = createElement2;
|
|
1132
1210
|
SCROLL_KEYS = [
|
|
1133
1211
|
{ key: "upArrow", caption: "scroll", action: "scrollUp", order: 0 },
|
|
@@ -1295,11 +1373,16 @@ __export(screen_exports, {
|
|
|
1295
1373
|
buildBreadcrumb: () => buildBreadcrumb,
|
|
1296
1374
|
buildDetailBreadcrumb: () => buildDetailBreadcrumb,
|
|
1297
1375
|
buildFooter: () => buildFooter,
|
|
1376
|
+
clampScroll: () => clampScroll,
|
|
1298
1377
|
formatBindingKey: () => formatBindingKey,
|
|
1299
1378
|
h: () => createElement3,
|
|
1379
|
+
isScrolledToBottom: () => isScrolledToBottom,
|
|
1300
1380
|
load: () => load,
|
|
1301
1381
|
memo: () => memo,
|
|
1382
|
+
nextScrollAfterContentChange: () => nextScrollAfterContentChange,
|
|
1383
|
+
nextScrollAfterUserMove: () => nextScrollAfterUserMove,
|
|
1302
1384
|
organizeFooterMessages: () => organizeFooterMessages,
|
|
1385
|
+
padEndVisible: () => padEndVisible,
|
|
1303
1386
|
scrollbarGlyphs: () => scrollbarGlyphs,
|
|
1304
1387
|
showListScreen: () => showListScreen,
|
|
1305
1388
|
showMenuScreen: () => showMenuScreen,
|
|
@@ -1307,6 +1390,8 @@ __export(screen_exports, {
|
|
|
1307
1390
|
showMultiColumnListWithPreviewScreen: () => showMultiColumnListWithPreviewScreen,
|
|
1308
1391
|
showScreen: () => showScreen,
|
|
1309
1392
|
showWordGridScreen: () => showWordGridScreen,
|
|
1393
|
+
sliceVisible: () => sliceVisible,
|
|
1394
|
+
stripAnsi: () => stripAnsi,
|
|
1310
1395
|
useCallback: () => useCallback,
|
|
1311
1396
|
useEffect: () => useEffect3,
|
|
1312
1397
|
useInput: () => useInput2,
|
|
@@ -1314,6 +1399,7 @@ __export(screen_exports, {
|
|
|
1314
1399
|
useMemo: () => useMemo2,
|
|
1315
1400
|
useRef: () => useRef3,
|
|
1316
1401
|
useState: () => useState4,
|
|
1402
|
+
visibleWidth: () => visibleWidth,
|
|
1317
1403
|
wrapTextLines: () => wrapTextLines
|
|
1318
1404
|
});
|
|
1319
1405
|
import React2, { useState as useState4, useEffect as useEffect3, useLayoutEffect, useRef as useRef3, useMemo as useMemo2, useCallback, memo, createElement as createElement3 } from "react";
|
|
@@ -1335,6 +1421,8 @@ var init_screen = __esm({
|
|
|
1335
1421
|
init_components();
|
|
1336
1422
|
init_ui_elements();
|
|
1337
1423
|
init_scrollable_text();
|
|
1424
|
+
init_visible_text();
|
|
1425
|
+
init_follow_scroll();
|
|
1338
1426
|
init_scrollbar();
|
|
1339
1427
|
init_key_bindings();
|
|
1340
1428
|
init_utils();
|