Engee documentation

StyledStrings

The page is in the process of being translated.

CurrentModule = StyledStrings
DocTestSetup = quote
    using StyledStrings
end

The API for StyledStrings and AnnotatedStrings is considered experimental and can be changed in different versions of Julia.

Applying Style

When working with strings, formatting and applying style often take a back seat.

For example, when outputting to a terminal, you may need to add https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_ (Select_Graphic_Rendition)_parameters[ANSI escape sequences] in the output when the output constructs are in HTML style (<span style="...">, etc.) serve a similar purpose, and so on. You can simply paste the raw style constructs into the row next to the content itself, but it quickly becomes clear that this option is suitable only for the simplest use cases. Not all terminals support the same ANSI codes, and style constructs need to be painstakingly removed when calculating the width of already stylized content, not to mention working with multiple output formats.

This task can be solved by introducing a special string type (AnnotatedString). This string type encloses any other type. AbstractString and allows formatting information to be applied to areas (for example, characters 1 through 7 are highlighted in bold and red).

Areas of the string are styled by applying fonts to them (Face) — a structure that contains information about the style. For convenience, fonts in the global font dictionary (for example, shadow) can simply be named instead of passing the font (Face) directly.

Along with these features, we also provide a convenient way to build AnnotatedString, described in detail in the section Literals of stylized strings.

julia> using StyledStrings


julia> styled"{yellow:hello} {blue:there}"
"hello there"

Annotated lines

Sometimes it is useful to be able to store metadata related to areas of a string. AnnotatedString' wraps another string and allows you to annotate its areas with labeled values (+:label ⇒ value+). All universal string operations are applied to the base string. However, when possible, the style information is saved. This means that you can work with `AnnotatedString — take substrings, complement them, combine them with other strings — and metadata annotations will be attached.

