StyledStrings
La API para StyledStrings y AnnotatedStrings se considera experimental y está sujeta a cambios entre versiones de Julia.
Styling
Cuando se trabaja con cadenas, el formato y el estilo a menudo aparecen como una preocupación secundaria.
Por ejemplo, al imprimir en un terminal, es posible que desees esparcir ANSI escape sequences en la salida. Al generar construcciones de estilo HTML (<span style="...">
, etc.), se cumple un propósito similar, y así sucesivamente. Es posible simplemente insertar las construcciones de estilo en bruto en la cadena junto al contenido mismo, pero rápidamente se hace evidente que esto no es adecuado para nada más que los casos de uso más básicos. No todos los terminales admiten los mismos códigos ANSI, las construcciones de estilo deben ser meticulosamente eliminadas al calcular el ancho del contenido ya estilizado, y eso es antes de que incluso comiences a manejar múltiples formatos de salida.
En lugar de dejar que este dolor de cabeza sea ampliamente experimentado en la parte inferior, se aborda de manera directa mediante la introducción de un tipo de cadena especial (AnnotatedString
). Este tipo de cadena envuelve cualquier otro tipo AbstractString
y permite que se apliquen información de formato a regiones (por ejemplo, los caracteres del 1 al 7 son negrita y rojos).
Las regiones de una cadena se estilizan aplicando Face
(piensa en "tipografía") a ellas: una estructura que contiene información de estilo. Como conveniencia, las tipografías en el diccionario global de tipografías (por ejemplo, shadow
) pueden ser nombradas en lugar de dar el 4d61726b646f776e2e436f64652822222c2022466163652229_40726566205374796c6564537472696e67732e46616365
directamente.
Junto con estas capacidades, también proporcionamos una forma conveniente de construir AnnotatedString
, detallado en Styled String Literals.
julia> using StyledStrings
julia> styled"{yellow:hello} {blue:there}"
"hello there"
Annotated Strings
A veces es útil poder mantener metadatos relacionados con regiones de una cadena. Un AnnotatedString
envuelve otra cadena y permite que las regiones de esta sean anotadas con valores etiquetados (:label => value
). Todas las operaciones de cadena genéricas se aplican a la cadena subyacente. Sin embargo, cuando es posible, se preserva la información de estilo. Esto significa que puedes manipular un 4d61726b646f776e2e436f64652822222c2022416e6e6f7461746564537472696e672229_4072656620426173652e416e6e6f7461746564537472696e67
—tomando subcadenas, rellenándolas, concatenándolas con otras cadenas— y las anotaciones de metadatos "vendrán junto con el viaje".
Este tipo de cadena es fundamental para el StyledStrings stdlib, que utiliza anotaciones etiquetadas con :face
para mantener información de estilo.
Al concatenar un AnnotatedString
, asegúrate de usar annotatedstring
en lugar de string
si deseas mantener las anotaciones de cadena.
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
Las anotaciones de un AnnotatedString
se pueden acceder y modificar a través de las funciones annotations
y annotate!
.
Styling via AnnotatedString
s
Faces
The Face
type
Un Face
especifica detalles de una tipografía en la que se puede establecer texto. Cubre un conjunto de atributos básicos que se generalizan bien en diferentes formatos, a saber:
fuente
altura
peso
inclinación
primer plano
fondo
subrayar
tachado
inverso
heredar
Para obtener detalles sobre las formas particulares que toman estos atributos, consulta el Face
docstring, pero de particular interés es inherit
, ya que te permite heredar atributos de otros 4d61726b646f776e2e436f64652822222c2022466163652229_40726566205374796c6564537472696e67732e46616365
s.
The global faces dictionary
Para hacer que la referencia a estilos particulares sea más conveniente, hay un Dict{Symbol, Face}
global que permite que los Face
se refieran simplemente por nombre. Los paquetes pueden agregar caras a este diccionario a través de la función addface!
, y las caras cargadas pueden ser fácilmente customized.
Cualquier paquete que registre nuevas caras debe asegurarse de que estén precedidas por el nombre del paquete, es decir, seguir el formato mypackage_myface
. Esto es importante para la previsibilidad y para prevenir conflictos de nombres.
Además, los paquetes deben tener cuidado de usar (e introducir) caras semánticas (como code
) en lugar de colores y estilos directos (como cyan
). Esto es útil de varias maneras, desde hacer que la intención en el uso sea más obvia, ayudar a la composabilidad y hacer que la personalización del usuario sea más intuitiva.
Hay dos conjuntos de exenciones a la regla del prefijo del paquete:
- el conjunto de caras básicas que son parte del valor predeterminado del diccionario de caras
- caras introducidas por la propia biblioteca estándar de Julia, a saber,
JuliaSyntaxHighlighting
Basic faces
Las caras básicas están destinadas a representar una idea general que es ampliamente aplicable.
Para establecer un texto con un cierto atributo, tenemos las caras negrita
, ligera
, cursiva
, subrayado
, tachado
e inversa
.
También hay nombres para los 16 colores terminales: negro
, rojo
, verde
, amarillo
, azul
, magenta
, cian
, blanco
, negro_brillante
/gris
, rojo_brillante
, verde_brillante
, azul_brillante
, magenta_brillante
, cian_brillante
y blanco_brillante
.
Para el texto sombreado (es decir, tenue pero presente) existe la cara shadow
. Para indicar una región seleccionada, está la cara region
. De manera similar, para énfasis y resaltado se definen las caras emphasis
y highlight
. También hay code
para texto similar al código.
Para indicar visualmente la gravedad de los mensajes, se definen las caras de error
, warning
, success
, info
, note
y tip
.
Customisation of faces (Faces.toml
)
Es bueno que los nombres de las caras en el diccionario global de caras sean personalizables. La tematización y la estética son agradables, y también es importante por razones de accesibilidad. Un archivo TOML se puede analizar en una lista de Face
especificaciones que se fusionan con la entrada preexistente en el diccionario de caras.
Un Face
se representa en TOML de la siguiente manera:
[facename]
attribute = "value"
...
[package.facename]
attribute = "value"
Por ejemplo, si la cara shadow
es demasiado difícil de leer, se puede hacer más brillante así:
[shadow]
foreground = "white"
Al iniciar, se carga el archivo config/faces.toml
en el primer depósito de Julia (generalmente ~/.julia
).
Applying faces to a AnnotatedString
Por convención, los atributos :face
de un AnnotatedString
contienen información sobre los Face
que actualmente se aplican. Esto se puede dar en múltiples formas, como un único Symbol
que nombra un 4d61726b646f776e2e436f64652822222c2022466163652229_40726566205374796c6564537472696e67732e46616365
en el diccionario de caras global, un 4d61726b646f776e2e436f64652822222c2022466163652229_40726566205374796c6564537472696e67732e46616365
en sí, o un vector de cualquiera de ellos.
Los métodos show(::IO, ::MIME"text/plain", ::AnnotatedString)
y show(::IO, ::MIME"text/html", ::AnnotatedString)
ambos examinan los atributos :face
y los combinan todos al determinar el estilo general.
Podemos suministrar atributos :face
a un AnnotatedString
durante la construcción, agregarlos a la lista de propiedades después, o usar el conveniente 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
Para facilitar la construcción de AnnotatedString
s con Face
s aplicados, el literal de cadena estilizado styled"..."
permite que el contenido y los atributos se expresen fácilmente juntos a través de una gramática personalizada.
Dentro de un literal styled"..."
, las llaves se consideran caracteres especiales y deben ser escapadas en el uso normal (\{
, \}
). Esto permite que se utilicen para expresar anotaciones con construcciones {anotaciones...:texto}
(anidables).
El componente annotations...
es una lista separada por comas de tres tipos de anotaciones.
- Nombres de cara
- Expresiones
Face
en línea(clave=valor,...)
clave=valor
pares
La interpolación es posible en todas partes excepto para las claves de cara en línea.
Para más información sobre la gramática, consulte la ayuda extendida del docstring styled"..."
.
Como ejemplo, podemos demostrar la lista de caras integradas mencionadas anteriormente de la siguiente manera:
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
Construya una cadena con estilo. Dentro de la cadena, las estructuras {<specs>:<content>}
aplican el formato a <content>
, de acuerdo con la lista de especificaciones separadas por comas <specs>
. Cada especificación puede tomar la forma de un nombre de cara, una especificación de cara en línea, o un par key=value
. El valor debe estar envuelto por {...}
si contiene alguno de los caracteres ,=:{}
.
La interpolación de cadenas con $
funciona de la misma manera que las cadenas regulares, excepto que las comillas deben ser escapadas. Las caras, claves y valores también se pueden interpolar con $
.
Ejemplo
styled"The {bold:{italic:quick} {(foreground=#cd853f):brown} fox} jumped over the {link={https://en.wikipedia.org/wiki/Laziness}:lazy} dog"
Ayuda extendida
Este macro se puede describir mediante la siguiente gramática 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' } ; (* espacio en blanco *)
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 = [^${},:], [^,:]* ;
Una estipulación adicional no codificada en la gramática anterior es que plain
debe ser una entrada válida para unescape_string
, con specialchar
mantenido.
La gramática anterior para inlineface
está simplificada, ya que la implementación real es un poco más sofisticada. El comportamiento completo se da a continuación.
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
Construye una cadena estilizada. Dentro de la cadena, las estructuras {<specs>:<content>}
aplican el formato a <content>
, de acuerdo con la lista de especificaciones separadas por comas <specs>
. Cada especificación puede tomar la forma de un nombre de cara, una especificación de cara en línea, o un par key=value
. El valor debe estar envuelto por {...}
si contiene alguno de los caracteres ,=:{}
.
Esta es una equivalente funcional de la macro @styled_str
, solo que sin capacidades de interpolación.
StyledStrings.Face
— TypeUna Face
es una colección de atributos gráficos para mostrar texto. Las caras controlan cómo se muestra el texto en la terminal, y posiblemente en otros lugares también.
La mayoría de las veces, una Face
se almacenará en los diccionarios globales de caras como una asociación única con un nombre de cara Symbol, y se referirá a menudo por este nombre en lugar del objeto Face
en sí.
Atributos
Todos los atributos se pueden establecer a través del constructor de palabras clave y por defecto son nothing
.
height
(unInt
oFloat64
): La altura en deci-pt (cuando es unInt
), o como un factor del tamaño base (cuando es unFloat64
).weight
(unSymbol
): Uno de los símbolos (de más tenue a más denso):thin
,:extralight
,:light
,:semilight
,:normal
,:medium
,:semibold
,:bold
,:extrabold
, o:black
. En las terminales, cualquier peso mayor que:normal
se muestra como negrita, y en las terminales que soportan texto de brillo variable, cualquier peso menor que:normal
se muestra como tenue.slant
(unSymbol
): Uno de los símbolos:italic
,:oblique
, o:normal
.foreground
(unSimpleColor
): El color del primer plano del texto.background
(unSimpleColor
): El color de fondo del texto.underline
, el subrayado del texto, que toma una de las siguientes formas:- un
Bool
: Si el texto debe estar subrayado o no. - un
SimpleColor
: El texto debe estar subrayado con este color. - un
Tuple{Nothing, Symbol}
: El texto debe estar subrayado utilizando el estilo establecido por el Symbol, uno de:straight
,:double
,:curly
,:dotted
, o:dashed
. - un
Tuple{SimpleColor, Symbol}
: El texto debe estar subrayado en el SimpleColor especificado, y utilizando el estilo especificado por el Symbol, como antes.
- un
strikethrough
(unBool
): Si el texto debe estar tachado.inverse
(unBool
): Si los colores de primer plano y fondo deben ser invertidos.inherit
(unVector{Symbol}
): Nombres de caras de las que heredar, con las caras anteriores tomando prioridad. Todas las caras heredan de la cara:default
.
StyledStrings.addface!
— Functionaddface!(name::Symbol => default::Face)
Crea una nueva cara con el nombre name
. Siempre que no exista ya una cara con este nombre, default
se añade tanto a FACES
.default
como (una copia de) a FACES
.current
, con el valor actual devuelto.
Si la cara name
ya existe, se devuelve nothing
.
Ejemplos
julia> addface!(:mypkg_myface => Face(slant=:italic, underline=true))
Face (muestra)
slant: italic
underline: true
StyledStrings.withfaces
— Functionwithfaces(f, kv::Pair...)
withfaces(f, kvpair_itr)
Ejecuta f
con FACES
.current
temporalmente modificado por cero o más argumentos :name => val
kv
, o kvpair_itr
que produce valores en forma de kv
.
withfaces
se utiliza generalmente a través de la sintaxis withfaces(kv...) do ... end
. Un valor de nothing
se puede usar para desactivar temporalmente una cara (si ha sido configurada). Cuando withfaces
retorna, el original FACES
.current
ha sido restaurado.
Ejemplos
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
Una representación básica de un color, destinada a propósitos de estilo de cadena. Puede contener un color nombrado (como :red
), o un RGBTuple
que es un NamedTuple que especifica un color r
, g
, b
con una profundidad de bits de 8.
Constructores
SimpleColor(name::Symbol) # p. ej. :red
SimpleColor(rgb::RGBTuple) # p. ej. (r=1, b=2, g=3)
SimpleColor(r::Integer, b::Integer, b::Integer)
SimpleColor(rgb::UInt32) # p. ej. 0x123456
También consulta tryparse(SimpleColor, rgb::String)
.
Base.parse
— Methodparse(::Type{SimpleColor}, rgb::String)
Un análogo de tryparse(SimpleColor, rgb::String)
(ver), que genera un error en lugar de devolver nothing
.
Base.tryparse
— Methodtryparse(::Type{SimpleColor}, rgb::String)
Intenta analizar rgb
como un SimpleColor
. Si rgb
comienza con #
y tiene una longitud de 7, se convierte en un SimpleColor
respaldado por un RGBTuple
. Si rgb
comienza con a
-z
, rgb
se interpreta como un nombre de color y se convierte en un SimpleColor
respaldado por un Symbol
.
De lo contrario, se devuelve nothing
.
Ejemplos
julia> tryparse(SimpleColor, "blue")
SimpleColor(blue)
julia> tryparse(SimpleColor, "#9558b2")
SimpleColor(#9558b2)
julia> tryparse(SimpleColor, "#nocolor")
Base.merge
— Methodmerge(initial::Face, others::Face...)
Fusiona las propiedades de la cara initial
y others
, dando prioridad a las caras posteriores.