@nmakarov/cli-toolkit 0.81.0 → 0.84.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.js CHANGED
@@ -615,23 +615,23 @@ function formatKeyBindings(bindings, mode = "long") {
615
615
  })));
616
616
  groups.sort((a, b) => a.order - b.order);
617
617
  const items = [];
618
- groups.forEach((group) => {
618
+ groups.forEach((group, groupIndex) => {
619
619
  const bindingWithCustom = resolvedBindings.find(
620
- (b) => group.keys.includes(b.key) && typeof b.resolvedCaption !== "string"
620
+ (b) => group.keys.includes(formatBindingKey(b)) && typeof b.resolvedCaption !== "string"
621
621
  );
622
622
  if (bindingWithCustom && bindingWithCustom.resolvedCaption) {
623
623
  items.push(bindingWithCustom.resolvedCaption);
624
624
  } else {
625
- const keyStr = formatKeys(group.keys);
626
- if (mode === "long") {
627
- items.push(`${keyStr} to ${group.caption}`);
628
- } else {
629
- items.push(keyStr);
630
- }
625
+ items.push(formatFooterHotkey(formatKeys(group.keys), group.caption, mode, `kb-${groupIndex}`));
631
626
  }
632
627
  });
633
628
  return items;
634
629
  }
630
+ function formatFooterHotkey(keyStr, caption = "", mode = "long", reactKey = "hotkey") {
631
+ const keyNode = h3(Text3, { key: `${reactKey}-key`, ...FOOTER_HOTKEY_STYLE }, keyStr);
632
+ if (mode !== "long" || !caption) return keyNode;
633
+ return h3(Text3, { key: reactKey, dimColor: true, color: "white" }, keyNode, ` to ${caption}`);
634
+ }
635
635
  function formatKeys(keys) {
636
636
  const keyMap = {
637
637
  escape: "esc",
@@ -901,12 +901,13 @@ async function showMultiColumnListWithPreviewScreen(config2) {
901
901
  }
902
902
  });
903
903
  }