This string type is the main one for [StyledStrings stdlib] (StyledStrings.md#stdlib-styledstrings), which uses annotations marked :face, for storing information about the style.

When concatenating AnnotatedString try to use annotatedstring instead of string, if you want to save string annotations.

julia> str = AnnotatedString("hello there", [(1:5, :word, :greeting), (7:11, :label, 1)])
"hello there"

julia> length(str)
11

julia> lpad(str, 14)
"   hello there"

julia> typeof(lpad(str, 7))
AnnotatedString{String}

julia> str2 = AnnotatedString(" julia", [(2:6, :face, :magenta)])
" julia"

julia> annotatedstring(str, str2)
"hello there julia"

julia> str * str2 == annotatedstring(str, str2) # *-конкатенация работает
true

Access to annotations AnnotatedString and their modification is carried out using the functions annotations and annotate!.

Stylization using AnnotatedString

Fonts

The Face type

'Face' defines the details of the font that the text can be typed in. It covers a set of basic attributes that are well suited for various formats, namely:

  • font

  • height

  • weight

  • slant

  • foreground

  • background

  • underline

  • strikethrough

  • inverse

  • inherit

For more information about the forms these attributes take, see the docstring description. Face, but inherit is of particular interest because it allows you to inherit attributes from other fonts (Face).

Global Font Dictionary

For the convenience of references to certain styles, there is a global dictionary Dict'.{Symbol, Face}, which allows you to link to fonts (Face) just by name. Packages can add fonts to this dictionary using the function addface!, and downloaded fonts can be easily customize.

!!! warning "Appropriate face naming" Any package registering new fonts must ensure that they have a prefix in the form of the package name, i.e. compliance with the format mypackage_myface. This is important for predictability and avoiding naming conflicts.

Additionally, packages should use (and introduce) *semantic* fonts (e.g., `code`) rather than direct colors and styles (e.g., `cyan`). This is useful for a variety of reasons, from a more obvious intent in use, to compositionality and more intuitive user customization.

There are two exceptions to the packet prefix rule:

  • a set of basic fonts that are part of the default value of the font dictionary;

  • fonts provided by Julia’s own standard library, namely `JuliaSyntaxHighlighting'.

Basic fonts

The basic fonts are designed to represent a broadly applicable general idea.

To set text with a specific attribute, there are the following fonts: bold, light, italic, underline, strikethrough and `inverse'.

Named fonts are also provided for the 16 terminal colors: black, red, green, yellow, blue, magenta, cyan, white, bright_black/grey/gray, bright_red, bright_green, bright_blue, bright_magenta', `bright_cyan and `bright_white'.

For shaded text (i.e., dim but present), the shadow font is used. There is a region font to indicate the selected area. The fonts emphasis and highlight are defined to indicate significance and emphasis. There is also a `code' for code-like text.

Fonts such as error, warning, success, info, note and tip are defined to visually indicate the severity of messages.

Font Settings (`Faces.toml')

It is advisable that the named fonts in the global font dictionary are customizable. The design and aesthetics are a wonderful addition, which is also important in terms of special features. The TOML file can be analyzed into a list of specifications. Face, which are combined with an existing entry in the font dictionary.

Font (Face) is represented in TOML as follows:

[facename]
attribute = "value"
...

[package.facename]
attribute = "value"

For example, if the font shadow is too difficult to read, you can make it brighter as follows:

[shadow]
foreground = "white"

During initialization, the file config/faces.toml is loaded in the first Julia repository (usually ~/.julia).

Applying fonts to the 'AnnotatedString`

Traditional attributes :face AnnotatedString contains information about fonts (Face), which are currently in use. They can be specified in several forms: as a single character (Symbol) naming fonts (Face) in the global dictionary of fonts, the font itself (Face) or a vector of any of them.

The methods show(::IO, ::MIME"text/plain", ::AnnotatedString) and show(::IO, ::MIME"text/html", ::AnnotatedString) examine attributes`:face` and combine them when defining a common style.

You can specify attributes :face for `AnnotatedString' during construction, add them to the list of properties or use convenient literals of stylized strings.

str1 = AnnotatedString("blue text", [(1:9, :face, :blue)])
str2 = styled"{blue:blue text}"
str1 == str2
sprint(print, str1, context = :color => true)
sprint(show, MIME("text/html"), str1, context = :color => true)

Literals of stylized strings

To simplify the creation AnnotatedString with applied fonts (Face), a literal of stylized strings styled"..." makes it easy to express content and attributes using a custom grammar.

Inside the literal styled"..." curly braces are considered special characters and must be escaped in normal use (\{, \}). This allows them to be used to express annotations with (nested) constructs {annotations...:text}.

The annotations' component... is a comma-separated list of three types of annotations.

  • Font Names

  • Expressions +(key=val,…​)+`Embedded `Face

  • key=value pairs

Interpolation is possible everywhere except for embedded font keys.

For more information about the grammar, see the extended help for docstring. styled"...".

As an example, you can demonstrate the list of embedded fonts mentioned above as follows:

julia> println(styled"
The basic font-style attributes are {bold:bold}, {light:light}, {italic:italic},
{underline:underline}, and {strikethrough:strikethrough}.

In terms of color, we have named faces for the 16 standard terminal colors:
 {black:■} {red:■} {green:■} {yellow:■} {blue:■} {magenta:■} {cyan:■} {white:■}
 {bright_black:■} {bright_red:■} {bright_green:■} {bright_yellow:■} {bright_blue:■} {bright_magenta:■} {bright_cyan:■} {bright_white:■}

Since {code:bright_black} is effectively grey, we define two aliases for it:
{code:grey} and {code:gray} to allow for regional spelling differences.

To flip the foreground and background colors of some text, you can use the
{code:inverse} face, for example: {magenta:some {inverse:inverse} text}.

The intent-based basic faces are {shadow:shadow} (for dim but visible text),
{region:region} for selections, {emphasis:emphasis}, and {highlight:highlight}.
As above, {code:code} is used for code-like text.

Lastly, we have the 'message severity' faces: {error:error}, {warning:warning},
{success:success}, {info:info}, {note:note}, and {tip:tip}.

Remember that all these faces (and any user or package-defined ones) can
arbitrarily nest and overlap, {region,tip:like {bold,italic:so}}.")
Documenter doesn't properly represent all the styling above, so I've converted it manually to HTML and LaTeX.
<pre>
 The basic font-style attributes are <span style="font-weight: 700;">bold, <span style="font-weight: 300;">light, <span style="font-style: italic;">italic,
 <span style="text-decoration: underline;">underline, and <span style="text-decoration: line-through">strikethrough.

 In terms of color, we have named faces for the 16 standard terminal colors:
  <span style="color: #1c1a23;">■ <span style="color: #a51c2c;">■ <span style="color: #25a268;">■ <span style="color: #e5a509;">■ <span style="color: #195eb3;">■ <span style="color: #803d9b;">■ <span style="color: #0097a7;">■ <span style="color: #dddcd9;">■
  <span style="color: #76757a;">■ <span style="color: #ed333b;">■ <span style="color: #33d079;">■ <span style="color: #f6d22c;">■ <span style="color: #3583e4;">■ <span style="color: #bf60ca;">■ <span style="color: #26c6da;">■ <span style="color: #f6f5f4;">■

 Since <span style="color: #0097a7;">bright_black является фактически серым, мы определяем для него два псевдонима:
 <span style="color: #0097a7;">grey и <span style="color: #0097a7;">grey для учета различий в написании.

 To flip the foreground and background colors of some text, you can use the
 <span style="color: #0097a7;">inverse, например: <span style="color: #803d9b;">какой-то <span style="background-color: #803d9b;">обратный<span style="color: #803d9b;"> текст.

 The intent-based basic faces are <span style="color: #76757a;">shadow (для неяркого, но видимого текста),
 <span style="background-color: #3a3a3a;">region для выделений, <span style="color: #195eb3;">emphasis и <span style="background-color: #195eb3;">highlight.
 As above, <span style="color: #0097a7;">code используется для текста, похожего на код.

 Lastly, we have the 'message severity' faces: <span style="color: #ed333b;">error, <span style="color: #e5a509;">warning,
 <span style="color: #25a268;">success, <span style="color: #26c6da;">info, <span style="color: #76757a;">note и <span style="color: #33d079;">tip.

 Remember that all these faces (and any user or package-defined ones) can
 arbitrarily nest and overlap, <span style="color: #33d079;background-color: #3a3a3a;">таким <span style="font-weight: 700;font-style: italic;">образом.</pre>
\begingroup
\ttfamily
\setlength{\parindent}{0pt}
\setlength{\parskip}{\baselineskip}

The basic font-style attributes are {\fontseries{b}\selectfont bold}, {\fontseries{l}\selectfont light}, {\fontshape{it}\selectfont italic},\\
\underline{underline}, and {strikethrough}.

In terms of color, we have named faces for the 16 standard terminal colors:\\
{\color[HTML]{1c1a23}\(\blacksquare\)} {\color[HTML]{a51c2c}\(\blacksquare\)} {\color[HTML]{25a268}\(\blacksquare\)}
{\color[HTML]{e5a509}\(\blacksquare\)} {\color[HTML]{195eb3}\(\blacksquare\)} {\color[HTML]{803d9b}\(\blacksquare\)}
{\color[HTML]{0097a7}\(\blacksquare\)} {\color[HTML]{dddcd9}\(\blacksquare\)} \\
{\color[HTML]{76757a}\(\blacksquare\)} {\color[HTML]{ed333b}\(\blacksquare\)} {\color[HTML]{33d079}\(\blacksquare\)} {\color[HTML]{f6d22c}\(\blacksquare\)} {\color[HTML]{3583e4}\(\blacksquare\)} {\color[HTML]{bf60ca}\(\blacksquare\)} {\color[HTML]{26c6da}\(\blacksquare\)} {\color[HTML]{f6f5f4}\(\blacksquare\)}

Since {\color[HTML]{0097a7}bright\_black} is effectively grey, we define two aliases for it:\\
{\color[HTML]{0097a7}grey} and {\color[HTML]{0097a7}gray} to allow for regional spelling differences.

To flip the foreground and background colors of some text, you can use the\\
{\color[HTML]{0097a7}inverse} face, for example: {\color[HTML]{803d9b}some \colorbox[HTML]{803d9b}{\color[HTML]{000000}inverse} text}.

The intent-based basic faces are {\color[HTML]{76757a}shadow} (for dim but visible text),\\
\colorbox[HTML]{3a3a3a}{region} for selections, {\color[HTML]{195eb3}emphasis}, and \colorbox[HTML]{195eb3}{highlight}.\\
As above, {\color[HTML]{0097a7}code} is used for code-like text.

Lastly, we have the 'message severity' faces: {\color[HTML]{ed333b}error}, {\color[HTML]{e5a509}warning},\\
{\color[HTML]{25a268}success}, {\color[HTML]{26c6da}info}, {\color[HTML]{76757a}note}, and {\color[HTML]{33d079}tip}.

Remember that all these faces (and any user or package-defined ones) can\\
arbitrarily nest and overlap, \colorbox[HTML]{3a3a3a}{\color[HTML]{33d079}like
  {\fontseries{b}\fontshape{it}\selectfont so}}.
\endgroup

API Help

Styles and fonts

@styled_str -> AnnotatedString

Creates a stylized string. Inside the structure string {<specs>:<content>} apply formatting to <content> according to a comma-separated list of specifications <specs>'. Each specification can take the form of a font name, an embedded font specification, or a pair of `key=value'. If the value contains the characters `,=:{}, оно должно быть заключено в {...}.

String interpolation using $ works the same way as regular strings, except that quotation marks need to be escaped. Fonts, keys, and values can also be interpolated using $.

Example

styled"The {bold:{italic:quick} {(foreground=#cd853f):brown} fox} jumped over the {link={https://en.wikipedia.org/wiki/Laziness}:lazy} dog"

Advanced Help

This macro can be described by the following EBNF grammar:

styledstring = { styled | interpolated | escaped | plain } ;

specialchar = '{' | '}' | '$' | '\"' ;
anychar = [\u0-\u1fffff] ;
plain = { anychar - specialchar } ;
escaped = '\\', specialchar ;

interpolated = '$', ? expr ? | '$(', ? expr ?, ')' ;

styled = '{', ws, annotations, ':', content, '}' ;
content = { interpolated | plain | escaped | styled } ;
annotations = annotation | annotations, ws, ',', ws, annotation ;
annotation = face | inlineface | keyvalue ;
ws = { ' ' | '\t' | '\n' } ; (* whitespace *)

face = facename | interpolated ;
facename = [A-Za-z0-9_]+ ;

inlineface = '(', ws, [ faceprop ], { ws, ',', faceprop }, ws, ')' ;
faceprop = [a-z]+, ws, '=', ws, ( [^,)]+ | interpolated) ;

