Movatterモバイル変換


[0]ホーム

URL:


GitHub

StyledStrings

Note

The API for StyledStrings and AnnotatedStrings is considered experimental and is subject to change between Julia versions.

Styling

When working with strings, formatting and styling often appear as a secondary concern.

For instance, when printing to a terminal you might want to sprinkleANSI escape sequences in the output, when outputting HTML styling constructs (<span style="...">, etc.) serve a similar purpose, and so on. It is possible to simply insert the raw styling constructs into the string next to the content itself, but it quickly becomes apparent that this is not well suited for anything but the most basic use cases. Not all terminals support the same ANSI codes, the styling constructs need to be painstakingly removed when calculating the width of already-styled content, and that's before you even get into handling multiple output formats.

Instead of leaving this headache to be widely experienced downstream, it is tackled head-on by the introduction of a special string type (AnnotatedString). This string type wraps any otherAbstractString type and allows for formatting information to be applied to regions (e.g. characters 1 through to 7 are bold and red).

Regions of a string are styled by applyingFaces (think "typeface") to them — a structure that holds styling information. As a convenience, faces in the global faces dictionary (e.g.shadow) can just be named instead of giving theFace directly.

Along with these capabilities, we also provide a convenient way for constructingAnnotatedStrings, detailed inStyled String Literals.

julia> using StyledStrings
julia> styled"{yellow:hello} {blue:there}""hellothere"

Annotated Strings

It is sometimes useful to be able to hold metadata relating to regions of a string. AAnnotatedString wraps another string and allows for regions of it to be annotated with labelled values (:label => value). All generic string operations are applied to the underlying string. However, when possible, styling information is preserved. This means you can manipulate aAnnotatedString —taking substrings, padding them, concatenating them with other strings— and the metadata annotations will "come along for the ride".

This string type is fundamental to theStyledStrings stdlib, which uses:face-labelled annotations to hold styling information.

When concatenating aAnnotatedString, take care to useannotatedstring instead ofstring if you want to keep the string annotations.

julia> str = AnnotatedString("hello there", [(1:5, :word, :greeting), (7:11, :label, 1)])"hello there"julia> length(str)11julia> 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) # *-concatenation workstrue

The annotations of aAnnotatedString can be accessed and modified via theannotations andannotate! functions.

Styling viaAnnotatedStrings

Faces

TheFace type

AFace specifies details of a typeface that text can be set in. It covers a set of basic attributes that generalize well across different formats, namely:

For details on the particular forms these attributes take, see theFace docstring, but of particular interest isinherit as it allows you toinherit attributes from otherFaces.

The global faces dictionary

To make referring to particular styles more convenient, there is a globalDict{Symbol, Face} that allows forFaces to be referred to simply by name. Packages can add faces to this dictionary via theaddface! function, and the loaded faces can be easilycustomized.

Appropriate face naming

Any package registering new faces should ensure that they are prefixed by the package name, i.e. follow the formatmypackage_myface. This is important for predictability, and to prevent name clashes.

Furthermore, packages should take care to use (and introduce)semantic faces (likecode) over direct colours and styles (likecyan). This is helpful in a number of ways, from making the intent in usage more obvious, aiding composability, and making user customisation more intuitive.

There are two set of exemptions to the package-prefix rule:

Basic faces

Basic faces are intended to represent a general idea that is widely applicable.

For setting some text with a certain attribute, we have thebold,light,italic,underline,strikethrough, andinverse faces.

There are also named faces 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, andbright_white.

For shadowed text (i.e. dim but there) there is theshadow face. To indicate a selected region, there is theregion face. Similarly for emphasis and highlighting theemphasis andhighlight faces are defined. There is alsocode for code-like text.

For visually indicating the severity of messages, theerror,warning,success,info,note, andtip faces are defined.

Customisation of faces (Faces.toml)

