StyledStrings
API для StyledStrings и AnnotatedStrings считается экспериментальным и может изменяться между версиями Julia.
Styling
При работе со строками форматирование и стилизация часто выступают в качестве второстепенной задачи.
Например, при печати в терминал вы можете захотеть добавить ANSI escape sequences в вывод, когда выводите конструкции HTML-стилизации (<span style="...">
и т. д.), которые служат аналогичной цели, и так далее. Возможно просто вставить сырые конструкции стилизации в строку рядом с самим содержимым, но быстро становится очевидным, что это не очень подходит для чего-либо, кроме самых базовых случаев использования. Не все терминалы поддерживают одни и те же коды ANSI, конструкции стилизации необходимо тщательно удалять при расчете ширины уже стилизованного контента, и это еще до того, как вы даже начнете обрабатывать несколько форматов вывода.
Вместо того чтобы оставлять эту головную боль для широкого опыта downstream, она решается напрямую с помощью введения специального типа строки (AnnotatedString
). Этот тип строки оборачивает любой другой тип AbstractString
и позволяет применять информацию о форматировании к регионам (например, символы с 1 по 7 выделены жирным шрифтом и красным цветом).
Регионы строки оформляются применением Face
(думайте о "шрифте") к ним — структура, которая содержит информацию о стиле. В качестве удобства, шрифты в глобальном словаре шрифтов (например, shadow
) могут просто называться вместо того, чтобы указывать 4d61726b646f776e2e436f64652822222c2022466163652229_40726566205374796c6564537472696e67732e46616365
напрямую.
Вместе с этими возможностями мы также предоставляем удобный способ для построения AnnotatedString
, подробно описанный в Styled String Literals.
julia> using StyledStrings
julia> styled"{yellow:hello} {blue:there}"
"hello there"
Annotated Strings
Иногда полезно иметь возможность хранить метаданные, относящиеся к регионам строки. AnnotatedString
оборачивает другую строку и позволяет аннотировать ее регионы с помощью помеченных значений (:label => value
). Все общие операции со строками применяются к основной строке. Однако, когда это возможно, информация о стиле сохраняется. Это означает, что вы можете манипулировать 4d61726b646f776e2e436f64652822222c2022416e6e6f7461746564537472696e672229_4072656620426173652e416e6e6f7461746564537472696e67
— брать подстроки, добавлять к ним отступы, конкатенировать их с другими строками — и аннотации метаданных "поедут с вами".
Этот тип строки является фундаментальным для StyledStrings stdlib, который использует аннотации с меткой :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) # *-concatenation works
true
Аннотации AnnotatedString
могут быть доступны и изменены через функции annotations
и annotate!
.
Styling via AnnotatedString
s
Faces
The Face
type
Face
задает детали шрифта, в котором может быть установлен текст. Он охватывает набор основных атрибутов, которые хорошо обобщаются на различных форматах, а именно:
шрифт
высота
вес
скос
foreground
фон
подчеркнуть
зачеркнутый
обратный
наследовать
Для получения подробной информации о конкретных формах, которые принимают эти атрибуты, смотрите Face
docstring, но особый интерес представляет inherit
, так как он позволяет вам наследовать атрибуты от других 4d61726b646f776e2e436f64652822222c2022466163652229_40726566205374796c6564537472696e67732e46616365
.
The global faces dictionary
Чтобы сделать ссылку на определенные стили более удобной, существует глобальный Dict{Symbol, Face}
, который позволяет ссылаться на Face
просто по имени. Пакеты могут добавлять шрифты в этот словарь с помощью функции addface!
, а загруженные шрифты можно легко customized.
Любой пакет, регистрирующий новые лица, должен убедиться, что они начинаются с имени пакета, т.е. следовать формату mypackage_myface
. Это важно для предсказуемости и предотвращения конфликтов имен.
Кроме того, пакеты должны заботиться о том, чтобы использовать (и вводить) семантические лица (например, code
) вместо прямых цветов и стилей (например, cyan
). Это полезно во многих отношениях: от того, что делает намерение в использовании более очевидным, до помощи в композируемости и упрощения пользовательской настройки.
Существует два набора исключений из правила префикса пакета:
- набор основных лиц, которые являются частью значения по умолчанию словаря лиц
- лица, введенные стандартной библиотекой Julia, а именно
JuliaSyntaxHighlighting
Basic faces
Основные лица предназначены для представления общей идеи, которая широко применима.
Для установки некоторого текста с определенным атрибутом у нас есть шрифты 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
.
Customisation of faces (Faces.toml
)
Хорошо, что имена лиц в глобальном словаре лиц можно настраивать. Тематика и эстетика важны, и это также важно по причинам доступности. Файл TOML можно разобрать на список спецификаций Face
, которые объединяются с уже существующей записью в словаре лиц.
Face
представлен в TOML следующим образом:
[facename]
attribute = "value"
...
[package.facename]
attribute = "value"
Например, если лицо shadow
слишком трудно читать, его можно сделать ярче вот так:
[shadow]
foreground = "white"
При инициализации загружается файл config/faces.toml
, находящийся в первом хранилище Julia (обычно ~/.julia
).
Applying faces to a AnnotatedString
По соглашению, атрибуты :face
AnnotatedString
содержат информацию о Face
, которые в настоящее время применяются. Это может быть представлено в нескольких формах: в виде одного Symbol
, указывающего на 4d61726b646f776e2e436f64652822222c2022466163652229_40726566205374796c6564537472696e67732e46616365
в глобальном словаре лиц, самого 4d61726b646f776e2e436f64652822222c2022466163652229_40726566205374796c6564537472696e67732e46616365
или вектором любого из них.
Методы show(::IO, ::MIME"text/plain", ::AnnotatedString)
и show(::IO, ::MIME"text/html", ::AnnotatedString)
оба рассматривают атрибуты :face
и объединяют их все вместе при определении общего стиля.
Мы можем предоставить :face
атрибуты для AnnotatedString
во время создания, добавить их в список свойств позже или использовать удобный Styled String literals.
julia> str1 = AnnotatedString("blue text", [(1:9, :face, :blue)])
"blue text"
julia> str2 = styled"{blue:blue text}"
"blue text"
julia> str1 == str2
true
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
Чтобы упростить создание AnnotatedString
с применением Face
, строковый литерал в стиле styled"..."
позволяет легко выражать содержимое и атрибуты вместе с помощью пользовательской грамматики.
Внутри литерала styled"..."
фигурные скобки считаются специальными символами и должны быть экранированы в обычном использовании (\{
, \}
). Это позволяет использовать их для выражения аннотаций с помощью (вложенных) конструкций {annotations...:text}
.
Компонент annotations...
представляет собой список из трех типов аннотаций, разделенный запятыми.
- Имена лиц
- Встроенные
Face
выражения(key=val,...)
key=value
пары
Интерполяция возможна везде, кроме ключей лиц в строке.
Для получения дополнительной информации о грамматике смотрите расширенную справку документации 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}}.")
The basic font-style attributes are bold, light, italic, underline, and strikethrough. In terms of color, we have named faces for the 16 standard terminal colors: ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ Since bright_black is effectively grey, we define two aliases for it: grey and gray to allow for regional spelling differences. To flip the foreground and background colors of some text, you can use the inverse face, for example: some inverse text. The intent-based basic faces are shadow (for dim but visible text), region for selections, emphasis, and highlight. As above, code is used for code-like text. Lastly, we have the 'message severity' faces: error, warning, success, info, note, and tip. Remember that all these faces (and any user or package-defined ones) can arbitrarily nest and overlap, like so.
API reference
Styling and Faces
StyledStrings.StyledMarkup.@styled_str
— Macro@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' } ; (* пробелы *)
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 ;
StyledStrings.StyledMarkup.styled
— Functionstyled(content::AbstractString) -> AnnotatedString
Создает стилизованную строку. Внутри строки структуры {<specs>:<content>}
применяют форматирование к <content>
, в соответствии со списком спецификаций <specs>
, разделенных запятыми. Каждая спецификация может принимать форму имени шрифта, спецификации встроенного шрифта или пары key=value
. Значение должно быть заключено в {...}
, если оно содержит любые из символов ,=:{}
.
Это функциональный эквивалент макроса @styled_str
, просто без возможностей интерполяции.
StyledStrings.Face
— TypeЛицо
— это коллекция графических атрибутов для отображения текста. Лица контролируют, как текст отображается в терминале и, возможно, в других местах.
Чаще всего Лицо
будет храниться в глобальных словарях лиц как уникальная ассоциация с символом имя лица, и чаще всего будет упоминаться по этому имени, а не по самому объекту Лицо
.
Атрибуты
Все атрибуты могут быть установлены через конструктор ключевых слов и по умолчанию равны 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
.
StyledStrings.addface!
— Functionaddface!(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
StyledStrings.withfaces
— Functionwithfaces(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
StyledStrings.SimpleColor
— Typestruct 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)
.
Base.parse
— Methodparse(::Type{SimpleColor}, rgb::String)
Аналог функции tryparse(SimpleColor, rgb::String)
(см. там), которая вызывает ошибку вместо возврата nothing
.
Base.tryparse
— Methodtryparse(::Type{SimpleColor}, rgb::String)
Попытка разобрать rgb
как SimpleColor
. Если rgb
начинается с #
и имеет длину 7, он преобразуется в RGBTuple
-поддерживаемый SimpleColor
. Если rgb
начинается с a
-z
, rgb
интерпретируется как имя цвета и преобразуется в Symbol
-поддерживаемый SimpleColor
.
В противном случае возвращается nothing
.
Примеры
julia> tryparse(SimpleColor, "blue")
SimpleColor(blue)
julia> tryparse(SimpleColor, "#9558b2")
SimpleColor(#9558b2)
julia> tryparse(SimpleColor, "#nocolor")
Base.merge
— Methodmerge(initial::Face, others::Face...)
Объединяет свойства начального лица initial
и других, при этом более поздние лица имеют приоритет.