@nmakarov/cli-toolkit 0.81.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/index.cjs CHANGED
@@ -1042,7 +1042,44 @@ var init_follow_scroll = __esm({
1042
1042
  }
1043
1043
  });
1044
1044
 
1045
- // src/screen/scrollable-text.js
1045
+ // src/screen/visible-text.js
1046
+ function stripAnsi(text) {
1047
+ return String(text ?? "").replace(ANSI_RE, "");
1048
+ }
1049
+ function visibleWidth(text) {
1050
+ return [...stripAnsi(text)].length;
1051
+ }
1052
+ function sliceVisible(text, cols) {
1053
+ const w = Math.max(0, Math.floor(Number(cols) || 0));
1054
+ const s = String(text ?? "");
1055
+ if (w === 0) return "";
1056
+ let vis = 0;
1057
+ let out = "";
1058
+ let i = 0;
1059
+ while (i < s.length && vis < w) {
1060
+ ANSI_RE.lastIndex = i;
1061
+ const m = ANSI_RE.exec(s);
1062
+ if (m && m.index === i) {
1063
+ out += m[0];
1064
+ i += m[0].length;
1065
+ continue;
1066
+ }
1067
+ const cp3 = s.codePointAt(i);
1068
+ const ch = String.fromCodePoint(cp3);
1069
+ out += ch;
1070
+ i += ch.length;
1071
+ vis += 1;
1072
+ }
1073
+ return out;
1074
+ }
1075
+ function padEndVisible(text, cols) {
1076
+ const w = Math.max(0, Math.floor(Number(cols) || 0));
1077
+ const s = String(text ?? "");
1078
+ const vis = visibleWidth(s);
1079
+ if (vis === w) return s;
1080
+ if (vis > w) return sliceVisible(s, w);
1081
+ return s + " ".repeat(w - vis);
1082
+ }
1046
1083
  function wrapTextLines(text, cols) {
1047
1084
  const w = Math.max(1, Math.floor(Number(cols) || 1));
1048
1085
  const out = [];
@@ -1051,20 +1088,28 @@ function wrapTextLines(text, cols) {
1051
1088
  out.push("");
1052
1089
  continue;
1053
1090
  }
1091
+ if (visibleWidth(raw) <= w) {
1092
+ out.push(raw);
1093
+ continue;
1094
+ }
1054
1095
  let rest = raw;
1055
- while (rest.length > w) {
1056
- out.push(rest.slice(0, w));
1057
- rest = rest.slice(w);
1096
+ while (visibleWidth(rest) > w) {
1097
+ const head = sliceVisible(rest, w);
1098
+ out.push(head);
1099
+ rest = rest.slice(head.length);
1058
1100
  }
1059
1101
  if (rest.length > 0) out.push(rest);
1060
1102
  }
1061
1103
  return out;
1062
1104
  }
