Definições de estilo para layouts de terminal agradáveis. Construído com TUIs em mente.
Lip Gloss adota uma abordagem expressiva e declarativa para renderização de terminal. Os usuários familiarizados com CSS se sentirão em casa com o Lip Gloss.
import "github.com/charmbracelet/lipgloss"
var style = lipgloss . NewStyle ().
Bold ( true ).
Foreground ( lipgloss . Color ( "#FAFAFA" )).
Background ( lipgloss . Color ( "#7D56F4" )).
PaddingTop ( 2 ).
PaddingLeft ( 4 ).
Width ( 22 )
fmt . Println ( style . Render ( "Hello, kitty" ))
Lip Gloss suporta os seguintes perfis de cores:
lipgloss . Color ( "5" ) // magenta
lipgloss . Color ( "9" ) // red
lipgloss . Color ( "12" ) // light blue
lipgloss . Color ( "86" ) // aqua
lipgloss . Color ( "201" ) // hot pink
lipgloss . Color ( "202" ) // orange
lipgloss . Color ( "#0000FF" ) // good ol' 100% blue
lipgloss . Color ( "#04B575" ) // a green
lipgloss . Color ( "#3C3C3C" ) // a dark gray
...bem como um perfil ASCII de 1 bit, que é apenas preto e branco.
O perfil de cores do terminal será detectado automaticamente e as cores fora da gama da paleta atual serão automaticamente coagidas para o valor disponível mais próximo.
Você também pode especificar opções de cores para fundos claros e escuros:
lipgloss. AdaptiveColor { Light : "236" , Dark : "248" }
A cor de fundo do terminal será detectada automaticamente e a cor apropriada será escolhida em tempo de execução.
CompleteColor especifica valores exatos para perfis de cores True Color, ANSI256 e ANSI.
lipgloss. CompleteColor { TrueColor : "#0000FF" , ANSI256 : "86" , ANSI : "5" }
A degradação automática da cor não será executada neste caso e será baseada na cor especificada.
Você pode usar CompleteColor
com AdaptiveColor
para especificar os valores exatos para fundos claros e escuros sem degradação automática de cores.
lipgloss. CompleteAdaptiveColor {
Light : CompleteColor { TrueColor : "#d7ffae" , ANSI256 : "193" , ANSI : "11" },
Dark : CompleteColor { TrueColor : "#d75fee" , ANSI256 : "163" , ANSI : "5" },
}
Lip Gloss suporta as opções usuais de formatação de texto ANSI:
var style = lipgloss . NewStyle ().
Bold ( true ).
Italic ( true ).
Faint ( true ).
Blink ( true ).
Strikethrough ( true ).
Underline ( true ).
Reverse ( true )
Lip Gloss também oferece suporte a regras para formatação em nível de bloco:
// Padding
var style = lipgloss . NewStyle ().
PaddingTop ( 2 ).
PaddingRight ( 4 ).
PaddingBottom ( 2 ).
PaddingLeft ( 4 )
// Margins
var style = lipgloss . NewStyle ().
MarginTop ( 2 ).
MarginRight ( 4 ).
MarginBottom ( 2 ).
MarginLeft ( 4 )
Há também uma sintaxe abreviada para margens e preenchimento, que segue o mesmo formato do CSS:
// 2 cells on all sides
lipgloss . NewStyle (). Padding ( 2 )
// 2 cells on the top and bottom, 4 cells on the left and right
lipgloss . NewStyle (). Margin ( 2 , 4 )
// 1 cell on the top, 4 cells on the sides, 2 cells on the bottom
lipgloss . NewStyle (). Padding ( 1 , 4 , 2 )
// Clockwise, starting from the top: 2 cells on the top, 4 on the right, 3 on
// the bottom, and 1 on the left
lipgloss . NewStyle (). Margin ( 2 , 4 , 3 , 1 )
Você pode alinhar parágrafos de texto à esquerda, à direita ou ao centro.
var style = lipgloss . NewStyle ().
Width ( 24 ).
Align ( lipgloss . Left ). // align it left
Align ( lipgloss . Right ). // no wait, align it right
Align ( lipgloss . Center ) // just kidding, align it in the center
Definir largura e altura mínimas é simples e direto.
var style = lipgloss . NewStyle ().
SetString ( "What’s for lunch?" ).
Width ( 24 ).
Height ( 32 ).
Foreground ( lipgloss . Color ( "63" ))
Adicionar bordas é fácil:
// Add a purple, rectangular border
var style = lipgloss . NewStyle ().
BorderStyle ( lipgloss . NormalBorder ()).
BorderForeground ( lipgloss . Color ( "63" ))
// Set a rounded, yellow-on-purple border to the top and left
var anotherStyle = lipgloss . NewStyle ().
BorderStyle ( lipgloss . RoundedBorder ()).
BorderForeground ( lipgloss . Color ( "228" )).
BorderBackground ( lipgloss . Color ( "63" )).
BorderTop ( true ).
BorderLeft ( true )
// Make your own border
var myCuteBorder = lipgloss. Border {
Top : "._.:*:" ,
Bottom : "._.:*:" ,
Left : "|*" ,
Right : "|*" ,
TopLeft : "*" ,
TopRight : "*" ,
BottomLeft : "*" ,
BottomRight : "*" ,
}
Existem também funções abreviadas para definir bordas, que seguem um padrão semelhante às funções abreviadas de margem e preenchimento.
// Add a thick border to the top and bottom
lipgloss . NewStyle ().
Border ( lipgloss . ThickBorder (), true , false )
// Add a double border to the top and left sides. Rules are set clockwise
// from top.
lipgloss . NewStyle ().
Border ( lipgloss . DoubleBorder (), true , false , false , true )
Para mais informações sobre fronteiras, consulte a documentação.
Basta usar atribuição:
style := lipgloss . NewStyle (). Foreground ( lipgloss . Color ( "219" ))
copiedStyle := style // this is a true copy
wildStyle := style . Blink ( true ) // this is also true copy, with blink added
Como as estruturas de dados Style
contêm apenas tipos primitivos, atribuir um estilo a outro cria efetivamente uma nova cópia do estilo sem alterar o original.
Os estilos podem herdar regras de outros estilos. Ao herdar, apenas as regras não definidas no receptor são herdadas.
var styleA = lipgloss . NewStyle ().
Foreground ( lipgloss . Color ( "229" )).
Background ( lipgloss . Color ( "63" ))
// Only the background color will be inherited here, because the foreground
// color will have been already set:
var styleB = lipgloss . NewStyle ().
Foreground ( lipgloss . Color ( "201" )).
Inherit ( styleA )
Todas as regras podem ser canceladas:
var style = lipgloss . NewStyle ().
Bold ( true ). // make it bold
UnsetBold (). // jk don't make it bold
Background ( lipgloss . Color ( "227" )). // yellow background
UnsetBackground () // never mind
Quando uma regra não é definida, ela não será herdada nem copiada.
Às vezes, como ao desenvolver um componente, você deseja garantir que as definições de estilo respeitem a finalidade pretendida na IU. É aqui que entram Inline
, MaxWidth
e MaxHeight
:
// Force rendering onto a single line, ignoring margins, padding, and borders.
someStyle . Inline ( true ). Render ( "yadda yadda" )
// Also limit rendering to five cells
someStyle . Inline ( true ). MaxWidth ( 5 ). Render ( "yadda yadda" )
// Limit rendering to a 5x5 cell block
someStyle . MaxWidth ( 5 ). MaxHeight ( 5 ). Render ( "yadda yadda" )
O caractere de tabulação ( t
) é renderizado de forma diferente em terminais diferentes (geralmente com 8 espaços, às vezes 4). Devido a essa inconsistência, o Lip Gloss converte tabulações em 4 espaços no momento da renderização. No entanto, esse comportamento pode ser alterado de acordo com o estilo:
style := lipgloss . NewStyle () // tabs will render as 4 spaces, the default
style = style . TabWidth ( 2 ) // render tabs as 2 spaces
style = style . TabWidth ( 0 ) // remove tabs entirely
style = style . TabWidth ( lipgloss . NoTabConversion ) // leave tabs intact
Geralmente, você apenas chama o método Render(string...)
em um lipgloss.Style
:
style := lipgloss . NewStyle (). Bold ( true ). SetString ( "Hello," )
fmt . Println ( style . Render ( "kitty." )) // Hello, kitty.
fmt . Println ( style . Render ( "puppy." )) // Hello, puppy.
Mas você também pode usar a interface Stringer:
var style = lipgloss . NewStyle (). SetString ( "你好,猫咪。" ). Bold ( true )
fmt . Println ( style ) // 你好,猫咪。
Renderizadores personalizados permitem renderizar para saídas específicas. Isso é particularmente importante quando você deseja renderizar diferentes saídas e detectar corretamente o perfil de cores e o status do fundo escuro de cada uma, como em uma situação servidor-cliente.
func myLittleHandler ( sess ssh. Session ) {
// Create a renderer for the client.
renderer := lipgloss . NewRenderer ( sess )
// Create a new style on the renderer.
style := renderer . NewStyle (). Background (lipgloss. AdaptiveColor { Light : "63" , Dark : "228" })
// Render. The color profile and dark background state will be correctly detected.
io . WriteString ( sess , style . Render ( "Heyyyyyyy" ))
}
Para obter um exemplo de como usar um renderizador personalizado sobre SSH com Wish, consulte o exemplo SSH.
Além do estilo puro, o Lip Gloss também vem com alguns utilitários para ajudar a montar seus layouts.
Unir parágrafos horizontal e verticalmente é muito fácil.
// Horizontally join three paragraphs along their bottom edges
lipgloss . JoinHorizontal ( lipgloss . Bottom , paragraphA , paragraphB , paragraphC )
// Vertically join two paragraphs along their center axes
lipgloss . JoinVertical ( lipgloss . Center , paragraphA , paragraphB )
// Horizontally join three paragraphs, with the shorter ones aligning 20%
// from the top of the tallest
lipgloss . JoinHorizontal ( 0.2 , paragraphA , paragraphB , paragraphC )
Às vezes você vai querer saber a largura e a altura dos blocos de texto ao construir seus layouts.
// Render a block of text.
var style = lipgloss . NewStyle ().
Width ( 40 ).
Padding ( 2 )
var block string = style . Render ( someLongString )
// Get the actual, physical dimensions of the text block.
width := lipgloss . Width ( block )
height := lipgloss . Height ( block )
// Here's a shorthand function.
w , h := lipgloss . Size ( block )
Às vezes você simplesmente desejará colocar um bloco de texto em um espaço em branco.
// Center a paragraph horizontally in a space 80 cells wide. The height of
// the block returned will be as tall as the input paragraph.
block := lipgloss . PlaceHorizontal ( 80 , lipgloss . Center , fancyStyledParagraph )
// Place a paragraph at the bottom of a space 30 cells tall. The width of
// the text block returned will be as wide as the input paragraph.
block := lipgloss . PlaceVertical ( 30 , lipgloss . Bottom , fancyStyledParagraph )
// Place a paragraph in the bottom right corner of a 30x80 cell space.
block := lipgloss . Place ( 30 , 80 , lipgloss . Right , lipgloss . Bottom , fancyStyledParagraph )
Você também pode estilizar o espaço em branco. Para obter detalhes, consulte os documentos.
Lip Gloss vem com um subpacote de renderização de tabela.
import "github.com/charmbracelet/lipgloss/table"
Defina algumas linhas de dados.
rows := [][] string {
{ "Chinese" , "您好" , "你好" },
{ "Japanese" , "こんにちは" , "やあ" },
{ "Arabic" , "أهلين" , "أهلا" },
{ "Russian" , "Здравствуйте" , "Привет" },
{ "Spanish" , "Hola" , "¿Qué tal?" },
}
Use o pacote table para estilizar e renderizar a tabela.
t := table . New ().
Border ( lipgloss . NormalBorder ()).
BorderStyle ( lipgloss . NewStyle (). Foreground ( lipgloss . Color ( "99" ))).
StyleFunc ( func ( row , col int ) lipgloss. Style {
switch {
case row == 0 :
return HeaderStyle
case row % 2 == 0 :
return EvenRowStyle
default :
return OddRowStyle
}
}).
Headers ( "LANGUAGE" , "FORMAL" , "INFORMAL" ).
Rows ( rows ... )
// You can also add tables row-by-row
t . Row ( "English" , "You look absolutely fabulous." , "How's it going?" )
Imprima a tabela.
fmt . Println ( t )
Aviso
Rows
da tabela precisam ser declaradas antes Offset
, caso contrário não fará nada.
Para mais informações sobre tabelas, consulte os documentos e exemplos.
Lip Gloss vem com um subpacote de renderização de lista.
import "github.com/charmbracelet/lipgloss/list"
Defina uma nova lista.
l := list . New ( "A" , "B" , "C" )
Imprima a lista.
fmt . Println ( l )
// • A
// • B
// • C
As listas têm a capacidade de aninhar.
l := list . New (
"A" , list . New ( "Artichoke" ),
"B" , list . New ( "Baking Flour" , "Bananas" , "Barley" , "Bean Sprouts" ),
"C" , list . New ( "Cashew Apple" , "Cashews" , "Coconut Milk" , "Curry Paste" , "Currywurst" ),
"D" , list . New ( "Dill" , "Dragonfruit" , "Dried Shrimp" ),
"E" , list . New ( "Eggs" ),
"F" , list . New ( "Fish Cake" , "Furikake" ),
"J" , list . New ( "Jicama" ),
"K" , list . New ( "Kohlrabi" ),
"L" , list . New ( "Leeks" , "Lentils" , "Licorice Root" ),
)
Imprima a lista.
fmt . Println ( l )
As listas podem ser personalizadas através de sua função de enumeração, bem como usando lipgloss.Style
s.
enumeratorStyle := lipgloss . NewStyle (). Foreground ( lipgloss . Color ( "99" )). MarginRight ( 1 )
itemStyle := lipgloss . NewStyle (). Foreground ( lipgloss . Color ( "212" )). MarginRight ( 1 )
l := list . New (
"Glossier" ,
"Claire’s Boutique" ,
"Nyx" ,
"Mac" ,
"Milk" ,
).
Enumerator ( list . Roman ).
EnumeratorStyle ( enumeratorStyle ).
ItemStyle ( itemStyle )
Imprima a lista.
Além dos enumeradores predefinidos ( Arabic
, Alphabet
, Roman
, Bullet
, Tree
), você também pode definir seu próprio enumerador personalizado:
l := list . New ( "Duck" , "Duck" , "Duck" , "Duck" , "Goose" , "Duck" , "Duck" )
func DuckDuckGooseEnumerator ( l list. Items , i int ) string {
if l . At ( i ). Value () == "Goose" {
return "Honk →"
}
return ""
}
l = l . Enumerator ( DuckDuckGooseEnumerator )
Imprima a lista:
Se precisar, você também pode criar listas de forma incremental:
l := list . New ()
for i := 0 ; i < repeat ; i ++ {
l . Item ( "Lip Gloss" )
}
Lip Gloss vem com um subpacote de renderização de árvore.
import "github.com/charmbracelet/lipgloss/tree"
Defina uma nova árvore.
t := tree . Root ( "." ).
Child ( "A" , "B" , "C" )
Imprima a árvore.
fmt . Println ( t )
// .
// ├── A
// ├── B
// └── C
As árvores têm a capacidade de nidificar.
t := tree . Root ( "." ).
Child ( "macOS" ).
Child (
tree . New ().
Root ( "Linux" ).
Child ( "NixOS" ).
Child ( "Arch Linux (btw)" ).
Child ( "Void Linux" ),
).
Child (
tree . New ().
Root ( "BSD" ).
Child ( "FreeBSD" ).
Child ( "OpenBSD" ),
)
Imprima a árvore.
fmt . Println ( t )
As árvores podem ser personalizadas através de sua função de enumeração, bem como usando lipgloss.Style
s.
enumeratorStyle := lipgloss . NewStyle (). Foreground ( lipgloss . Color ( "63" )). MarginRight ( 1 )
rootStyle := lipgloss . NewStyle (). Foreground ( lipgloss . Color ( "35" ))
itemStyle := lipgloss . NewStyle (). Foreground ( lipgloss . Color ( "212" ))
t := tree .
Root ( "⁜ Makeup" ).
Child (
"Glossier" ,
"Fenty Beauty" ,
tree . New (). Child (
"Gloss Bomb Universal Lip Luminizer" ,
"Hot Cheeks Velour Blushlighter" ,
),
"Nyx" ,
"Mac" ,
"Milk" ,
).
Enumerator ( tree . RoundedEnumerator ).
EnumeratorStyle ( enumeratorStyle ).
RootStyle ( rootStyle ).
ItemStyle ( itemStyle )
Imprima a árvore.
Os enumeradores predefinidos para árvores são DefaultEnumerator
e RoundedEnumerator
.
Se precisar, você também pode construir árvores de forma incremental:
t := tree . New ()
for i := 0 ; i < repeat ; i ++ {
t . Child ( "Lip Gloss" )
}
Provavelmente, isso se deve à sua localidade e codificação, principalmente em relação ao chinês, japonês e coreano (por exemplo, zh_CN.UTF-8
ou ja_JP.UTF-8
). A maneira mais direta de corrigir isso é definir RUNEWIDTH_EASTASIAN=0
em seu ambiente.
Para obter detalhes, consulte https://github.com/charmbracelet/lipgloss/issues/40.
O Lip Gloss degrada automaticamente as cores para a melhor opção disponível no terminal fornecido e, se a saída não for um TTY, ele removerá totalmente a saída colorida. Isso é comum ao executar testes, CI ou ao canalizar a saída para outro lugar.
Se necessário, você pode forçar um perfil de cores em seus testes com SetColorProfile
.
import (
"github.com/charmbracelet/lipgloss"
"github.com/muesli/termenv"
)
lipgloss . SetColorProfile ( termenv . TrueColor )
Observação: esta opção limita a flexibilidade do seu aplicativo e pode fazer com que códigos de escape ANSI sejam gerados em casos em que isso não seja desejado. Observe cuidadosamente seu caso de uso e ambiente antes de decidir forçar um perfil de cores.
Lip Gloss não substitui Bubble Tea. Em vez disso, é um excelente companheiro do Bubble Tea. Ele foi projetado para tornar a montagem de visualizações da interface do usuário do terminal tão simples e divertida quanto possível, para que você possa se concentrar na construção de seu aplicativo em vez de se preocupar com detalhes de layout de baixo nível.
Em termos simples, você pode usar Lip Gloss para ajudar a construir suas visualizações do Bubble Tea.
Lip Gloss é baseado nas excelentes bibliotecas Termenv e Reflow que lidam com operações de cores e texto com reconhecimento de ANSI, respectivamente. Para muitos casos de uso, Termenv e Reflow serão suficientes para suas necessidades.
Para uma solução de renderização mais centrada em documentos com suporte para coisas como listas, tabelas e código realçado por sintaxe, dê uma olhada no Glamour, o renderizador Markdown baseado em folha de estilo.
Veja contribuindo.
Adoraríamos ouvir sua opinião sobre este projeto. Sinta-se à vontade para nos deixar uma mensagem!
MIT
Parte do charme.
Charm热爱开源 • Charm adora código aberto