@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/init.js CHANGED
@@ -1025,9 +1025,44 @@ var init_follow_scroll = __esm({
1025
1025
  }
1026
1026
  });
1027
1027
 
1028
- // src/screen/scrollable-text.js
1029
- import { useState as useState3, useEffect as useEffect2, useMemo, useRef as useRef2, createElement as createElement2 } from "react";
1030
- import { Box as Box4, Text as Text5 } from "ink";
1028
+ // src/screen/visible-text.js
1029
+ function stripAnsi(text) {
1030
+ return String(text ?? "").replace(ANSI_RE, "");
1031
+ }
1032
+ function visibleWidth(text) {
1033
+ return [...stripAnsi(text)].length;
1034
+ }
1035
+ function sliceVisible(text, cols) {
1036
+ const w = Math.max(0, Math.floor(Number(cols) || 0));
1037
+ const s = String(text ?? "");
1038
+ if (w === 0) return "";
1039
+ let vis = 0;
1040
+ let out = "";
1041
+ let i = 0;
1042
+ while (i < s.length && vis < w) {
1043
+ ANSI_RE.lastIndex = i;
1044
+ const m = ANSI_RE.exec(s);
1045
+ if (m && m.index === i) {
1046
+ out += m[0];
1047
+ i += m[0].length;
1048
+ continue;
1049
+ }
1050
+ const cp = s.codePointAt(i);
1051
+ const ch = String.fromCodePoint(cp);
1052
+ out += ch;
1053
+ i += ch.length;
1054
+ vis += 1;
1055
+ }
1056
+ return out;
1057
+ }
1058
+ function padEndVisible(text, cols) {
1059
+ const w = Math.max(0, Math.floor(Number(cols) || 0));
1060
+ const s = String(text ?? "");
1061
+ const vis = visibleWidth(s);
1062
+ if (vis === w) return s;
1063
+ if (vis > w) return sliceVisible(s, w);
1064
+ return s + " ".repeat(w - vis);
1065
+ }
1031
1066
  function wrapTextLines(text, cols) {
1032
1067
  const w = Math.max(1, Math.floor(Number(cols) || 1));
1033
1068
  const out = [];
@@ -1036,20 +1071,30 @@ function wrapTextLines(text, cols) {
1036
1071
  out.push("");
1037
1072
  continue;
1038
1073
  }
1074
+ if (visibleWidth(raw) <= w) {
1075
+ out.push(raw);
1076
+ continue;
1077
+ }
1039
1078
  let rest = raw;
1040
- while (rest.length > w) {
1041
- out.push(rest.slice(0, w));
1042
- rest = rest.slice(w);
1079
+ while (visibleWidth(rest) > w) {
1080
+ const head = sliceVisible(rest, w);
1081
+ out.push(head);
1082
+ rest = rest.slice(head.length);
1043
1083
  }
1044
1084
  if (rest.length > 0) out.push(rest);
1045
1085
  }
1046
1086
  return out;
1047
1087
  }