1063
- function padEndVisible(s, w) {
1064
- const t = String(s ?? "");
1065
- if (t.length >= w) return t.slice(0, w);
1066
- return t + " ".repeat(w - t.length);
1067
- }
1105
+ var ANSI_RE;
1106
+ var init_visible_text = __esm({
1107
+ "src/screen/visible-text.js"() {
1108
+ ANSI_RE = /\u001b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
1109
+ }
1110
+ });
1111
+
1112
+ // src/screen/scrollable-text.js
1068
1113
  function ScrollableText({
1069
1114
  ctx,
1070
1115
  text = "",
@@ -1132,14 +1177,17 @@ function ScrollableText({
1132
1177
  }, [ctx, bindKeys, followBottom]);
1133
1178
  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" : "");
1134
1179
  const rowNodes = visible.map((line, i) => {
1135
- const body = padEndVisible(line, textWidth);
1136
1180
  const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? " " : "";
1137
1181
  const isThumb = glyph === BAR_THUMB;
1138
1182
  return h5(
1139
- import_ink5.Text,
1140
- { key: `L${clamped + i}` },
1141
- body,
1142
- glyph ? h5(import_ink5.Text, { color: isThumb ? "cyan" : "gray" }, glyph) : null
1183
+ import_ink5.Box,
1184
+ { key: `L${clamped + i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
1185
+ h5(
1186
+ import_ink5.Box,
1187
+ { width: textWidth, flexShrink: 0 },
1188
+ h5(import_ink5.Text, { wrap: "truncate" }, padEndVisible(line, textWidth))
1189
+ ),
1190
+ showScrollbar ? h5(import_ink5.Box, { width: 1, flexShrink: 0 }, h5(import_ink5.Text, { color: isThumb ? "cyan" : "gray" }, glyph)) : null
1143
1191
  );
1144
1192
  });
1145
1193
  if (bar && visible.length < viewportRows) {
@@ -1147,10 +1195,10 @@ function ScrollableText({
1147
1195
  const glyph = bar[i] ?? BAR_TRACK;
1148
1196
  rowNodes.push(
1149
1197
  h5(
1150
- import_ink5.Text,
1151
- { key: `pad${i}` },
1152
- padEndVisible("", textWidth),
1153
- h5(import_ink5.Text, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph)
1198
+ import_ink5.Box,
1199
+ { key: `pad${i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
1200
+ h5(import_ink5.Box, { width: textWidth, flexShrink: 0 }, h5(import_ink5.Text, {}, padEndVisible("", textWidth))),
1201
+ h5(import_ink5.Box, { width: 1, flexShrink: 0 }, h5(import_ink5.Text, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph))
1154
1202
  )
1155
1203
  );
1156
1204
  }
@@ -1171,7 +1219,9 @@ var init_scrollable_text = __esm({
1171
1219
  init_components();
1172
1220
  init_scrollbar();
1173
1221
  init_follow_scroll();
1222
+ init_visible_text();
1174
1223
  init_scrollbar();
1224
+ init_visible_text();
1175
1225
  h5 = import_react5.createElement;
1176
1226
  SCROLL_KEYS = [
1177
1227
  { key: "upArrow", caption: "scroll", action: "scrollUp", order: 0 },
@@ -1326,6 +1376,7 @@ var init_screen = __esm({
1326
1376
  init_components();
1327
1377
  init_ui_elements();
1328
1378
  init_scrollable_text();
1379
+ init_visible_text();
1329
1380
  init_follow_scroll();
1330
1381
  init_scrollbar();
1331
1382
  init_key_bindings();
@@ -1465,6 +1516,7 @@ __export(src_exports, {
1465
1516
  npmEnv: () => npmEnv,
1466
1517
  npmInstallEnv: () => npmInstallEnv,
1467
1518
  organizeFooterMessages: () => organizeFooterMessages,
1519
+ padEndVisible: () => padEndVisible,
1468
1520
  parseGitHost: () => parseGitHost,
1469
1521
  parsePm2Jlist: () => parsePm2Jlist,
1470
1522
  prepareGitHost: () => prepareGitHost,
@@ -1510,9 +1562,11 @@ __export(src_exports, {
1510
1562
  showMultiColumnListWithPreviewScreen: () => showMultiColumnListWithPreviewScreen,
1511
1563
  showScreen: () => showScreen,
1512
1564
  showWordGridScreen: () => showWordGridScreen,
1565
+ sliceVisible: () => sliceVisible,
1513
1566
  sshRun: () => sshRun,
1514
1567
  startPm2: () => startPm2,
1515
1568
  stopPm2: () => stopPm2,
1569
+ stripAnsi: () => stripAnsi,
1516
1570
  syncEnv: () => syncEnv,
1517
1571
  taskHistoryInsertFromQueueRow: () => taskHistoryInsertFromQueueRow,
1518
1572
  timeMatcher: () => timeMatcher,
@@ -1529,6 +1583,7 @@ __export(src_exports, {
1529
1583
  useMemo: () => import_react6.useMemo,
1530
1584
  useRef: () => import_react6.useRef,
1531
1585
  useState: () => import_react6.useState,
1586
+ visibleWidth: () => visibleWidth,
1532
1587
  waitForTaskResult: () => waitForTaskResult,
1533
1588
  waitPm2: () => waitPm2,
1534
1589
  wrapTextLines: () => wrapTextLines,
@@ -10443,6 +10498,7 @@ var TasksManager = class _TasksManager {
10443
10498
  npmEnv,
10444
10499
  npmInstallEnv,
10445
10500
  organizeFooterMessages,
10501
+ padEndVisible,
10446
10502
  parseGitHost,
10447
10503
  parsePm2Jlist,
10448
10504
  prepareGitHost,
@@ -10488,9 +10544,11 @@ var TasksManager = class _TasksManager {
10488
10544
  showMultiColumnListWithPreviewScreen,
10489
10545
  showScreen,
10490
10546
  showWordGridScreen,
10547
+ sliceVisible,
10491
10548
  sshRun,
10492
10549
  startPm2,
10493
10550
  stopPm2,
10551
+ stripAnsi,
10494
10552
  syncEnv,
10495
10553
  taskHistoryInsertFromQueueRow,
10496
10554
  timeMatcher,
@@ -10507,6 +10565,7 @@ var TasksManager = class _TasksManager {
10507
10565
  useMemo,
10508
10566
  useRef,
10509
10567
  useState,
10568
+ visibleWidth,
10510
10569
  waitForTaskResult,
10511
10570
  waitPm2,
10512
10571
  wrapTextLines,