It is good for the name faces in the global face dictionary to be customizable. Theming and aesthetics are nice, and it is important for accessibility reasons too. A TOML file can be parsed into a list ofFace specifications that are merged with the pre-existing entry in the face dictionary.

AFace is represented in TOML like so:

[facename]attribute = "value"...[package.facename]attribute = "value"

For example, if theshadow face is too hard to read it can be made brighter like so:

[shadow]foreground = "white"

On initialization, theconfig/faces.toml file under the first Julia depot (usually~/.julia) is loaded.

Applying faces to aAnnotatedString

By convention, the:face attributes of aAnnotatedString hold information on theFaces that currently apply. This can be given in multiple forms, as a singleSymbol naming aFaces in the global face dictionary, aFace itself, or a vector of either.

Theshow(::IO, ::MIME"text/plain", ::AnnotatedString) andshow(::IO, ::MIME"text/html", ::AnnotatedString) methods both look at the:face attributes and merge them all together when determining the overall styling.

We can supply:face attributes to aAnnotatedString during construction, add them to the properties list afterwards, or use the convenientStyled String literals.

julia> str1 = AnnotatedString("blue text", [(1:9, :face, :blue)])"blue text"
julia> str2 = styled"{blue:blue text}""blue text"
julia> str1 == str2true
julia> sprint(print, str1, context = :color => true)"\e[34mblue text\e[39m"
julia> sprint(show, MIME("text/html"), str1, context = :color => true)"<span style=\"color: #195eb3\">blue text</span>"

Styled String Literals

To ease construction ofAnnotatedStrings withFaces applied, thestyled"..." styled string literal allows for the content and attributes to be easily expressed together via a custom grammar.

Within astyled"..." literal, curly braces are considered special characters and must be escaped in normal usage (\{,\}). This allows them to be used to express annotations with (nestable){annotations...:text} constructs.

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

Interpolation is possible everywhere except for inline face keys.

For more information on the grammar, see the extended help of thestyled"..." docstring.

As an example, we can demonstrate the list of built-in faces mentioned above like so:

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) canarbitrarily nest and overlap, {region,tip:like {bold,italic:so}}.")
 The basic font-style attributes arebold,light,italic,underline, andstrikethrough. In terms of color, we have named faces for the 16 standard terminal colors: Sincebright_black is effectively grey, we define two aliases for it:grey andgray to allow for regional spelling differences. To flip the foreground and background colors of some text, you can use theinverse face, for example:someinverse text. The intent-based basic faces areshadow (for dim but visible text),region for selections,emphasis, andhighlight. As above,code is used for code-like text. Lastly, we have the 'message severity' faces:error,warning,success,info,note, andtip. Remember that all these faces (and any user or package-defined ones) can arbitrarily nest and overlap,likeso.

API reference

Styling and Faces

StyledStrings.StyledMarkup.@styled_strMacro
@styled_str -> AnnotatedString

Construct a styled string. Within the string,{<specs>:<content>} structures apply the formatting to<content>, according to the list of comma-separated specifications<specs>. Each spec can either take the form of a face name, an inline face specification, or akey=value pair. The value must be wrapped by{...} should it contain any of the characters,=:{}.

String interpolation with$ functions in the same way as regular strings, except quotes need to be escaped. Faces, keys, and values can also be interpolated with$.

Example

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

Extended 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 extra stipulation not encoded in the above grammar is thatplain should be a valid input tounescape_string, withspecialchar kept.

The above grammar forinlineface is simplified, as the actual implementation is a bit more sophisticated. The full behaviour 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 ;
StyledStrings.StyledMarkup.styledFunction
styled(content::AbstractString) -> AnnotatedString

Construct a styled string. Within the string,{<specs>:<content>} structures apply the formatting to<content>, according to the list of comma-separated specifications<specs>. Each spec can either take the form of a face name, an inline face specification, or akey=value pair. The value must be wrapped by{...} should it contain any of the characters,=:{}.

This is a functional equivalent of the@styled_str macro, just without interpolation capabilities.

