Документация Engee

StyledStrings

Страница в процессе перевода.

CurrentModule = StyledStrings
DocTestSetup = quote
    using StyledStrings
end

API для StyledStrings и AnnotatedStrings считается экспериментальным и может быть изменен в разных версиях Julia.

Применение стиля

При работе со строками форматирование и применение стиля часто оказываются на втором плане.

Например, при выводе на терминал может потребоваться добавить escape-последовательности ANSI в выходные данные, когда выводимые конструкции в HTML-стиле (<span style="..."> и т. д.) служат аналогичной цели, и так далее. Можно просто вставить необработанные конструкции стилей в строку рядом с самим содержимым, но быстро становится ясно, что такой вариант подходит только для самых простых случаев использования. Не все терминалы поддерживают одинаковые коды ANSI, конструкции стиля нужно кропотливо удалять при расчете ширины уже стилизованного содержимого, и это еще не говоря о работе с несколькими форматами вывода.

Эту задачу можно решить благодаря внедрению специального строкового типа (AnnotatedString). Этот строковый тип заключает в оболочку любой другой тип AbstractString и позволяет применять к областям информацию о форматировании (например, символы с 1 по 7 выделяются жирным шрифтом и красным цветом).

Области строки стилизуются путем применения к ним шрифтов (Face) — структуры, которая содержит информацию о стиле. Для удобства шрифтам в глобальном словаре шрифтов (например, shadow) можно просто присвоить имена вместо того, чтобы передавать шрифт (Face) напрямую.

Наряду с этими возможностями мы также предоставляем удобный способ построения AnnotatedString, подробно описанный в разделе Литералы стилизованных строк.

julia> using StyledStrings


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

Аннотированные строки

Иногда полезно иметь возможность хранить метаданные, относящиеся к областям строки. AnnotatedString заключает в оболочку другую строку и позволяет аннотировать ее области маркированными значениями (:label => value). Все универсальные операции со строками применяются к базовой строке. Однако, когда это возможно, сохраняется информация о стиле. Это означает, что вы можете работать с AnnotatedString — брать подстроки, дополнять их, объединять с другими строками — и аннотации метаданных будут присоединены.

