@oh-my-pi/pi-tui 17.4.2 → 18.0.1

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/src/utils.ts CHANGED
@@ -225,6 +225,13 @@ export function getSegmenter(): Intl.Segmenter {
225
225
  // added back so width matches the native truncate/slice/wrap helpers.
226
226
  const OSC66_SPAN_REGEX = /\x1b\]66;([^;]*);([\s\S]*?)(?:\x07|\x1b\\)/g;
227
227
  const OSC66_PREFIX = "\x1b]66;";
228
+ // APC sequences (`ESC _ ... ST|BEL`) — Kitty graphics commands such as the
229
+ // virtual-placement prefix on Unicode-placeholder image lines, or the TUI's
230
+ // BEL-terminated cursor marker. `Bun.stringWidth` strips CSI/OSC but counts APC
231
+ // payloads as printable text, so they are removed before measuring (they occupy
232
+ // zero cells — matching the native width engine in pi-natives/text.rs).
233
+ const APC_SPAN_REGEX = /\x1b_[\s\S]*?(?:\x07|\x1b\\)/g;
234
+ const APC_PREFIX = "\x1b_";
228
235
  const PRINTABLE_ASCII_REGEX = /^[\u0020-\u007e]*$/;
229
236
 
230
237
  // Pin Bun.stringWidth semantics to the native width engine and guard against Bun
@@ -296,8 +303,9 @@ let visibleWidthCacheEpoch = widthConfigEpoch;
296
303
  * Visible width of a string in terminal columns, excluding ANSI/OSC escapes.
297
304
  *
298
305
  * `Bun.stringWidth` does the heavy lifting (UAX#11 width tables + ANSI/OSC
299
- * stripping); this adds the two corrections it omits — tabs (expanded to
300
- * `tabWidth` cells) and OSC 66 text-sizing payloads (scaled by `s=`).
306
+ * stripping); this adds the corrections it omits — tabs (expanded to
307
+ * `tabWidth` cells), OSC 66 text-sizing payloads (scaled by `s=`), and APC
308
+ * sequences (counted as printable by Bun, actually zero cells).
301
309
  */
302
310
  export function visibleWidth(str: string): number {
303
311
  if (!str) return 0;
@@ -337,7 +345,8 @@ export function visibleWidth(str: string): number {
337
345
  }
338
346
  }
339
347
 
340
- let width = Bun.stringWidth(str, STRING_WIDTH_OPTS);
348
+ const measurable = hasEsc && str.includes(APC_PREFIX) ? str.replace(APC_SPAN_REGEX, "") : str;
349
+ let width = Bun.stringWidth(measurable, STRING_WIDTH_OPTS);
341
350
  if (tabCount > 0) width += tabCount * DEFAULT_TAB_WIDTH;
342
351
 
343
352
  if (hasEsc && str.includes(OSC66_PREFIX)) {