keyvalue = key, ws, '=', ws, value ;
key = ( [^\0${}=,:], [^\0=,:]* ) | interpolated ;
value = simplevalue | curlybraced | interpolated ;
curlybraced = '{' { escaped | plain } '}' ;
simplevalue = [^${},:], [^,:]* ;

An additional condition not specified in the grammar above is that plain must be valid input data for unescape_string, while the specialchar is saved.

The grammar above for inlineface is simplified, the actual implementation is a bit more complicated. The full description of the behavior is given below.

faceprop = ( 'face', ws, '=', ws, ( ? string ? | interpolated ) ) |
           ( 'height', ws, '=', ws, ( ? number ? | interpolated ) ) |
           ( 'weight', ws, '=', ws, ( symbol | interpolated ) ) |
           ( 'slant', ws, '=', ws, ( symbol | interpolated ) ) |
           ( ( 'foreground' | 'fg' | 'background' | 'bg' ),
               ws, '=', ws, ( simplecolor | interpolated ) ) |
           ( 'underline', ws, '=', ws, ( underline | interpolated ) ) |
           ( 'strikethrough', ws, '=', ws, ( bool | interpolated ) ) |
           ( 'inverse', ws, '=', ws, ( bool | interpolated ) ) |
           ( 'inherit', ws, '=', ws, ( inherit | interpolated ) ) ;

