Skip to content

Package: strings

Eugene Lazutkin edited this page Sep 26, 2026 · 14 revisions

The strings.js package provides helpers for working with strings — the simplest text container: an array of strings. See Concepts for background.

const strings = ['one', 'two', 'three'];

for (const line of strings) console.log(line);

Important note: Some Unicode symbols (East Asian characters, certain emoji) are double-wide. Emoji widths are built in: an emoji in Unicode's RGI set, an unqualified keycap, or a ZWJ sequence is two cells, and a text-presentation symbol such as ☃ without VS16 is one. For East Asian characters, strings can optionally use get-east-asian-width, loaded dynamically if installed. Without it, East Asian characters are assumed to be single-wide. Combining marks and invisible formatting characters, such as zero-width space (U+200B) or the byte order mark (U+FEFF), take no cells; the soft hyphen (U+00AD) keeps its cell, and a spacing mark, such as the vowel sign in Devanagari कि, adds its own, as in glibc's wcwidth().

Warning: character width detection is not 100% reliable and depends on the font. Use with caution.

Note on Bun: The package above is used on Bun too, so widths match Node and Deno. Only when it isn't installed does getLength() fall back to Bun.stringWidth(), for the East Asian width of each character; the other rules stay the same. Its tables lag behind the package on some recently added wide characters, which it counts as one cell. Version 1.4.0 and earlier always used Bun.stringWidth() on Bun.

strings.js

The main module of the strings package. It depends on the sub-modules described below.

import {getLength, toStrings} from 'console-toolkit/strings.js';

Exports:

Name Return Description
matchCsiNoGroups RegExp Matches CSI sequences with no groups.
matchCsiNoSgrNoGroups RegExp Matches CSI sequences excluding SGR commands and no groups.
getLength(string, matcher = matchCsiNoGroups) number Returns the length of the string.
getMaxLength(strings, matcher = matchCsiNoGroups) number Returns the maximum length of the strings.
clip(string, width, options = {}) string Returns the clipped string.
clipStrings(strings, width, options = {}) strings Returns the clipped strings.
toStrings(arg) strings Creates a string array from various sources.

options is an optional object with the following optional properties:

  • includeLastCommand — if true, the last (invisible) command is included in the clipping. Defaults to false.
  • preserveState — if true, SGR commands are appended so the clipped string ends in the same SGR state as the whole string: a style closed in the cut-off part is closed, and a style the string leaves open stays open. SGR commands are read regardless of matcher. Defaults to false.
  • matcher — a regular expression used to match the string. Defaults to matchCsiNoGroups.
  • ignoreControlSymbols — if true, control symbols are ignored when calculating the width.
  • ambiguousAsWide — if true, East Asian ambiguous-width characters are treated as wide.

getLength() calculates the visible length of a string, excluding invisible SGR commands and accounting for multi-code-unit Unicode characters. A return value of 5 means the string occupies exactly 5 screen columns.

getMaxLength() returns the maximum length across all strings.

clip() clips a string to the given display width, handling SGR commands and multi-code-unit characters.

Example:

const s = style.bold.text('X') + 'Y'; // '\x1B[1mX\x1B[mY'
const a = clip(s, 1); // '\x1B[1mX'
const b = clip(s, 1, {includeLastCommand: true}); // '\x1B[1mX\x1B[m'

const t = style.bg.blue.text(style.red.text('abc') + 'def');
const c = clip(t, 3); // blue background and red text stay on
const d = clip(t, 3, {preserveState: true}); // both are closed, as at the end of t

clipStrings() clips strings by applying clip() to each of them.

toStrings(arg) converts its argument to a string array:

  • A function — calls it with no arguments and reapplies toStrings() to its result.
    • A function could return a function, but toStrings() restricts the recursion to 10 invocations.
  • A number, boolean, bigint, or symbol — returns [String(arg)].
  • A string is split by newlines and returned as an array of strings.
  • An array is copied (shallow) and returned as is.
  • An object with a function property toStrings() is called and its result is returned.
  • Other non-null objects are converted via String(arg) and reprocessed.
  • null, undefined, and anything else returns an empty array.

strings can express almost all text rectangles:

  • ['', ''] — 2 by 0 rectangle
  • ['z'] — 1 by 1 rectangle
  • [] — 0 by 0 rectangle

strings cannot express 0 by N rectangles.

Exports

All objects described above are exported. There is no default export.

strings/parse.js

Exports a generator function for parsing strings.

import parse from 'console-toolkit/strings/parse.js';

Exports:

Name Return Description
matchCsiNoGroups RegExp Matches CSI sequences with no groups.
matchCsiNoSgrNoGroups RegExp Matches CSI sequences excluding SGR commands and no groups.
parse(s, matcher = matchCsiNoGroups) generator Parses the string.

parse() uses matcher and yields triplets: {string, start, match}:

  • string is the string that preceded the match.
  • start is the start index of string from the beginning of s.
  • match is the result of matcher on the s.
    • matchCsiNoGroups and matchCsiNoSgrNoGroups have no groups. match[0] is the whole matched escape sequence. If certain details are needed, define your own matcher.

Example:

import parse from 'console-toolkit/strings/parse.js';
import {extractState} from 'console-toolkit/ansi/sgr-state.js';

// ...

for (const {string, start, match} of parse(input)) {
  console.log('From:', start, ' string:', string);

  const state = extractState(match[0]);
  console.log('State:', state);
}

Exports

All objects described above are exported. parse() is the default export.

strings/split.js

Exports functions to split strings into graphemes and calculate display width, optionally detecting double-wide characters (see note above).

import {split, size} from 'console-toolkit/strings/split.js';

Exports:

Name Return Description
split(string, options = {}) {graphemes, width} Splits the string into graphemes.
size(string, options = {}) number Calculates the string width.

options is an optional object with the following optional properties:

  • ignoreControlSymbols — if true, control symbols are ignored. Defaults to false.
  • ambiguousAsWide — if true, ambiguous characters are treated as double wide. Defaults to false.
    • This option is used only with the optional get-east-asian-width module. See get-east-asian-width for more details.

size() returns the string width. This function is used to implement getLength() of strings.js:

const getLength = (s, matcher) => {
  let counter = 0;
  for (const {string} of parse(s, matcher)) {
    counter += size(string);
  }
  return counter;
};

split() returns an object with the following properties:

  • graphemes — an array of graphemes, each with:
    • symbol — the symbol as a string.
    • width — display width (1 or 2; 2 only when optional packages are installed).
  • width — total display width of the string (same as size()).

This function is used to implement clip() of strings/clip.js and create Panel of Module: panel.

Exports

All objects described above are exported. split() is the default export.

strings/clip.js

Clips a string to a given display width.

import clip from 'console-toolkit/strings/clip.js';

Export:

Name Return Description
clip(string, width, options = {}) string Returns the clipped string.

See clip() in strings.js above for details.

Exports

clip() is exported by name and as the default export.

Clone this wiki locally