@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.
@@ -1026,9 +1026,44 @@ var init_follow_scroll = __esm({
1026
1026
  }
1027
1027
  });
1028
1028
 
1029
- // src/screen/scrollable-text.js
1030
- import { useState as useState3, useEffect as useEffect2, useMemo, useRef as useRef2, createElement as createElement2 } from "react";
1031
- import { Box as Box4, Text as Text5 } from "ink";
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
+ }
1032
1067
  function wrapTextLines(text, cols) {
1033
1068
  const w = Math.max(1, Math.floor(Number(cols) || 1));
1034
1069
  const out = [];
@@ -1037,20 +1072,30 @@ function wrapTextLines(text, cols) {
1037
1072
  out.push("");
1038
1073
  continue;
1039
1074
  }
1075
+ if (visibleWidth(raw) <= w) {
1076
+ out.push(raw);
1077
+ continue;
1078
+ }
1040
1079
  let rest = raw;
1041
- while (rest.length > w) {
1042
- out.push(rest.slice(0, w));
1043
- rest = rest.slice(w);
1080
+ while (visibleWidth(rest) > w) {
1081
+ const head = sliceVisible(rest, w);
1082
+ out.push(head);
1083
+ rest = rest.slice(head.length);
1044
1084
  }
1045
1085
  if (rest.length > 0) out.push(rest);
1046
1086
  }
1047
1087
  return out;
1048
1088
  }
1049
- function padEndVisible(s, w) {
1050
- const t = String(s ?? "");
1051
- if (t.length >= w) return t.slice(0, w);
1052
- return t + " ".repeat(w - t.length);
1053
- }
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";
1054
1099
  function ScrollableText({
1055
1100
  ctx,
1056
1101
  text = "",
@@ -1118,14 +1163,17 @@ function ScrollableText({
1118
1163
  }, [ctx, bindKeys, followBottom]);
1119
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" : "");
1120
1165
  const rowNodes = visible.map((line, i) => {
1121
- const body = padEndVisible(line, textWidth);
1122
1166
  const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? " " : "";
1123
1167
  const isThumb = glyph === BAR_THUMB;
1124
1168
  return h5(
1125
- Text5,
1126
- { key: `L${clamped + i}` },
1127
- body,
1128
- glyph ? h5(Text5, { color: isThumb ? "cyan" : "gray" }, glyph) : null
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
1129
1177
  );
1130
1178
  });
1131
1179
  if (bar && visible.length < viewportRows) {
@@ -1133,10 +1181,10 @@ function ScrollableText({
1133
1181
  const glyph = bar[i] ?? BAR_TRACK;
1134
1182
  rowNodes.push(
1135
1183
  h5(
1136
- Text5,
1137
- { key: `pad${i}` },
1138
- padEndVisible("", textWidth),
1139
- 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))
1140
1188
  )
1141
1189
  );
1142
1190
  }
@@ -1155,7 +1203,9 @@ var init_scrollable_text = __esm({
1155
1203
  init_components();
1156
1204
  init_scrollbar();
1157
1205
  init_follow_scroll();
1206
+ init_visible_text();
1158
1207
  init_scrollbar();
1208
+ init_visible_text();
1159
1209
  h5 = createElement2;
1160
1210
  SCROLL_KEYS = [
1161
1211
  { key: "upArrow", caption: "scroll", action: "scrollUp", order: 0 },
@@ -1332,6 +1382,7 @@ __export(screen_exports, {
1332
1382
  nextScrollAfterContentChange: () => nextScrollAfterContentChange,
1333
1383
  nextScrollAfterUserMove: () => nextScrollAfterUserMove,
1334
1384
  organizeFooterMessages: () => organizeFooterMessages,
1385
+ padEndVisible: () => padEndVisible,
1335
1386
  scrollbarGlyphs: () => scrollbarGlyphs,
1336
1387
  showListScreen: () => showListScreen,
1337
1388
  showMenuScreen: () => showMenuScreen,
@@ -1339,6 +1390,8 @@ __export(screen_exports, {
1339
1390
  showMultiColumnListWithPreviewScreen: () => showMultiColumnListWithPreviewScreen,
1340
1391
  showScreen: () => showScreen,
1341
1392
  showWordGridScreen: () => showWordGridScreen,
1393
+ sliceVisible: () => sliceVisible,
1394
+ stripAnsi: () => stripAnsi,
1342
1395
  useCallback: () => useCallback,
1343
1396
  useEffect: () => useEffect3,
1344
1397
  useInput: () => useInput2,
@@ -1346,6 +1399,7 @@ __export(screen_exports, {
1346
1399
  useMemo: () => useMemo2,
1347
1400
  useRef: () => useRef3,
1348
1401
  useState: () => useState4,
1402
+ visibleWidth: () => visibleWidth,
1349
1403
  wrapTextLines: () => wrapTextLines
1350
1404
  });
1351
1405
  import React2, { useState as useState4, useEffect as useEffect3, useLayoutEffect, useRef as useRef3, useMemo as useMemo2, useCallback, memo, createElement as createElement3 } from "react";
@@ -1367,6 +1421,7 @@ var init_screen = __esm({
1367
1421
  init_components();
1368
1422
  init_ui_elements();
1369
1423
  init_scrollable_text();
1424
+ init_visible_text();
1370
1425
  init_follow_scroll();
1371
1426
  init_scrollbar();
1372
1427
  init_key_bindings();