nothing = 'nothing' ;
bool = 'true' | 'false' ;
symbol = [^ ,)]+ ;
hexcolor = ('#' | '0x'), [0-9a-f]{6} ;
simplecolor = hexcolor | symbol | nothing ;

underline = nothing | bool | simplecolor | underlinestyled;
underlinestyled = '(', ws, ('' | nothing | simplecolor | interpolated), ws,
                  ',', ws, ( symbol | interpolated ), ws ')' ;

inherit = ( '[', inheritval, { ',', inheritval }, ']' ) | inheritval;
inheritval = ws, ':'?, symbol ;
styled(content::AbstractString) -> AnnotatedString

Creates a stylized string. Inside the structure string {<specs>:<content>} apply formatting to <content> according to a comma-separated list of specifications <specs>'. Each specification can take the form of a font name, an embedded font specification, or a pair of `key=value'. If the value contains the characters `,=:{}, оно должно быть заключено в {...}.

This is the functional equivalent of a macro. @styled_str, only without the possibility of interpolation.

Face is a collection of graphic attributes for displaying text. Fonts control how text is displayed in the terminal, and possibly in other places as well.

Most of the time Face will be stored in global font dictionaries as a unique link to the font_name symbol, and most often it will be accessed by that name rather than the object itself. Face.

Attributes

All attributes can be set using the named argument constructor; by default, they are set to `nothing'.

  • height (Int or Float64): height either in decimal points (Int) or as a multiplier of the base size (Float64).

  • weight (Symbol): one of the symbols (from the faintest to the most saturated) :thin, :extralight, :light, :semilight, :normal, :medium, :semibold, :bold, :extrabold or :black. In terminals with any saturation greater than :normal, the text is displayed in bold, and in terminals that support text of variable brightness, with any saturation less than :normal, the text is displayed in dim font.

  • slant (Symbol): one of the characters :italic, :oblique or `:normal'.

  • 'foreground' (`SimpleColor'): the foreground color of the text.

  • background (`SimpleColor'): the background color of the text.

  • `underline', underlining text in one of the following forms:

    • Bool: whether the text should be underlined.

    • SimpleColor: the text should be underlined in this color.

    • Tuple{Nothing, Symbol}: the text must be underlined using the style specified by the character :straight, :double, :curly, :dotted or `:dashed'.

    • Tuple{SimpleColor, Symbol}: The text must be underlined in the specified SimpleColor color and using the style specified by the symbol, as before.

  • strikethrough' (`Bool): whether the text should be crossed out.

  • inverse (Bool): Whether the foreground and background colors should be inverted.

  • inherit (Vector{Symbol}): names of fonts from which inheritance should take place, with earlier fonts taking precedence. All fonts are inherited from the font `:default'.

addface!(name::Symbol => default::Face)

Creates a new font named name'. If there are no fonts with that name yet, `default is added to both FACES.default` and (a copy of) FACES.`current', and the current value is returned.