StyledStrings.FaceType

AFace is a collection of graphical attributes for displaying text. Faces control how text is displayed in the terminal, and possibly other places too.

Most of the time, aFace will be stored in the global faces dicts as a unique association with aface name Symbol, and will be most often referred to by this name instead of theFace object itself.

Attributes

All attributes can be set via the keyword constructor, and default tonothing.

  • height (anInt orFloat64): The height in either deci-pt (when anInt), or as a factor of the base size (when aFloat64).
  • weight (aSymbol): One of the symbols (from faintest to densest):thin,:extralight,:light,:semilight,:normal,:medium,:semibold,:bold,:extrabold, or:black. In terminals any weight greater than:normal is displayed as bold, and in terminals that support variable-brightness text, any weight less than:normal is displayed as faint.
  • slant (aSymbol): One of the symbols:italic,:oblique, or:normal.
  • foreground (aSimpleColor): The text foreground color.
  • background (aSimpleColor): The text background color.
  • underline, the text underline, which takes one of the following forms:
    • aBool: Whether the text should be underlined or not.
    • aSimpleColor: The text should be underlined with this color.
    • aTuple{Nothing, Symbol}: The text should be underlined using the style set by the Symbol, one of:straight,:double,:curly,:dotted, or:dashed.
    • aTuple{SimpleColor, Symbol}: The text should be underlined in the specified SimpleColor, and using the style specified by the Symbol, as before.
  • strikethrough (aBool): Whether the text should be struck through.
  • inverse (aBool): Whether the foreground and background colors should be inverted.
  • inherit (aVector{Symbol}): Names of faces to inherit from, with earlier faces taking priority. All faces inherit from the:default face.
StyledStrings.addface!Function
addface!(name::Symbol => default::Face)

Create a new face by the namename. So long as no face already exists by this name,default is added to bothFACES.default and (a copy of) toFACES.current, with the current value returned.

Should the facename already exist,nothing is returned.

Examples

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

Executef withFACES.current temporarily modified by zero or more:name => val argumentskv, orkvpair_itr which produceskv-form values.

withfaces is generally used via thewithfaces(kv...) do ... end syntax. A value ofnothing can be used to temporarily unset a face (if it has been set). Whenwithfaces returns, the originalFACES.current has been restored.

Examples

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

A basic representation of a color, intended for string styling purposes. It can either contain a named color (like:red), or anRGBTuple which is a NamedTuple specifying anr,g,b color with a bit-depth of 8.

Constructors

SimpleColor(name::Symbol)  # e.g. :redSimpleColor(rgb::RGBTuple) # e.g. (r=1, b=2, g=3)SimpleColor(r::Integer, b::Integer, b::Integer)SimpleColor(rgb::UInt32)   # e.g. 0x123456

Also seetryparse(SimpleColor, rgb::String).

Base.parseMethod
parse(::Type{SimpleColor}, rgb::String)

An analogue oftryparse(SimpleColor, rgb::String) (which see), that raises an error instead of returningnothing.

Base.tryparseMethod
tryparse(::Type{SimpleColor}, rgb::String)

Attempt to parsergb as aSimpleColor. Ifrgb starts with# and has a length of 7, it is converted into aRGBTuple-backedSimpleColor. Ifrgb starts witha-z,rgb is interpreted as a color name and converted to aSymbol-backedSimpleColor.

Otherwise,nothing is returned.

Examples

julia> tryparse(SimpleColor, "blue")SimpleColor(blue)julia> tryparse(SimpleColor, "#9558b2")SimpleColor(#9558b2)julia> tryparse(SimpleColor, "#nocolor")
Base.mergeMethod
merge(initial::Face, others::Face...)

Merge the properties of theinitial face andothers, with later faces taking priority.

Settings


This document was generated withDocumenter.jl version 1.8.0 onWednesday 9 July 2025. Using Julia version 1.11.6.


[8]ページ先頭

©2009-2025 Movatter.jp