Repository navigation
Package: strings
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.
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— iftrue, the last (invisible) command is included in the clipping. Defaults tofalse. -
preserveState— iftrue, 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 ofmatcher. Defaults tofalse. -
matcher— a regular expression used to match the string. Defaults tomatchCsiNoGroups. -
ignoreControlSymbols— iftrue, control symbols are ignored when calculating the width. -
ambiguousAsWide— iftrue, 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 tclipStrings() 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 function could return a function, but
- 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-
nullobjects are converted viaString(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.
All objects described above are exported. There is no default export.
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}:
-
stringis the string that preceded thematch. -
startis the start index ofstringfrom the beginning ofs. -
matchis the result ofmatcheron thes.-
matchCsiNoGroupsandmatchCsiNoSgrNoGroupshave 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);
}All objects described above are exported. parse() is the default export.
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— iftrue, control symbols are ignored. Defaults tofalse. -
ambiguousAsWide— iftrue, ambiguous characters are treated as double wide. Defaults tofalse.- This option is used only with the optional
get-east-asian-widthmodule. See get-east-asian-width for more details.
- This option is used only with the optional
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 assize()).
This function is used to implement clip() of strings/clip.js and create Panel of
Module: panel.
All objects described above are exported. split() is the default export.
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.
clip() is exported by name and as the default export.
Start here
Text containers
Styling
Drawing
Complex visuals
Dynamic output