Этот строковый тип является основным для [StyledStrings stdlib] (StyledStrings.md#stdlib-styledstrings), где используются аннотации, помеченные :face, для хранения информации о стиле.

При конкатенации AnnotatedString старайтесь использовать annotatedstring вместо string, если хотите сохранить строковые аннотации.

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

Доступ к аннотациям AnnotatedString и их изменение осуществляются с помощью функций annotations и annotate!.

Стилизация с помощью AnnotatedString

Шрифты

Тип Face

Face определяет детали шрифта, которым может быть набран текст. Он охватывает набор основных атрибутов, которые хорошо подходят для различных форматов, а именно:

  • font

  • height

  • weight

  • slant

  • foreground

  • background

  • underline

  • strikethrough

  • inverse

  • inherit

Подробнее о том, какие формы принимают эти атрибуты, см. в описании docstring Face, но особый интерес представляет inherit, поскольку он позволяет наследовать атрибуты от других шрифтов (Face).

Глобальный словарь шрифтов

Для удобства ссылок на определенные стили существует глобальный словарь Dict{Symbol, Face}, который позволяет ссылаться на шрифты (Face) просто по имени. Пакеты могут добавлять шрифты в этот словарь с помощью функции addface!, а загруженные шрифты можно легко настраивать.

!!! warning "Appropriate face naming" Любой пакет, регистрирующий новые шрифты, должен гарантировать у них наличие префикса в виде имени пакета, т. е. соблюдение формата mypackage_myface. Это важно для предсказуемости и предотвращения конфликтов имен.

Кроме того, пакеты должны использовать (и вводить) *семантические* шрифты (например, `code`), а не прямые цвета и стили (например, `cyan`). Это полезно по целому ряду причин, от более очевидного намерения в использовании, до композиционности и более интуитивной настройки пользователем.

Существует два исключения из правила префиксов пакетов:

  • набор основных шрифтов, которые являются частью значения по умолчанию словаря шрифтов;

  • шрифты, представленные собственной стандартной библиотекой Julia, а именно JuliaSyntaxHighlighting.

Основные шрифты

Основные шрифты предназначены для представления широко применимой общей идеи.

Для задания текста с определенным атрибутом существуют следующие шрифты: bold, light, italic, underline, strikethrough и inverse.

Для 16 цветов терминала также предусмотрены именованные шрифты: black, red, green, yellow, blue, magenta, cyan, white, bright_black/grey/gray, bright_red, bright_green, bright_blue, bright_magenta, bright_cyan и bright_white.

Для затененного текста (т. е. неяркого, но присутствующего) используется шрифт shadow. Для обозначения выбранной области существует шрифт region. Для обозначения значимости и выделения определены шрифты emphasis и highlight. Есть также code для текста, похожего на код.

Для визуального указания серьезности сообщений определены такие шрифты, как error, warning, success, info, note и tip.

Настройка шрифтов (Faces.toml)

Желательно, чтобы именованные шрифты в глобальном словаре шрифтов были настраиваемыми. Оформление и эстетика — это прекрасное дополнение, которое также имеет значение и с точки зрения специальных возможностей. TOML-файл может быть проанализирован в список спецификаций Face, которые объединяются с уже существующей записью в словаре шрифтов.

Шрифт (Face) представлен в TOML следующим образом:

[facename]
attribute = "value"
...

[package.facename]
attribute = "value"

Например, если шрифт shadow слишком труден для чтения, его можно сделать ярче следующим образом:

[shadow]
foreground = "white"

При инициализации загружается файл config/faces.toml в первом хранилище Julia (обычно ~/.julia).

Применение шрифтов к AnnotatedString

Традиционно атрибуты :face AnnotatedString содержат информацию о шрифтах (Face), которые применяются в данный момент. Их можно задать в нескольких формах: в виде одного символа (Symbol), называющего шрифты (Face) в глобальном словаре шрифтов, самого шрифта (Face) или вектора любого из них.

Методы show(::IO, ::MIME"text/plain", ::AnnotatedString) и show(::IO, ::MIME"text/html", ::AnnotatedString) изучают атрибуты :face и объединяют их при определении общего стиля.

Можно указывать атрибуты :face для AnnotatedString во время конструирования, добавлять их в список свойств или использовать удобные литералы стилизованных строк.

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)

Литералы стилизованных строк

Чтобы упростить создание AnnotatedString с примененными шрифтами (Face), литерал стилизованных строк styled"..." позволяет легко выражать содержимое и атрибуты с помощью пользовательской грамматики.

Внутри литерала styled"..." фигурные скобки считаются специальными символами и должны экранироваться при обычном использовании (\{, \}). Это позволяет использовать их для выражения аннотаций с (вложенными) конструкциями {annotations...:text}.

Компонент annotations... представляет собой список из трех типов аннотаций, разделенных запятыми.

  • Имена шрифтов

  • Выражения (key=val,...) встроенных Face

  • Пары key=value

Интерполяция возможна везде, кроме ключей встроенных шрифтов.

Дополнительные сведения о грамматике см. в расширенной справке к docstring styled"...".

В качестве примера можно продемонстрировать список встроенных шрифтов, упомянутый выше, следующим образом:

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>, <span style="font-weight: 300;">light</span>, <span style="font-style: italic;">italic</span>,
 <span style="text-decoration: underline;">underline</span>, and <span style="text-decoration: line-through">strikethrough</span>.

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

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

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

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

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

 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;">образом</span></span>.</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

Стили и шрифты

@styled_str -> AnnotatedString

Создает стилизованную строку. Внутри строки структуры {<specs>:<content>} применяют форматирование к <content> в соответствии со списком разделенных запятыми спецификаций <specs>. Каждая спецификация может иметь форму названия шрифта, встроенной спецификации шрифта или пары key=value. Если в значении есть символы ,=:{}, оно должно быть заключено в {...}.

Интерполяция строк с помощью $ работает так же, как и обычные строки, за исключением того, что кавычки необходимо экранировать. Шрифты, ключи и значения также можно интерполировать с помощью $.

Пример

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

Расширенная справка

Этот макрос можно описать следующей грамматикой EBNF:

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 = [^${},:], [^,:]* ;

