Styles
The styles
module handles text styling. It provides functions and classes that can be used to customize the display of text in terminals that support escape sequences .
Style
The Style
type represents a Select Graphic Rendition (SGR ) sequence. It consists of a list of styling attributes and can be used in any part of the API that expects this type.
Styles are cumulative, i.e., they can be combined depending on the kind of styling attribute. For instance, tf.bold
can be combined with fg.green
to render text in bold intensity with green foreground color.
Styling attribute
In the next sections we present the various styling attributes available.
Not all of the attributes are supported in every terminal, so you should experiment with them before committing your code.
Typeface
The tf
enumeration declares text typefaces that can be combined. They are listed below.
- Font attributes:
bold
— bold or increased intensityfaint
— faint, decreased intensity, or dim (lower opacity)italic
— italic typeunderlined
— underlinedslowlyBlinking
— slowly blinkingrapidlyBlinking
— rapidly blinkinginverse
— reverse video or inverse (flips foreground and background color)invisible
— invisible, concealed or hiddencrossedOut
— crossed-out or strikethroughdoublyUnderlined
— doubly underlinedproportionallySpaced
— enable proportional spacingalternative[1-9]
— alternative font (1 through 9)fraktur
— black-letter font
- Ideogram attributes:
ideogramUnderline
— ideogram underline or right side lineideogramDoubleUnderline
— ideogram double underline, or double line on the right sideideogramOverline
— ideogram overline or left side lineideogramDoubleOverline
— ideogram double overline, or double line on the left sideideogramStressMarking
— ideogram stress marking
- Miscellaneous attributes:
framed
— framedencircled
— encircledoverlined
— overlinedsuperscript
— superscriptsubscript
— subscript
Resetting
The rs
enumeration declares attributes that can be used to “cancel” other preceding attributes. They are intended for internal use, so are not exposed in the API. They are listed below.
clear
— resets any other preceding attributeprimaryFont
— primary fontnotBoldOrFaint
— normal intensity (neither bold nor faint)notItalicOrFraktur
— regular type (neither italic nor black-letter)notUnderlined
— not underlinednotBlinking
— steady (not blinking)notInverse
— positive (not inverse)notInvisible
— visible (reveal, or not hidden)notCrossedOut
— not crossed out (no strikethrough)defaultForeground
— default foreground colordefaultBackground
— default background colornotProportionallySpaced
— disable proportional spacingnotFramedOrEncircled
— neither framed nor encirclednotOverlined
— not overlineddefaultUnderline
— default underline colornoIdeogram
— no ideogram attributesnotSuperscriptOrSubscript
— neither superscript nor subscript
Predefined color
The fg
and bg
enumerations declare foreground and background colors, respectively. They both have the same set of predefined colors, which are listed below.
- Standard colors:
black
— blackred
— redgreen
— greenyellow
— yellowblue
— bluemagenta
— magentacyan
— cyanwhite
— white
- High-intensity colors:
brightBlack
— bright “black” (i.e., gray)brightRed
— bright redbrightGreen
— bright greenbrightYellow
— bright yellowbrightBlue
— bright bluebrightMagenta
— bright magentabrightCyan
— bright cyanbrightWhite
— bright white
Extended color
In addition to predefined colors, fg
and bg
have a special enumerator called extended
. It must be followed by additional attributes, which can be obtained through one of the auxiliary functions below:
ext8
— creates an 8-bit indexed colorrgb
— creates a 24-bit RGB color
There is also a ul
enumeration with this enumerator, for underline colors. For example, to set the underline color to orange (#FFA500
):
const : = [., (255, 165, 0)];
ANSI string
The AnsiString
component handles the construction of strings that can be printed in a terminal. It has methods for splitting, appending, and wrapping strings with or without control sequences. The main logic implemented in this class is divided into splitting and wrapping, as is explained in the next subsections.
Text splitting
Text is split into paragraphs, list items and words using a combination of simple regular expressions. The features supported in text splitting are described below.
Placeholders
Both the split
and format
methods of a ANSI string accept a phrase to be split. During splitting, numeric placeholders prefixed with a hashtag #
may be extracted from the text and processed by a formatting callback.
This is used by the library in different places:
- by both the parser and validator, to produce error messages based on configured error phrases
- by the formatter, to assemble help items from configured help phrases
Placeholders are meant to be replaced with a value. The number on the placeholder indicates the index of the argument that was passed to the formatting function. The resulting format depends on the type of the value, which is denoted internally by a single character. The available ones are:
b
— aboolean
values
— astring
value (enclosed by the value of thestringQuote
connective word)n
— anumber
valuer
— aRegExp
valuem
— asymbol
value (e.g., option name)t
— another ANSI string instanceu
— aURL
valuea
— an array or tuple (elements are enclosed by the values of thearrayOpen
andarrayClose
connective words)o
— anobject
(entries are enclosed by the values of theobjectOpen
andobjectClose
connective words)v
— anunknown
value (enclosed by the values of thevalueOpen
andvalueClose
connective words)
When a phrase includes placeholders, they indicate where in the phrase to place the corresponding value. The same placeholder may be repeated multiple times. If a phrase has multiple alternatives (depending on the context), different pieces of text may be specified separated by a vertical bar and grouped in parentheses, e.g. '(...|...)'
.
You can also apply a phrase to each element of an array through the arrayWithPhrase
function.
Formatting flags
The format
method accepts an optional parameter of type FormattingFlags
with the following optional properties:
alt
— the phrase alternative, if anysep
— the element delimiter for array and object values (overrides connective words)open
— the opening delimiter for array and object values (overrides connective words)close
— the closing delimiter for array and object values (overrides connective words)mergePrev
— whether the separator should be merged with the previous element (defaults totrue
)mergeNext
— whether the separator should be merged with the next element (defaults tofalse
)custom
— a custom callback to format the arguments
Paragraphs and lists
Although Markdown  syntax is not fully supported, paragraphs and itemized/numbered lists are formatted in a Markdown-ish fashion. For example, the following text
A paragraph with
single line breaks, redundant spacing and:
- itemized; or
1. numbered lists
Another paragraph
Would be rendered as:
A paragraph with single line breaks, redundant spacing and:
- itemized; or
1. numbered lists
Another paragraph
Template literal
You can easily create ANSI strings with the ansi
tag function for template literals . The latter can be used in any part of the API that expects a styled string, such as option synopsis, deprecation notice, parameter name and text block. It also has a convenient style
method, which accepts a list of styling attributes as parameters, e.g.:
`A text with ${.(., (255, 165, 0))`orange underline`}.`;
You can freely nest template literals with or without style. Just be aware that arguments inside the template will be treated as placeholders. So, for example, a traditional (non-ANSI) template literal will be treated as plain string and thus subject to the formatting of a string
placeholder.
The formatting flags for template literals have default values and cannot be changed.
Text wrapping
Splitted text is always wrapped according to a configured width, i.e., the number of terminal columns by which to limit each line of text. When a width of zero or NaN
is provided, the ANSI string will by default avoid wrapping and instead suppress control sequences that would otherwise be used to render the text in a terminal.
The following features are supported in text wrapping.
Indentation level
The ANSI string has an optional indentation level, i.e., the starting terminal column of each new line of text. When wrapping text to the desired width, the instance will attempt to respect this setting, but if the desired width does not accommodate the length of the largest word, it will disregard the indentation level.
The first line is only affected by this setting if the cursor is positioned before the configured value.
Text alignment
The ANSI string has an optional flag that indicates whether the text should be aligned to the terminal’s right boundary (or according to the instance’s width
property). This feature is used by the formatter in help messages.
Line-wise wrapping
The ANSI string can be chained with another instance for the purpose of multi-column wrapping. We call this mode “line-wise”, because it allows the lines of each instance to be wrapped independently of other instances. This feature is used by the formatter when rendering a groups section configured with non-responsive layout.
The first instance in a chain serves as the “head”, and it drives the procedure until all lines of all instances are wrapped. The final instance in a chain serves as the “tail”, and should be empty (i.e., have no internal strings). Line feeds from child instances are ignored, because it is he head who appends them to the result.
In this mode, the terminal width is ignored, as it makes no sense. Instead, each instance should be configured with its own width. For this to work, the length of the longest word in any instance must not exceed the instance’s width. Otherwise, an error will be raised to alert the developer of this issue.
The reason an error may occur is that we cannot split words, as they may have styles that should not leak into subsequent columns.
Messages
There are different kinds of content that an application might want to print in the terminal. We denote them “messages” and provide a specific class for each kind of message that the library can produce.
For convenience, all message classes have a toString
method and a message
property, both of which can be used to obtain a plain string
. However, each class uses its own default terminal width to render the resulting string. The various classes are described below.
All messages produced by the library are instances of one of these classes. So you can check the kind of a captured message through instanceof
.
ANSI message
The AnsiMessage
class wraps a list of ANSI strings and is the type used for help messages and version info. It provides a wrap
method to get a plain string, accepting the following optional parameters:
width
— the desired terminal width (0
means no wrapping)emitStyles
— whether styles should be emittedemitSpaces
— whether spaces should be emitted instead of move sequences
The default values of these parameters depend on a few environment variables:
FORCE_WIDTH
— force the terminal width to a specific value (otherwise, see below)FORCE_COLOR
— force emission of styles regardless of the terminal widthNO_COLOR
— force omission of styles regardless of the terminal widthTERM
— set to'dumb'
to achieve the same behavior asNO_COLOR
FORCE_SPACES
— force emission of spaces when the terminal width is non-zero
When FORCE_WIDTH
is not set, the default width used by this class is the columns
property of the standard output stream (i.e., process.stdout
). Therefore, this kind of message should be printed with console.log
or equivalent.
When redirecting the output of a command (e.g., writing to a file or piping to another command), the associated stream may not have a columns
property, thus defaulting to zero width.
Generally, you should refrain from altering the returned string after being wrapped, as this would mess up the disposition of text in the terminal. If you must, you can either prepend text ending with line feeds, or append text starting with line feeds, as this will preserve the disposition of wrapped text.
Alternatively, you can retrieve the underlying strings and manipulate them before calling the wrap
method.
Error message
The ErrorMessage
class is a specialization of the ANSI message, used for errors and warnings. It also has a utility method add
, which appends a ANSI string formatted from either one of the error phrases or a custom phrase.
When FORCE_WIDTH
is not set, the default width used by this class is the columns
property of the standard error stream (i.e., process.stderr
). Therefore, this kind of message should be printed with console.error
or equivalent.
Text message
The TextMessage
class represents a list of text lines with no wrapping and is the type used for completion words. It produces a string delimited by line feeds, and should be printed with console.log
or equivalent.
JSON message
The JsonMessage
class represents a list of opaque objects and is the type used for completion suggestions. It produces a serialized JSON string, and should be printed with console.log
or equivalent.
Message configuration
ANSI-based messages produced by the library can be customized via the global config
object, which is a singleton instance of the MessageConfig
type, containing the properties described below.
Message styles
The styles
property specifies the styles of text elements in ANSI messages. It has the following settings:
Property | Used for | Default style |
---|---|---|
boolean | Boolean values | fg.blue |
string | String values | fg.green |
number | Number values | fg.yellow |
regex | Regular expressions | fg.red |
symbol | Symbols (e.g., names) | fg.magenta |
value | Unknown values | fg.brightBlack |
url | URLs | fg.cyan |
error | Error messages | fg.brightRed |
base | Base style | none |
To preserve previous styles for a particular element, you can assign it an empty Style
. Or, to completely disable styling for your application (regardless of environment configuration), do the same for all elements.
Connective words
The connectives
property specifies words used to format some text elements that cannot be customized with phrases, such as option requirements, element separators and string quoting. It has the following settings:
Property | Description | Default |
---|---|---|
and | Connects two logical expressions in conjunction | 'and' |
or | Connects two logical expressions in disjunction | 'or' |
not | Connects a logical expression in negation | 'not' |
no | Connects a logical expression in non-existence | 'no' |
equals | Connects two expressions in equality comparison | '==' |
notEquals | Connects two expressions in non-equality comparison | '!=' |
optionAlt | Connects two option names in alternation | '|' |
optionSep | Connects two option names in succession | ',' |
stringQuote | Encloses a string value | "'" |
arraySep | Connects two array elements in succession | ',' |
arrayOpen | Opening bracket of an array value | '[' |
arrayClose | Closing bracket of an array value | ']' |
objectSep | Connects two object entries in succession | ',' |
objectOpen | Opening bracket of an object value | '{' |
objectClose | Closing bracket of an object value | '}' |
valueSep | Connects an object key with its value | ':' |
valueOpen | Opening bracket of an unknown value | '<' |
valueClose | Closing bracket of an unknown value | '>' |
exprOpen | Opening bracket of an expression | '(' |
exprClose | Closing bracket of an expression | ')' |
optionalOpen | Opening bracket of an optional group | '[' |
optionalClose | Closing bracket of an optional group | ']' |
Connective words should not contain line feeds.
Error phrases
The errorPhrases
property specifies the phrases to use for error messages. It has the following settings, whose keys are enumerators from ErrorItem
:
Error item | Raised when | Default phrase | Placeholders |
---|---|---|---|
unknownOption | An option name is not found, with possible name suggestions | 'Unknown option #0.(| Similar names are: #1.)' | #0 = the unknown option name; #1 = the similar names |
unsatisfiedRequirement | An option’s forward requirement is not satisfied | 'Option #0 requires #1.' | #0 = the supplied option name; #1 = the requirements |
missingRequiredOption | An option that is always required was not supplied | 'Option #0 is required.' | #0 = the option’s preferred name |
missingParameter | An option is supplied without one of its expected parameter(s) | 'Missing parameter(s) to option #0: requires (exactly|at least|between) #1.' | #0 = the supplied option name; #1 = the expected parameter count |
disallowedInlineParameter | An option is supplied with an inline parameter, despite being disallowed | 'Option #0 does not accept inline parameters.' | #0 = the supplied option name |
choiceConstraintViolation | An option parameter fails to satisfy a choice constraint | 'Invalid parameter to #0: #1. Value must be one of: #2.' | #0 = the supplied option name; #1 = the supplied value; #2 = the choices |
regexConstraintViolation | An option parameter fails to satisfy a regex constraint | 'Invalid parameter to #0: #1. Value must match the regex #2.' | #0 = the supplied option name; #1 = the supplied value; #2 = the regex |
limitConstraintViolation | An option value fails to satisfy a count limit constraint | 'Option #0 has too many values: #1. Should have at most #2.' | #0 = the supplied option name; #1 = the element count; #2 = the limit |
deprecatedOption | A deprecated option is supplied on the command line | 'Option #0 is deprecated and may be removed in future releases.' | #0 = the supplied option name |
unsatisfiedCondRequirement | An option’s conditional requirement is not satisfied | 'Option #0 is required if #1.' | #0 = the supplied option name; #1 = the requirements |
invalidClusterOption | A variadic option option is supplied in the middle of a cluster argument | 'Option letter #0 must be the last in a cluster.' | #0 = the supplied cluster letter |
missingInlineParameter | An option is supplied with no inline parameter, despite being required | 'Option #0 requires an inline parameter.' | #0 = the supplied option name |
invalidOptionName | An option has an invalid name, cluster letter or environment variable name | 'Option #0 has invalid name #1.' | #0 = the option’s key; #1 = the invalid name |
invalidSelfRequirement | An option references itself in a requirement | 'Option #0 requires itself.' | #0 = the option’s key |
unknownRequiredOption | An option references an unknown option in a requirement | 'Unknown option #0 in requirement.' | #0 = the required option’s key |
invalidRequiredOption | An option references a non-valued option in a requirement | 'Invalid option #0 in requirement.' | #0 = the required option’s key |
invalidRequiredValue | An option uses an invalid value in a requirement | 'Invalid required value for option #0. Option is always required or has a default value.' | #0 = the required option’s key |
duplicateOptionName | There are duplicate option names, cluster letters or environment variable names | 'Option #0 has duplicate name #1.' | #0 = the option’s key; #1 = the duplicate name |
duplicateParameterChoice | A choices constraint has a duplicate value | 'Option #0 has duplicate choice #1.' | #0 = the option’s key; #1 = the duplicate value |
tooSimilarOptionNames | An option name is too similar to other names | '#0: Option name #1 has too similar names: #2.' | #0 = the subcommand prefix1; #1 = the option name; #2 = the similar names |
mixedNamingConvention | A name slot contains names with different naming conventions | '#0: Name slot #1 has mixed naming conventions: #2.' | #0 = the subcommand prefix1; #1 = the name slot index; #2 = the naming conventions |
invalidParamCount | A function option has an invalid parameter count | 'Option #0 has invalid parameter count #1.' | #0 = the option’s key; #1 = the parameter count |
variadicWithClusterLetter | A variadic option declares cluster letters | 'Variadic option #0 may only appear at the end of a cluster.' | #0 = the option’s key |
invalidInlineConstraint | An option declares an invalid inline constraint | 'Option #0 has invalid inline constraint.' | #0 = the option’s key |
invalidOption | An option is not suppliable | 'Option #0 is not suppliable.' | #0 = the option’s key |
Error phrases are formatted according to text formatting rules.
Help phrases
The helpPhrases
property specifies the phrases to use for help items. It has the following settings, whose keys are enumerators from HelpItem
:
Help item | Description | Default phrase | Placeholders |
---|---|---|---|
synopsis | The option’s synopsis | '#0' | #0 = the option synopsis |
cluster | The option’s cluster letters | 'Can be clustered with #0.' | #0 = the cluster letters |
separator | The parameter delimiter of an array-valued option | 'Values can be delimited with #0.' | #0 = the parameter separator |
paramCount | The parameter count of a variadic or polyadic option | 'Accepts (multiple|#0|at most #0|at least #0|between #0) parameters.' | #0 = the parameter count |
positional | Whether the option accepts positional arguments | 'Accepts positional arguments.' | |
inline | The option’s treatment of inline parameters | '(Disallows|Requires) inline parameters.' | |
append | Whether an array-valued option can be supplied multiple times | 'Can be supplied multiple times.' | |
choices | The option’s parameter choices | 'Values must be one of #0.' | #0 = the parameter choices |
regex | The regular expression that parameters should match | 'Values must match the regex #0.' | #0 = the regular expression |
unique | Whether duplicate elements are removed from an array-valued option value | 'Duplicate values will be removed.' | |
limit | The element count limit of an array-valued option | 'Element count is limited to #0.' | #0 = the count limit |
sources | The option’s environment data sources | 'If not supplied on the command line, will be read from #0.' | #0 = the data sources |
stdin | Whether the option reads data from the standard input | '(If not supplied, will|Will) be read from the standard input.' | |
requires | The option’s forward requirements | 'Requires #0.' | #0 = the requirements |
required | Whether the option is always required | 'Always required.' | |
requiredIf | The option’s conditional requirements | 'Required if #0.' | #0 = the requirements |
default | The option’s default value | 'Defaults to #0.' | #0 = the default value |
useCommand | Whether a help option uses the next argument as the name of a subcommand | 'Uses the next argument as the name of a subcommand.' | |
useFilter | Whether a help option uses the remaining arguments as option filter | 'Uses the remaining arguments as option filter.' | |
deprecated | The option’s deprecation notice | 'Deprecated for #0.' | #0 = the deprecation notice |
link | The option’s external media hyperlink | 'Refer to #0 for details.' | #0 = the media hyperlink |
Help phrases are formatted according to text formatting rules.
Footnotes
-
The subcommand prefix is a series of option keys interspersed with periods, denoting the current level in a hierarchical definition. It begins as the empty string and is appended with a subcommand’s key whenever one is encountered. It also appears in other validation errors, prefixing the option’s key (e.g.:
cmd1.cmd2.flag
). ↩ ↩2