2024-05-01 21:22:21 +03:00
# Lip Gloss
2021-03-18 18:23:08 +03:00
2021-03-18 19:34:26 +03:00
< p >
2024-03-19 05:09:05 +03:00
< a href = "https://stuff.charm.sh/lipgloss/lipgloss-mascot-2k.png" > < img width = "340" alt = "Lip Gloss title treatment" src = "https://github.com/charmbracelet/lipgloss/assets/25087/147cadb1-4254-43ec-ae6b-8d6ca7b029a1" > < / a > < br >
2021-03-18 19:34:26 +03:00
< a href = "https://github.com/charmbracelet/lipgloss/releases" > < img src = "https://img.shields.io/github/release/charmbracelet/lipgloss.svg" alt = "Latest Release" > < / a >
< a href = "https://pkg.go.dev/github.com/charmbracelet/lipgloss?tab=doc" > < img src = "https://godoc.org/github.com/golang/gddo?status.svg" alt = "GoDoc" > < / a >
< a href = "https://github.com/charmbracelet/lipgloss/actions" > < img src = "https://github.com/charmbracelet/lipgloss/workflows/build/badge.svg" alt = "Build Status" > < / a >
2024-03-19 05:09:05 +03:00
< a href = "https://www.phorm.ai/query?projectId=a0e324b6-b706-4546-b951-6671ea60c13f" > < img src = "https://stuff.charm.sh/misc/phorm-badge.svg" alt = "phorm.ai" > < / a >
2021-03-18 19:34:26 +03:00
< / p >
2021-04-03 04:50:32 +03:00
Style definitions for nice terminal layouts. Built with TUIs in mind.
2021-03-31 17:24:58 +03:00
2021-04-03 00:57:53 +03:00
![Lip Gloss example ](https://stuff.charm.sh/lipgloss/lipgloss-example.png )
2021-03-31 17:24:58 +03:00
2021-04-03 17:25:48 +03:00
Lip Gloss takes an expressive, declarative approach to terminal rendering.
Users familiar with CSS will feel at home with Lip Gloss.
2021-03-18 18:23:08 +03:00
```go
import "github.com/charmbracelet/lipgloss"
2022-11-19 00:02:02 +03:00
var style = lipgloss.NewStyle().
2021-03-18 18:23:08 +03:00
Bold(true).
2021-03-31 17:24:58 +03:00
Foreground(lipgloss.Color("#FAFAFA")).
Background(lipgloss.Color("#7D56F4")).
2021-03-18 18:23:08 +03:00
PaddingTop(2).
PaddingLeft(4).
2021-03-31 17:24:58 +03:00
Width(22)
2021-03-18 18:23:08 +03:00
2023-03-08 22:51:26 +03:00
fmt.Println(style.Render("Hello, kitty"))
2021-03-18 18:23:08 +03:00
```
## Colors
Lip Gloss supports the following color profiles:
### ANSI 16 colors (4-bit)
```go
lipgloss.Color("5") // magenta
lipgloss.Color("9") // red
lipgloss.Color("12") // light blue
```
### ANSI 256 Colors (8-bit)
```go
lipgloss.Color("86") // aqua
lipgloss.Color("201") // hot pink
lipgloss.Color("202") // orange
```
2021-05-31 19:27:03 +03:00
### True Color (16,777,216 colors; 24-bit)
2021-03-18 18:23:08 +03:00
```go
lipgloss.Color("#0000FF") // good ol' 100% blue
lipgloss.Color("#04B575") // a green
lipgloss.Color("#3C3C3C") // a dark gray
```
2022-09-29 05:15:34 +03:00
...as well as a 1-bit ASCII profile, which is black and white only.
2021-05-31 19:27:03 +03:00
2021-03-25 16:19:04 +03:00
The terminal's color profile will be automatically detected, and colors outside
the gamut of the current palette will be automatically coerced to their closest
available value.
2021-03-18 18:23:08 +03:00
### Adaptive Colors
You can also specify color options for light and dark backgrounds:
```go
2021-03-18 22:00:54 +03:00
lipgloss.AdaptiveColor{Light: "236", Dark: "248"}
2021-03-18 18:23:08 +03:00
```
The terminal's background color will automatically be detected and the
2021-03-29 23:27:47 +03:00
appropriate color will be chosen at runtime.
2021-03-18 18:23:08 +03:00
2022-10-03 20:45:30 +03:00
### Complete Colors
CompleteColor specifies exact values for truecolor, ANSI256, and ANSI color
profiles.
```go
lipgloss.CompleteColor{True: "#0000FF", ANSI256: "86", ANSI: "5"}
```
Automatic color degradation will not be performed in this case and it will be
based on the color specified.
### Complete Adaptive Colors
You can use CompleteColor with AdaptiveColor to specify the exact values for
light and dark backgrounds without automatic color degradation.
```go
lipgloss.CompleteAdaptiveColor{
Light: CompleteColor{TrueColor: "#d7ffae", ANSI256: "193", ANSI: "11"},
Dark: CompleteColor{TrueColor: "#d75fee", ANSI256: "163", ANSI: "5"},
}
```
2021-03-18 18:23:08 +03:00
## Inline Formatting
Lip Gloss supports the usual ANSI text formatting options:
```go
var style = lipgloss.NewStyle().
Bold(true).
Italic(true).
Faint(true).
Blink(true).
Strikethrough(true).
Underline(true).
Reverse(true)
```
## Block-Level Formatting
Lip Gloss also supports rules for block-level formatting:
```go
// Padding
var style = lipgloss.NewStyle().
2021-03-24 20:55:43 +03:00
PaddingTop(2).
PaddingRight(4).
PaddingBottom(2).
PaddingLeft(4)
2021-03-18 18:23:08 +03:00
// Margins
var style = lipgloss.NewStyle().
2021-03-24 20:55:43 +03:00
MarginTop(2).
2021-12-10 23:13:14 +03:00
MarginRight(4).
2021-03-24 20:55:43 +03:00
MarginBottom(2).
MarginLeft(4)
2021-03-18 18:23:08 +03:00
```
There is also shorthand syntax for margins and padding, which follows the same
format as CSS:
```go
// 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)
```
## Aligning Text
2021-03-18 20:48:48 +03:00
You can align paragraphs of text to the left, right, or center.
2021-03-18 18:23:08 +03:00
```go
var style = lipgloss.NewStyle().
Width(24).
2021-03-31 21:06:12 +03:00
Align(lipgloss.Left). // align it left
Align(lipgloss.Right). // no wait, align it right
Align(lipgloss.Center) // just kidding, align it in the center
2021-03-18 18:23:08 +03:00
```
2021-03-31 17:24:58 +03:00
## Width and Height
2021-03-24 21:42:45 +03:00
2021-11-22 09:15:09 +03:00
Setting a minimum width and height is simple and straightforward.
2021-03-24 21:42:45 +03:00
```go
2022-11-19 00:02:02 +03:00
var style = lipgloss.NewStyle().
SetString("What’ s for lunch?").
2021-03-24 21:42:45 +03:00
Width(24).
Height(32).
2022-06-28 20:28:35 +03:00
Foreground(lipgloss.Color("63"))
2021-03-24 21:42:45 +03:00
```
2021-04-28 23:26:04 +03:00
## Borders
2021-04-29 01:39:02 +03:00
Adding borders is easy:
2021-04-28 23:26:04 +03:00
```go
2021-11-22 09:15:09 +03:00
// Add a purple, rectangular border
2021-04-28 23:26:04 +03:00
var style = lipgloss.NewStyle().
BorderStyle(lipgloss.NormalBorder()).
2021-04-29 01:39:02 +03:00
BorderForeground(lipgloss.Color("63"))
2021-04-28 23:26:04 +03:00
2021-04-29 01:39:02 +03:00
// Set a rounded, yellow-on-purple border to the top and left
2021-04-28 23:26:04 +03:00
var anotherStyle = lipgloss.NewStyle().
BorderStyle(lipgloss.RoundedBorder()).
2021-04-29 01:39:02 +03:00
BorderForeground(lipgloss.Color("228")).
BorderBackground(lipgloss.Color("63")).
2021-04-28 23:26:04 +03:00
BorderTop(true).
BorderLeft(true)
// Make your own border
var myCuteBorder = lipgloss.Border{
2021-04-29 01:27:08 +03:00
Top: "._.:*:",
Bottom: "._.:*:",
Left: "|*",
Right: "|*",
TopLeft: "*",
TopRight: "*",
BottomLeft: "*",
BottomRight: "*",
2021-04-28 23:26:04 +03:00
}
```
2021-04-29 01:39:02 +03:00
There are also shorthand functions for defining borders, which follow a similar
pattern to the margin and padding shorthand functions.
2021-04-28 23:26:04 +03:00
```go
// Add a thick border to the top and bottom
2021-04-29 01:39:02 +03:00
lipgloss.NewStyle().
Border(lipgloss.ThickBorder(), true, false)
2021-04-28 23:26:04 +03:00
2023-10-21 02:52:10 +03:00
// Add a double border to the top and left sides. Rules are set clockwise
2021-04-28 23:26:04 +03:00
// from top.
2021-04-29 01:39:02 +03:00
lipgloss.NewStyle().
Border(lipgloss.DoubleBorder(), true, false, false, true)
2021-04-28 23:26:04 +03:00
```
For more on borders see [the docs][docs].
2021-03-18 18:23:08 +03:00
## Copying Styles
2024-05-06 22:59:26 +03:00
Just use assignment:
2021-03-18 18:23:08 +03:00
```go
2024-05-06 22:59:26 +03:00
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
2021-03-18 18:23:08 +03:00
```
2024-05-01 21:26:50 +03:00
Since `Style` data structures contains only primitive types, assigning a style
2024-05-01 21:22:21 +03:00
to another effectively creates a new copy of the style without mutating the
original.
2021-03-18 18:23:08 +03:00
## Inheritance
Styles can inherit rules from other styles. When inheriting, only unset rules
2021-03-18 20:48:48 +03:00
on the receiver are inherited.
2021-03-18 18:23:08 +03:00
```go
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)
```
2021-03-31 17:24:58 +03:00
## Unsetting Rules
2021-03-18 18:23:08 +03:00
All rules can be unset:
```go
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
```
2021-03-31 06:00:40 +03:00
When a rule is unset, it won't be inherited or copied.
2021-03-18 18:23:08 +03:00
## Enforcing Rules
Sometimes, such as when developing a component, you want to make sure style
2021-04-03 14:43:37 +03:00
definitions respect their intended purpose in the UI. This is where `Inline`
2021-03-24 21:42:45 +03:00
and `MaxWidth` , and `MaxHeight` come in:
2021-03-18 18:23:08 +03:00
```go
2021-03-31 16:53:51 +03:00
// Force rendering onto a single line, ignoring margins, padding, and borders.
2022-10-03 20:45:30 +03:00
someStyle.Inline(true).Render("yadda yadda")
2021-03-18 18:23:08 +03:00
// Also limit rendering to five cells
2022-10-03 20:45:30 +03:00
someStyle.Inline(true).MaxWidth(5).Render("yadda yadda")
2021-03-24 21:42:45 +03:00
// Limit rendering to a 5x5 cell block
2022-10-03 20:45:30 +03:00
someStyle.MaxWidth(5).MaxHeight(5).Render("yadda yadda")
2021-03-18 18:23:08 +03:00
```
2023-07-24 19:42:34 +03:00
## Tabs
The tab character (`\t`) is rendered differently in different terminals (often
as 8 spaces, sometimes 4). Because of this inconsistency, Lip Gloss converts
tabs to 4 spaces at render time. This behavior can be changed on a per-style
basis, however:
```go
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
```
2021-03-18 18:23:08 +03:00
## Rendering
2022-10-03 20:45:30 +03:00
Generally, you just call the `Render(string...)` method on a `lipgloss.Style` :
2021-03-18 18:23:08 +03:00
```go
2023-03-08 22:51:26 +03:00
style := lipgloss.NewStyle().Bold(true).SetString("Hello,")
2022-10-03 20:45:30 +03:00
fmt.Println(style.Render("kitty.")) // Hello, kitty.
fmt.Println(style.Render("puppy.")) // Hello, puppy.
2021-03-18 18:23:08 +03:00
```
2022-10-03 20:45:30 +03:00
But you could also use the Stringer interface:
```go
2023-03-08 22:51:26 +03:00
var style = lipgloss.NewStyle().SetString("你好,猫咪。").Bold(true)
fmt.Println(style) // 你好,猫咪。
2022-10-03 20:45:30 +03:00
```
### Custom Renderers
2023-03-08 22:51:26 +03:00
Custom renderers allow you to render to a specific outputs. This is
particularly important when you want to render to different outputs and
correctly detect the color profile and dark background status for each, such as
in a server-client situation.
2021-03-18 18:23:08 +03:00
```go
2023-03-08 22:51:26 +03:00
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"})
2021-03-18 18:23:08 +03:00
2023-03-08 22:51:26 +03:00
// Render. The color profile and dark background state will be correctly detected.
io.WriteString(sess, style.Render("Heyyyyyyy"))
}
2021-03-18 18:23:08 +03:00
```
2023-03-08 22:51:26 +03:00
For an example on using a custom renderer over SSH with [Wish][wish] see the
[SSH example][ssh-example].
2021-04-29 01:39:02 +03:00
2021-04-28 22:49:08 +03:00
## Utilities
2021-03-18 18:23:08 +03:00
2021-11-22 09:15:09 +03:00
In addition to pure styling, Lip Gloss also ships with some utilities to help
2021-04-29 01:39:02 +03:00
assemble your layouts.
2021-04-28 22:49:08 +03:00
### Joining Paragraphs
2021-03-18 22:00:54 +03:00
2021-04-29 01:39:02 +03:00
Horizontally and vertically joining paragraphs is a cinch.
2021-03-18 22:00:54 +03:00
```go
// Horizontally join three paragraphs along their bottom edges
2021-06-16 04:43:11 +03:00
lipgloss.JoinHorizontal(lipgloss.Bottom, paragraphA, paragraphB, paragraphC)
2021-03-18 22:00:54 +03:00
// Vertically join two paragraphs along their center axes
2021-06-16 04:43:11 +03:00
lipgloss.JoinVertical(lipgloss.Center, paragraphA, paragraphB)
2021-03-18 22:08:18 +03:00
// Horizontally join three paragraphs, with the shorter ones aligning 20%
2021-03-31 05:43:48 +03:00
// from the top of the tallest
2021-06-16 04:43:11 +03:00
lipgloss.JoinHorizontal(0.2, paragraphA, paragraphB, paragraphC)
2021-03-18 22:00:54 +03:00
```
2021-04-28 22:58:18 +03:00
### Measuring Width and Height
Sometimes you’ ll want to know the width and height of text blocks when building
2021-04-29 01:39:02 +03:00
your layouts.
2021-04-28 22:58:18 +03:00
```go
2022-06-28 20:28:35 +03:00
// Render a block of text.
var style = lipgloss.NewStyle().
2021-04-28 22:58:18 +03:00
Width(40).
2022-06-28 20:28:35 +03:00
Padding(2)
2022-10-03 20:45:30 +03:00
var block string = style.Render(someLongString)
2021-04-28 22:58:18 +03:00
2021-11-22 09:15:09 +03:00
// Get the actual, physical dimensions of the text block.
2021-04-28 22:58:18 +03:00
width := lipgloss.Width(block)
height := lipgloss.Height(block)
// Here's a shorthand function.
w, h := lipgloss.Size(block)
```
2021-04-28 22:49:08 +03:00
### Placing Text in Whitespace
2021-03-31 05:43:48 +03:00
2021-04-28 22:58:18 +03:00
Sometimes you’ ll simply want to place a block of text in whitespace.
2021-03-31 05:43:48 +03:00
```go
// 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)
```
You can also style the whitespace. For details, see [the docs][docs].
2023-10-10 17:27:52 +03:00
### Rendering Tables
Lip Gloss ships with a table rendering sub-package.
```go
import "github.com/charmbracelet/lipgloss/table"
```
Define some rows of data.
```go
rows := [][]string{
{"Chinese", "您好", "你好"},
{"Japanese", "こんにちは", "やあ"},
{"Arabic", "أهلين", "أهلا"},
{"Russian", "Здравствуйте", "Привет"},
{"Spanish", "Hola", "¿Qué tal?"},
}
```
Use the table package to style and render the table.
```go
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?")
```
Print the table.
```go
fmt.Println(t)
```
![Table Example ](https://github.com/charmbracelet/lipgloss/assets/42545625/6e4b70c4-f494-45da-a467-bdd27df30d5d )
2023-10-12 14:30:51 +03:00
For more on tables see [the docs ](https://pkg.go.dev/github.com/charmbracelet/lipgloss?tab=doc ) and [examples ](https://github.com/charmbracelet/lipgloss/tree/master/examples/table ).
2021-04-28 22:49:08 +03:00
2024-05-01 21:22:21 +03:00
---
2021-03-31 05:43:48 +03:00
2023-05-23 21:58:52 +03:00
## FAQ
< details >
< summary >
Why are things misaligning? Why are borders at the wrong widths?
< / summary >
< p > This is most likely due to your locale and encoding, particularly with
regard to Chinese, Japanese, and Korean (for example, < code > zh_CN.UTF-8< / code >
or < code > ja_JP.UTF-8< / code > ). The most direct way to fix this is to set
< code > RUNEWIDTH_EASTASIAN=0< / code > in your environment.< / p >
< p > For details see < a href = "https://github.com/charmbracelet/lipgloss/issues/40" > https://github.com/charmbracelet/lipgloss/issues/40.< / a > < / p >
< / details >
< details >
< summary >
Why isn't Lip Gloss displaying colors?
< / summary >
< p > Lip Gloss automatically degrades colors to the best available option in the
given terminal, and if output's not a TTY it will remove color output entirely.
This is common when running tests, CI, or when piping output elsewhere.< / p >
< p > If necessary, you can force a color profile in your tests with
< a href = "https://pkg.go.dev/github.com/charmbracelet/lipgloss#SetColorProfile" > < code > SetColorProfile< / code > < / a > .< / p >
```go
import (
"github.com/charmbracelet/lipgloss"
"github.com/muesli/termenv"
)
lipgloss.SetColorProfile(termenv.TrueColor)
```
2024-05-01 21:22:21 +03:00
_Note:_ this option limits the flexibility of your application and can cause
2023-05-23 21:58:52 +03:00
ANSI escape codes to be output in cases where that might not be desired. Take
careful note of your use case and environment before choosing to force a color
profile.
2024-05-01 21:22:21 +03:00
2023-05-23 21:58:52 +03:00
< / details >
2021-03-31 05:43:48 +03:00
2021-04-03 04:50:32 +03:00
## What about [Bubble Tea][tea]?
2021-03-31 05:55:04 +03:00
2021-04-03 04:50:32 +03:00
Lip Gloss doesn’ t replace Bubble Tea. Rather, it is an excellent Bubble Tea
companion. It was designed to make assembling terminal user interface views as
2021-04-03 17:25:48 +03:00
simple and fun as possible so that you can focus on building your application
2021-04-03 04:50:32 +03:00
instead of concerning yourself with low-level layout details.
In simple terms, you can use Lip Gloss to help build your Bubble Tea views.
2021-03-31 05:55:04 +03:00
[tea]: https://github.com/charmbracelet/tea
2021-03-18 18:23:08 +03:00
## Under the Hood
Lip Gloss is built on the excellent [Termenv][termenv] and [Reflow][reflow]
libraries which deal with color and ANSI-aware text operations, respectively.
2021-03-31 17:24:58 +03:00
For many use cases Termenv and Reflow will be sufficient for your needs.
2021-03-18 18:23:08 +03:00
[termenv]: https://github.com/muesli/termenv
[reflow]: https://github.com/muesli/reflow
2021-03-18 22:00:54 +03:00
## Rendering Markdown
2021-03-31 05:43:48 +03:00
For a more document-centric rendering solution with support for things like
lists, tables, and syntax-highlighted code have a look at [Glamour][glamour],
the stylesheet-based Markdown renderer.
2021-03-18 22:00:54 +03:00
[glamour]: https://github.com/charmbracelet/glamour
2022-10-24 09:57:38 +03:00
## Feedback
2022-06-29 17:57:03 +03:00
2022-10-24 09:57:38 +03:00
We’ d love to hear your thoughts on this project. Feel free to drop us a note!
2022-06-29 17:57:03 +03:00
2024-05-01 21:22:21 +03:00
- [Twitter ](https://twitter.com/charmcli )
- [The Fediverse ](https://mastodon.social/@charmcli )
- [Discord ](https://charm.sh/chat )
2022-06-29 17:57:03 +03:00
2021-03-18 18:23:08 +03:00
## License
[MIT ](https://github.com/charmbracelet/lipgloss/raw/master/LICENSE )
2024-05-01 21:22:21 +03:00
---
2021-03-18 18:23:08 +03:00
Part of [Charm ](https://charm.sh ).
2022-06-29 17:55:26 +03:00
< a href = "https://charm.sh/" > < img alt = "The Charm logo" src = "https://stuff.charm.sh/charm-badge.jpg" width = "400" > < / a >
2021-03-18 18:23:08 +03:00
2021-03-18 22:00:54 +03:00
Charm热爱开源 • Charm loves open source
2021-03-31 05:43:48 +03:00
[docs]: https://pkg.go.dev/github.com/charmbracelet/lipgloss?tab=doc
2022-10-03 20:45:30 +03:00
[wish]: https://github.com/charmbracelet/wish
[ssh-example]: examples/ssh