Дополнительное условие, не оговоренное в приведенной выше грамматике, заключается в том, что plain должно быть допустимыми входными данными для unescape_string, при этом specialchar сохраняется.

Приведенная выше грамматика для inlineface упрощена, фактическая реализация немного сложнее. Полное описание поведения приведено ниже.

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

Создает стилизованную строку. Внутри строки структуры {<specs>:<content>} применяют форматирование к <content> в соответствии со списком разделенных запятыми спецификаций <specs>. Каждая спецификация может иметь форму названия шрифта, встроенной спецификации шрифта или пары key=value. Если в значении есть символы ,=:{}, оно должно быть заключено в {...}.

Это функциональный эквивалент макроса @styled_str, только без возможности интерполяции.

Face — это коллекция графических атрибутов для отображения текста. Шрифты управляют тем, как текст отображается в терминале, а возможно, и в других местах.

Большую часть времени Face будет храниться в глобальных словарях шрифтов как уникальная связь с символом имени шрифта, и чаще всего обращение будет происходить по этому имени, а не к самому объекту Face.

Атрибуты

Все атрибуты можно задать с помощью конструктора именованных аргументов; по умолчанию они равны nothing.

  • height (Int или Float64): высота либо в деципунктах (Int), либо как множитель базового размера (Float64).

  • weight (Symbol): один из символов (от самого тусклого до самого насыщенного) :thin, :extralight, :light, :semilight, :normal, :medium, :semibold, :bold, :extrabold или :black. В терминалах при любой насыщенности больше :normal текст отображается полужирным шрифтом, а в терминалах, поддерживающих текст переменной яркости, при любой насыщенности меньше :normal текст отображается тусклым шрифтом.

  • slant (Symbol): один из символов :italic, :oblique или :normal.

  • foreground (SimpleColor): цвет переднего плана текста.

  • background (SimpleColor): цвет фона текста.

  • underline, подчеркивание текста в одной из следующих форм:

    • Bool: должен ли текст подчеркиваться.

    • SimpleColor: текст должен подчеркиваться этим цветом.

    • Tuple{Nothing, Symbol}: текст должен подчеркиваться с использованием стиля, заданного символом :straight, :double, :curly, :dotted или :dashed.

    • Tuple{SimpleColor, Symbol}: текст должен подчеркиваться указанным цветом SimpleColor и с использованием стиля, заданного символом, как и ранее.

  • strikethrough (Bool): должен ли текст зачеркиваться.

  • inverse (Bool): должны ли инвертироваться цвета переднего плана и фона.

  • inherit (Vector{Symbol}): имена шрифтов, от которых должно происходить наследование, причем приоритет имеют более ранние шрифты. Все шрифты наследуются от шрифта :default.

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

Создает новый шрифт с именем name. Если шрифтов с таким именем еще нет, default добавляется как к FACES`.default`, так и к (копии) FACES.current, при этом возвращается текущее значение.

Если шрифт name уже существует, возвращается nothing.

Примеры

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

Выполняет f с FACES`.current`, временно измененным нулем или более аргументов :name => val kv, или kvpair_itr, который создает значения в форме kv.

Функция withfaces обычно применяется с синтаксисом withfaces(kv...) do ... end. С помощью значения nothing можно временно отключить шрифт (если он был задан). Когда функция withfaces возвращает управление, восстанавливается исходный FACES`.current`.

Примеры

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

Базовое представление цвета, предназначенное для стилизации строк. Может содержать либо именованный цвет (например, :red), либо объект RGBTuple, представляющий собой кортеж NamedTuple, определяющий цвет r, g, b с глубиной 8 бит.

Конструкторы

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

См. также описание tryparse(SimpleColor, rgb::String).

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

Аналог tryparse(SimpleColor, rgb::String), который выдает ошибку вместо возврата nothing.

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

Пытается проанализировать rgb как SimpleColor. Если значение rgb начинается с # и имеет длину 7, оно преобразуется в SimpleColor на основе RGBTuple. Если значение rgb начинается с a--z, rgb интерпретируется как название цвета и преобразуется в SimpleColor на основе Symbol.

В противном случае возвращается nothing.

Примеры

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

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

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

Объединяет свойства шрифта initial и others, причем последние имеют приоритет.