If the font name already exists, nothing is returned.

Examples

julia> addface!(:mypkg_myface => Face(slant=:italic, underline=true))
Face (sample)
         slant: italic
     underline: true
withfaces(f, kv::Pair...)
withfaces(f, kvpair_itr)

Executes f with FACES.current`, temporarily changed to zero or more arguments :name => val kv, or kvpair_itr, which creates values in the form `kv'.

The 'within` function is usually used with the syntax within(kv...) do ... end. Using the nothing value, you can temporarily disable the font (if it has been set). When the 'withfaces` function returns control, the original FACES'.current is restored.

Examples

julia> withfaces(:yellow => Face(foreground=:red), :green => :blue) do
           println(styled"{yellow:red} and {green:blue} mixed make {magenta:purple}")
       end
red and blue mixed make purple
struct SimpleColor

A basic color representation designed for string styling. It can contain either a named color (for example, :red), or an object RGBTuple, which is a tuple of NamedTuple defining the color r, g, b with a depth of 8 bits.

Constructors

SimpleColor(name::Symbol)  # например, :red
SimpleColor(rgb::RGBTuple) # например, (r=1, b=2, g=3)
SimpleColor(r::Integer, b::Integer, b::Integer)
SimpleColor(rgb::UInt32)   # например, 0x123456

See also the description of tryparse(SimpleColor, rgb::String).

parse(::Type{SimpleColor}, rgb::String)

An analog of tryparse(SimpleColor, rgb::String), which returns an error instead of returning nothing.

tryparse(::Type{SimpleColor}, rgb::String)

Tries to analyze rgb as SimpleColor'. If the `rgb value starts with # and has a length of 7, it is converted to SimpleColor based on RGBTuple'. If the value of `rgb starts with a--z, rgb is interpreted as the name of the color and converted to SimpleColor based on the `Symbol'.

Otherwise, `nothing' is returned.

Examples

julia> tryparse(SimpleColor, "blue")
SimpleColor(blue)

julia> tryparse(SimpleColor, "#9558b2")
SimpleColor(#9558b2)

julia> tryparse(SimpleColor, "#nocolor")
merge(initial::Face, others::Face...)

Combines the properties of the font initial and others, with the latter taking precedence.