904
- var showMenuScreen, showWordGridScreen;
904
+ var FOOTER_HOTKEY_STYLE, showMenuScreen, showWordGridScreen;
905
905
  var init_screens = __esm({
906
906
  "src/screen/screens.js"() {
907
907
  init_components();
908
908
  init_list_components();
909
909
  init_key_bindings();
910
+ FOOTER_HOTKEY_STYLE = { bold: true, color: "white", dimColor: false };
910
911
  showMenuScreen = showListScreen;
911
912
  showWordGridScreen = showMultiColumnListScreen;
912
913
  }
@@ -1020,9 +1021,44 @@ var init_follow_scroll = __esm({
1020
1021
  }
1021
1022
  });
1022
1023
 
1023
- // src/screen/scrollable-text.js
1024
- import { useState as useState3, useEffect as useEffect2, useMemo, useRef as useRef2, createElement as createElement2 } from "react";
1025
- import { Box as Box4, Text as Text5 } from "ink";
1024
+ // src/screen/visible-text.js
1025
+ function stripAnsi(text) {
1026
+ return String(text ?? "").replace(ANSI_RE, "");
1027
+ }
1028
+ function visibleWidth(text) {
1029
+ return [...stripAnsi(text)].length;
1030
+ }
1031
+ function sliceVisible(text, cols) {
1032
+ const w = Math.max(0, Math.floor(Number(cols) || 0));
1033
+ const s = String(text ?? "");
1034
+ if (w === 0) return "";
1035
+ let vis = 0;
1036
+ let out = "";
1037
+ let i = 0;
1038
+ while (i < s.length && vis < w) {
1039
+ ANSI_RE.lastIndex = i;
1040
+ const m = ANSI_RE.exec(s);
1041
+ if (m && m.index === i) {
1042
+ out += m[0];
1043
+ i += m[0].length;
1044
+ continue;
1045
+ }
1046
+ const cp3 = s.codePointAt(i);
1047
+ const ch = String.fromCodePoint(cp3);
1048
+ out += ch;
1049
+ i += ch.length;
1050
+ vis += 1;
1051
+ }
1052
+ return out;
1053
+ }
1054
+ function padEndVisible(text, cols) {
1055
+ const w = Math.max(0, Math.floor(Number(cols) || 0));
1056
+ const s = String(text ?? "");
1057
+ const vis = visibleWidth(s);
1058
+ if (vis === w) return s;
1059
+ if (vis > w) return sliceVisible(s, w);
1060
+ return s + " ".repeat(w - vis);
1061
+ }
1026
1062
  function wrapTextLines(text, cols) {
1027
1063
  const w = Math.max(1, Math.floor(Number(cols) || 1));
1028
1064
  const out = [];
@@ -1031,20 +1067,30 @@ function wrapTextLines(text, cols) {
1031
1067
  out.push("");
1032
1068
  continue;
1033
1069
  }
1070
+ if (visibleWidth(raw) <= w) {
1071
+ out.push(raw);
1072
+ continue;
1073
+ }
1034
1074
  let rest = raw;
1035
- while (rest.length > w) {
1036
- out.push(rest.slice(0, w));
1037
- rest = rest.slice(w);
1075
+ while (visibleWidth(rest) > w) {
1076
+ const head = sliceVisible(rest, w);
1077
+ out.push(head);
1078
+ rest = rest.slice(head.length);
1038
1079
  }
1039
1080
  if (rest.length > 0) out.push(rest);
1040
1081
  }
1041
1082
  return out;
1042
1083
  }
1043
- function padEndVisible(s, w) {
1044
- const t = String(s ?? "");
1045
- if (t.length >= w) return t.slice(0, w);
1046
- return t + " ".repeat(w - t.length);
1047
- }
1084
+ var ANSI_RE;
1085
+ var init_visible_text = __esm({
1086
+ "src/screen/visible-text.js"() {
1087
+ ANSI_RE = /\u001b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
1088
+ }
1089
+ });
1090
+
1091
+ // src/screen/scrollable-text.js
1092
+ import { useState as useState3, useEffect as useEffect2, useMemo, useRef as useRef2, createElement as createElement2 } from "react";
1093
+ import { Box as Box4, Text as Text5 } from "ink";
1048
1094
  function ScrollableText({
1049
1095
  ctx,
1050
1096
  text = "",
@@ -1112,14 +1158,17 @@ function ScrollableText({
1112
1158
  }, [ctx, bindKeys, followBottom]);
1113
1159
  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" : "");
1114
1160
  const rowNodes = visible.map((line, i) => {
1115
- const body = padEndVisible(line, textWidth);
1116
1161
  const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? " " : "";
1117
1162
  const isThumb = glyph === BAR_THUMB;
1118
1163
  return h5(
1119
- Text5,
1120
- { key: `L${clamped + i}` },
1121
- body,
1122
- glyph ? h5(Text5, { color: isThumb ? "cyan" : "gray" }, glyph) : null
1164
+ Box4,
1165
+ { key: `L${clamped + i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
1166
+ h5(
1167
+ Box4,
1168
+ { width: textWidth, flexShrink: 0 },
1169
+ h5(Text5, { wrap: "truncate" }, padEndVisible(line, textWidth))
1170
+ ),
1171
+ showScrollbar ? h5(Box4, { width: 1, flexShrink: 0 }, h5(Text5, { color: isThumb ? "cyan" : "gray" }, glyph)) : null
1123
1172
  );
1124
1173
  });
1125
1174
  if (bar && visible.length < viewportRows) {
@@ -1127,10 +1176,10 @@ function ScrollableText({
1127
1176
  const glyph = bar[i] ?? BAR_TRACK;
1128
1177
  rowNodes.push(
1129
1178
  h5(
1130
- Text5,
1131
- { key: `pad${i}` },
1132
- padEndVisible("", textWidth),
1133
- h5(Text5, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph)
1179
+ Box4,
1180
+ { key: `pad${i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
1181
+ h5(Box4, { width: textWidth, flexShrink: 0 }, h5(Text5, {}, padEndVisible("", textWidth))),
1182
+ h5(Box4, { width: 1, flexShrink: 0 }, h5(Text5, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph))
1134
1183
  )
1135
1184
  );
1136
1185
  }
@@ -1149,7 +1198,9 @@ var init_scrollable_text = __esm({
1149
1198
  init_components();
1150
1199
  init_scrollbar();
1151
1200
  init_follow_scroll();
1201
+ init_visible_text();
1152
1202
  init_scrollbar();
1203
+ init_visible_text();
1153
1204
  h5 = createElement2;
1154
1205
  SCROLL_KEYS = [
1155
1206
  { key: "upArrow", caption: "scroll", action: "scrollUp", order: 0 },
@@ -1307,6 +1358,7 @@ var init_screen = __esm({
1307
1358
  init_components();
1308
1359
  init_ui_elements();
1309
1360
  init_scrollable_text();
1361
+ init_visible_text();
1310
1362
  init_follow_scroll();
1311
1363
  init_scrollbar();
1312
1364
  init_key_bindings();
@@ -10138,6 +10190,7 @@ export {
10138
10190
  DEFAULT_RUNTIME_PARAM_SPECS,
10139
10191
  Db,
10140
10192
  Divider,
10193
+ FOOTER_HOTKEY_STYLE,
10141
10194
  FileDatabase,
10142
10195
  FileDatabaseError,
10143
10196
  FooterPresets,
@@ -10222,6 +10275,7 @@ export {
10222
10275
  ensureTasksRuntime,
10223
10276
  flushTaskIpcLogs,
10224
10277
  formatBindingKey,
10278
+ formatFooterHotkey,
10225
10279
  getArgsInstance,
10226
10280
  getPm2Process,
10227
10281
  createElement3 as h,
@@ -10252,6 +10306,7 @@ export {
10252
10306
  npmEnv,
10253
10307
  npmInstallEnv,
10254
10308
  organizeFooterMessages,
10309
+ padEndVisible,
10255
10310
  parseGitHost,
10256
10311
  parsePm2Jlist,
10257
10312
  prepareGitHost,
@@ -10297,9 +10352,11 @@ export {
10297
10352
  showMultiColumnListWithPreviewScreen,
10298
10353
  showScreen,
10299
10354
  showWordGridScreen,
10355
+ sliceVisible,
10300
10356
  sshRun,
10301
10357
  startPm2,
10302
10358
  stopPm2,
10359
+ stripAnsi,
10303
10360
  syncEnv,
10304
10361
  taskHistoryInsertFromQueueRow,
10305
10362
  timeMatcher,
@@ -10316,6 +10373,7 @@ export {
10316
10373
  useMemo2 as useMemo,
10317
10374
  useRef3 as useRef,
10318
10375
  useState4 as useState,
10376
+ visibleWidth,
10319
10377
  waitForTaskResult,
10320
10378
  waitPm2,
10321
10379
  wrapTextLines,