1048
- function padEndVisible(s, w) {
1049
- const t = String(s ?? "");
1050
- if (t.length >= w) return t.slice(0, w);
1051
- return t + " ".repeat(w - t.length);
1052
- }
1088
+ var ANSI_RE;
1089
+ var init_visible_text = __esm({
1090
+ "src/screen/visible-text.js"() {
1091
+ ANSI_RE = /\u001b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
1092
+ }
1093
+ });
1094
+
1095
+ // src/screen/scrollable-text.js
1096
+ import { useState as useState3, useEffect as useEffect2, useMemo, useRef as useRef2, createElement as createElement2 } from "react";
1097
+ import { Box as Box4, Text as Text5 } from "ink";
1053
1098
  function ScrollableText({
1054
1099
  ctx,
1055
1100
  text = "",
@@ -1117,14 +1162,17 @@ function ScrollableText({
1117
1162
  }, [ctx, bindKeys, followBottom]);
1118
1163
  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" : "");
1119
1164
  const rowNodes = visible.map((line, i) => {
1120
- const body = padEndVisible(line, textWidth);
1121
1165
  const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? " " : "";
1122
1166
  const isThumb = glyph === BAR_THUMB;
1123
1167
  return h5(
1124
- Text5,
1125
- { key: `L${clamped + i}` },
1126
- body,
1127
- glyph ? h5(Text5, { color: isThumb ? "cyan" : "gray" }, glyph) : null
1168
+ Box4,
1169
+ { key: `L${clamped + i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
1170
+ h5(
1171
+ Box4,
1172
+ { width: textWidth, flexShrink: 0 },
1173
+ h5(Text5, { wrap: "truncate" }, padEndVisible(line, textWidth))
1174
+ ),
1175
+ showScrollbar ? h5(Box4, { width: 1, flexShrink: 0 }, h5(Text5, { color: isThumb ? "cyan" : "gray" }, glyph)) : null
1128
1176
  );
1129
1177
  });
1130
1178
  if (bar && visible.length < viewportRows) {
@@ -1132,10 +1180,10 @@ function ScrollableText({
1132
1180
  const glyph = bar[i] ?? BAR_TRACK;
1133
1181
  rowNodes.push(
1134
1182
  h5(
1135
- Text5,
1136
- { key: `pad${i}` },
1137
- padEndVisible("", textWidth),
1138
- h5(Text5, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph)
1183
+ Box4,
1184
+ { key: `pad${i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
1185
+ h5(Box4, { width: textWidth, flexShrink: 0 }, h5(Text5, {}, padEndVisible("", textWidth))),
1186
+ h5(Box4, { width: 1, flexShrink: 0 }, h5(Text5, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph))
1139
1187
  )
1140
1188
  );
1141
1189
  }
@@ -1154,7 +1202,9 @@ var init_scrollable_text = __esm({
1154
1202
  init_components();
1155
1203
  init_scrollbar();
1156
1204
  init_follow_scroll();
1205
+ init_visible_text();
1157
1206
  init_scrollbar();
1207
+ init_visible_text();
1158
1208
  h5 = createElement2;
1159
1209
  SCROLL_KEYS = [
1160
1210
  { key: "upArrow", caption: "scroll", action: "scrollUp", order: 0 },
@@ -1331,6 +1381,7 @@ __export(screen_exports, {
1331
1381
  nextScrollAfterContentChange: () => nextScrollAfterContentChange,
1332
1382
  nextScrollAfterUserMove: () => nextScrollAfterUserMove,
1333
1383
  organizeFooterMessages: () => organizeFooterMessages,
1384
+ padEndVisible: () => padEndVisible,
1334
1385
  scrollbarGlyphs: () => scrollbarGlyphs,
1335
1386
  showListScreen: () => showListScreen,
1336
1387
  showMenuScreen: () => showMenuScreen,
@@ -1338,6 +1389,8 @@ __export(screen_exports, {
1338
1389
  showMultiColumnListWithPreviewScreen: () => showMultiColumnListWithPreviewScreen,
1339
1390
  showScreen: () => showScreen,
1340
1391
  showWordGridScreen: () => showWordGridScreen,
1392
+ sliceVisible: () => sliceVisible,
1393
+ stripAnsi: () => stripAnsi,
1341
1394
  useCallback: () => useCallback,
1342
1395
  useEffect: () => useEffect3,
1343
1396
  useInput: () => useInput2,
@@ -1345,6 +1398,7 @@ __export(screen_exports, {
1345
1398
  useMemo: () => useMemo2,
1346
1399
  useRef: () => useRef3,
1347
1400
  useState: () => useState4,
1401
+ visibleWidth: () => visibleWidth,
1348
1402
  wrapTextLines: () => wrapTextLines
1349
1403
  });
1350
1404
  import React2, { useState as useState4, useEffect as useEffect3, useLayoutEffect, useRef as useRef3, useMemo as useMemo2, useCallback, memo, createElement as createElement3 } from "react";
@@ -1366,6 +1420,7 @@ var init_screen = __esm({
1366
1420
  init_components();
1367
1421
  init_ui_elements();
1368
1422
  init_scrollable_text();
1423
+ init_visible_text();
1369
1424
  init_follow_scroll();
1370
1425
  init_scrollbar();
1371
1426
  init_key_bindings();