From 30142733509b56a2fee9ce52d93a27f4411a0811 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Fri, 30 Aug 2024 17:12:07 -0400 Subject: [PATCH 01/32] feat: add adaptive color package This introduces a helper type `LightDark` that takes a boolean to determine which `Color(light, dark)` to choose from. The `adaptive` package is a helper package that uses the `lipgloss.LightDark` along with querying the terminal when the module is imported to choose the appropriate light-dark color. Example: ```go var ( light = "#0000ff" dark = "#ff0000" ) colorToUse := adaptive.Color(light, dark) // the terminal is queried before choosing the color fmt.Println(colorToUse) ``` --- adaptive/adaptive.go | 47 ++++++++++++++++++++++ adaptive/color.go | 11 +++++ adaptive/terminal.go | 95 ++++++++++++++++++++++++++++++++++++++++++++ color.go | 36 ++++++++++++++--- examples/go.mod | 14 +++++-- examples/go.sum | 18 +++++++-- go.mod | 7 +++- go.sum | 16 +++++++- 8 files changed, 228 insertions(+), 16 deletions(-) create mode 100644 adaptive/adaptive.go create mode 100644 adaptive/color.go create mode 100644 adaptive/terminal.go diff --git a/adaptive/adaptive.go b/adaptive/adaptive.go new file mode 100644 index 00000000..3c4794d1 --- /dev/null +++ b/adaptive/adaptive.go @@ -0,0 +1,47 @@ +package adaptive + +import ( + "os" + + "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/x/term" +) + +// Stdin, Stdout, and HasDarkBackground are the standard input, output, and +// default background color value to use. They can be overridden by the +// importing program. +var ( + Stdin = os.Stdin + Stdout = os.Stdout + HasDarkBackground = true +) + +// colorFn is the light-dark Lip Gloss color function to use to determine the +// appropriate color based on the terminal's background color. +// When a program imports this package, it will query the terminal's background +// color and use it to determine whether to use the light or dark color. +var colorFn lipgloss.LightDark + +func init() { + Query() +} + +// Query queries the terminal's background color and updates the color function +// accordingly. +func Query() { + colorFn = lipgloss.LightDark(func() bool { + state, err := term.MakeRaw(Stdin.Fd()) + if err != nil { + return HasDarkBackground + } + + defer term.Restore(Stdin.Fd(), state) //nolint:errcheck + + bg, err := queryBackgroundColor(Stdin, Stdout) + if err == nil { + return lipgloss.IsDarkColor(bg) + } + + return HasDarkBackground + }()) +} diff --git a/adaptive/color.go b/adaptive/color.go new file mode 100644 index 00000000..ac049263 --- /dev/null +++ b/adaptive/color.go @@ -0,0 +1,11 @@ +package adaptive + +import ( + "image/color" +) + +// Color returns the color that should be used based on the terminal's +// background color. +func Color(light, dark any) color.Color { + return colorFn.Color(light, dark) +} diff --git a/adaptive/terminal.go b/adaptive/terminal.go new file mode 100644 index 00000000..108d61d9 --- /dev/null +++ b/adaptive/terminal.go @@ -0,0 +1,95 @@ +package adaptive + +import ( + "image/color" + "io" + "time" + + "github.com/charmbracelet/x/ansi" + "github.com/charmbracelet/x/input" +) + +// queryBackgroundColor queries the terminal for the background color. +// If the terminal does not support querying the background color, nil is +// returned. +// +// Note: you will need to set the input to raw mode before calling this +// function. +// +// state, _ := term.MakeRaw(in.Fd()) +// defer term.Restore(in.Fd(), state) +// +// copied from x/term@v0.1.3. +func queryBackgroundColor(in io.Reader, out io.Writer) (c color.Color, err error) { + // nolint: errcheck + err = queryTerminal(in, out, defaultQueryTimeout, + func(events []input.Event) bool { + for _, e := range events { + switch e := e.(type) { + case input.BackgroundColorEvent: + c = e.Color + continue // we need to consume the next DA1 event + case input.PrimaryDeviceAttributesEvent: + return false + } + } + return true + }, ansi.RequestBackgroundColor+ansi.RequestPrimaryDeviceAttributes) + return +} + +const defaultQueryTimeout = time.Second * 2 + +// queryTerminalFilter is a function that filters input events using a type +// switch. If false is returned, the QueryTerminal function will stop reading +// input. +type queryTerminalFilter func(events []input.Event) bool + +// queryTerminal queries the terminal for support of various features and +// returns a list of response events. +// Most of the time, you will need to set stdin to raw mode before calling this +// function. +// Note: This function will block until the terminal responds or the timeout +// is reached. +// copied from x/term@v0.1.3. +func queryTerminal( + in io.Reader, + out io.Writer, + timeout time.Duration, + filter queryTerminalFilter, + query string, +) error { + rd, err := input.NewDriver(in, "", 0) + if err != nil { + return err + } + + defer rd.Close() // nolint: errcheck + + done := make(chan struct{}, 1) + defer close(done) + go func() { + select { + case <-done: + case <-time.After(timeout): + rd.Cancel() + } + }() + + if _, err := io.WriteString(out, query); err != nil { + return err + } + + for { + events, err := rd.ReadEvents() + if err != nil { + return err + } + + if !filter(events) { + break + } + } + + return nil +} diff --git a/color.go b/color.go index d5f39838..78237f60 100644 --- a/color.go +++ b/color.go @@ -1,6 +1,7 @@ package lipgloss import ( + "fmt" "image/color" "strconv" @@ -54,12 +55,13 @@ func (n NoColor) RGBA() (r, g, b, a uint32) { // ansiColor := lipgloss.Color(21) // hexColor := lipgloss.Color("#0000ff") // uint32Color := lipgloss.Color(0xff0000) -func Color[T string | int](c T) color.Color { - var col color.Color = noColor - switch c := any(c).(type) { +func Color(c any) color.Color { + switch c := c.(type) { + case nil: + return noColor case string: if len(c) == 0 { - return col + return noColor } if h, err := colorful.Hex(c); err == nil { return h @@ -71,6 +73,7 @@ func Color[T string | int](c T) color.Color { } return ansi.TrueColor(i) } + return noColor case int: if c < 16 { return ansi.BasicColor(c) @@ -78,8 +81,10 @@ func Color[T string | int](c T) color.Color { return ansi.ExtendedColor(c) } return ansi.TrueColor(c) + case color.Color: + return c } - return col + return Color(fmt.Sprint(c)) } // RGBColor is a color specified by red, green, and blue values. @@ -107,6 +112,27 @@ func (c RGBColor) RGBA() (r, g, b, a uint32) { // colorB := lipgloss.ANSIColor(134) type ANSIColor = ansi.ExtendedColor +// LightDark is a helper type that can be used to specify colors that should be +// used based on the terminal's background color. +// +// Example usage: +// +// useDark := lipgloss.LightDark(true) +// light := "#0000ff" +// dark := "#ff0000" +// colorToUse := useDark.Color(light, dark) +// fmt.Println(colorToUse) +type LightDark bool + +// Color returns the color that should be used based on the terminal's +// background color. +func (a LightDark) Color(light, dark any) color.Color { + if bool(a) { + return Color(dark) + } + return Color(light) +} + // IsDarkColor returns whether the given color is dark. // // Example usage: diff --git a/examples/go.mod b/examples/go.mod index 15b2609c..ad4f4945 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -6,13 +6,13 @@ replace github.com/charmbracelet/lipgloss => ../ replace github.com/charmbracelet/lipgloss/list => ../list +replace github.com/charmbracelet/lipgloss/adaptive => ../adaptive + require ( github.com/charmbracelet/lipgloss v0.11.0 github.com/charmbracelet/ssh v0.0.0-20240401141849-854cddfa2917 github.com/charmbracelet/wish v1.4.0 - github.com/creack/pty v1.1.21 github.com/lucasb-eyer/go-colorful v1.2.0 - github.com/muesli/termenv v0.15.2 golang.org/x/term v0.21.0 ) @@ -22,10 +22,14 @@ require ( github.com/charmbracelet/bubbletea v0.25.0 // indirect github.com/charmbracelet/keygen v0.5.0 // indirect github.com/charmbracelet/log v0.4.0 // indirect - github.com/charmbracelet/x/ansi v0.1.4 // indirect + github.com/charmbracelet/x/ansi v0.2.3 // indirect github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651 // indirect github.com/charmbracelet/x/exp/term v0.0.0-20240328150354-ab9afc214dfd // indirect + github.com/charmbracelet/x/input v0.2.0 // indirect + github.com/charmbracelet/x/term v0.2.0 // indirect github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect + github.com/creack/pty v1.1.21 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-localereader v0.0.1 // indirect @@ -33,10 +37,12 @@ require ( github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.15.2 // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.21.0 // indirect + golang.org/x/sys v0.24.0 // indirect golang.org/x/text v0.14.0 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index 72eaeba8..01386b0b 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -13,17 +13,24 @@ github.com/charmbracelet/ssh v0.0.0-20240401141849-854cddfa2917 h1:NZKjJ7d/pzk/A github.com/charmbracelet/ssh v0.0.0-20240401141849-854cddfa2917/go.mod h1:8/Ve8iGRRIGFM1kepYfRF2pEOF5Y3TEZYoJaA54228U= github.com/charmbracelet/wish v1.4.0 h1:pL1uVP/YuYgJheHEj98teZ/n6pMYnmlZq/fcHvomrfc= github.com/charmbracelet/wish v1.4.0/go.mod h1:ew4/MjJVfW/akEO9KmrQHQv1F7bQRGscRMrA+KtovTk= -github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM= -github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= +github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651 h1:3RXpZWGWTOeVXCTv0Dnzxdv/MhNUkBfEcbaTY0zrTQI= github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0= +github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a h1:G99klV19u0QnhiizODirwVksQB91TJKV/UaTnACcG30= github.com/charmbracelet/x/exp/term v0.0.0-20240328150354-ab9afc214dfd h1:HqBjkSFXXfW4IgX3TMKipWoPEN08T3Pi4SA/3DLss/U= github.com/charmbracelet/x/exp/term v0.0.0-20240328150354-ab9afc214dfd/go.mod h1:6GZ13FjIP6eOCqWU4lqgveGnYxQo9c3qBzHPeFu4HBE= +github.com/charmbracelet/x/input v0.2.0 h1:1Sv+y/flcqUfUH2PXNIDKDIdT2G8smOnGOgawqhwy8A= +github.com/charmbracelet/x/input v0.2.0/go.mod h1:KUSFIS6uQymtnr5lHVSOK9j8RvwTD4YHnWnzJUYnd/M= +github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= +github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= @@ -49,16 +56,19 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= diff --git a/go.mod b/go.mod index 89abbd79..53e5803e 100644 --- a/go.mod +++ b/go.mod @@ -10,14 +10,19 @@ require ( github.com/aymanbagabas/go-udiff v0.2.0 github.com/charmbracelet/x/ansi v0.2.3 github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a + github.com/charmbracelet/x/input v0.2.0 + github.com/charmbracelet/x/term v0.2.0 github.com/lucasb-eyer/go-colorful v1.2.0 github.com/muesli/termenv v0.15.2 github.com/rivo/uniseg v0.4.7 - golang.org/x/sys v0.19.0 + golang.org/x/sys v0.24.0 ) require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect ) diff --git a/go.sum b/go.sum index 660066b6..3734b92b 100644 --- a/go.sum +++ b/go.sum @@ -6,17 +6,29 @@ github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqo github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a h1:G99klV19u0QnhiizODirwVksQB91TJKV/UaTnACcG30= github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/charmbracelet/x/input v0.2.0 h1:1Sv+y/flcqUfUH2PXNIDKDIdT2G8smOnGOgawqhwy8A= +github.com/charmbracelet/x/input v0.2.0/go.mod h1:KUSFIS6uQymtnr5lHVSOK9j8RvwTD4YHnWnzJUYnd/M= +github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= +github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= From dbc553889be8ab0f538c70da4931299633f3e26f Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Fri, 11 Oct 2024 15:06:47 -0400 Subject: [PATCH 02/32] chore: miscellaneous lint work --- adaptive/terminal.go | 7 ++++--- color.go | 11 ++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/adaptive/terminal.go b/adaptive/terminal.go index 108d61d9..27c530e2 100644 --- a/adaptive/terminal.go +++ b/adaptive/terminal.go @@ -1,6 +1,7 @@ package adaptive import ( + "fmt" "image/color" "io" "time" @@ -61,10 +62,10 @@ func queryTerminal( ) error { rd, err := input.NewDriver(in, "", 0) if err != nil { - return err + return fmt.Errorf("could not create driver: %w", err) } - defer rd.Close() // nolint: errcheck + defer rd.Close() //nolint: errcheck done := make(chan struct{}, 1) defer close(done) @@ -77,7 +78,7 @@ func queryTerminal( }() if _, err := io.WriteString(out, query); err != nil { - return err + return fmt.Errorf("could not write query: %w", err) } for { diff --git a/color.go b/color.go index 78237f60..0561a639 100644 --- a/color.go +++ b/color.go @@ -66,9 +66,9 @@ func Color(c any) color.Color { if h, err := colorful.Hex(c); err == nil { return h } else if i, err := strconv.Atoi(c); err == nil { - if i < 16 { + if i < 16 { //nolint:gomnd return ansi.BasicColor(i) - } else if i < 256 { + } else if i < 256 { //nolint:gomnd return ansi.ExtendedColor(i) } return ansi.TrueColor(i) @@ -97,9 +97,10 @@ type RGBColor struct { // RGBA returns the RGBA value of this color. This satisfies the Go Color // interface. func (c RGBColor) RGBA() (r, g, b, a uint32) { - r |= uint32(c.R) << 8 - g |= uint32(c.G) << 8 - b |= uint32(c.B) << 8 + const shift = 8 + r |= uint32(c.R) << shift + g |= uint32(c.G) << shift + b |= uint32(c.B) << shift a = 0xFFFF //nolint:gomnd return } From c0da46c39516bde9d2b5ac7812f7d84da1b8edbb Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Fri, 11 Oct 2024 15:24:12 -0400 Subject: [PATCH 03/32] chore: rename LightDark to Adapt per @bashbunni's acute suggestion --- adaptive/adaptive.go | 4 ++-- color.go | 40 +++++++++++++++++++++++++++------------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/adaptive/adaptive.go b/adaptive/adaptive.go index 3c4794d1..23db9c42 100644 --- a/adaptive/adaptive.go +++ b/adaptive/adaptive.go @@ -20,7 +20,7 @@ var ( // appropriate color based on the terminal's background color. // When a program imports this package, it will query the terminal's background // color and use it to determine whether to use the light or dark color. -var colorFn lipgloss.LightDark +var colorFn lipgloss.Adapt func init() { Query() @@ -29,7 +29,7 @@ func init() { // Query queries the terminal's background color and updates the color function // accordingly. func Query() { - colorFn = lipgloss.LightDark(func() bool { + colorFn = lipgloss.Adapt(func() bool { state, err := term.MakeRaw(Stdin.Fd()) if err != nil { return HasDarkBackground diff --git a/color.go b/color.go index 0561a639..0a87ba4f 100644 --- a/color.go +++ b/color.go @@ -113,36 +113,50 @@ func (c RGBColor) RGBA() (r, g, b, a uint32) { // colorB := lipgloss.ANSIColor(134) type ANSIColor = ansi.ExtendedColor -// LightDark is a helper type that can be used to specify colors that should be -// used based on the terminal's background color. +// Adapt is a simple helper type that can be used to choose the appropriate +// color based on whether the terminal has a light or dark background. // -// Example usage: +// adaptive := lipgloss.Adapt(hasDarkBackground) +// theRightColor := adaptive.Color("#0000ff", "#ff0000") +// +// In practice, there are slightly different workflows between Bubble Tea and +// Lip Gloss standalone. +// +// In Bubble Tea listen for tea.BackgroundColorMessage, which automatically +// flows through Update on start, and whenever the background color changes: +// +// case tea.BackgroundColorMessage: +// m.hasDarkBackground = msg.IsDark() +// +// Later, when you're rendering: +// +// adaptive := lipgloss.Adapt(m.hasDarkBackground) +// myHotColor := adaptive.Color("#ff0000", "#0000ff") +// +// In standalone Lip Gloss, the workflow is simpler: // -// useDark := lipgloss.LightDark(true) -// light := "#0000ff" -// dark := "#ff0000" -// colorToUse := useDark.Color(light, dark) -// fmt.Println(colorToUse) -type LightDark bool +// ... +type Adapt bool // Color returns the color that should be used based on the terminal's // background color. -func (a LightDark) Color(light, dark any) color.Color { +func (a Adapt) Color(light, dark any) color.Color { if bool(a) { return Color(dark) } return Color(light) } -// IsDarkColor returns whether the given color is dark. +// IsDarkColor returns whether the given color is dark (based on the luminance +// portion of the color as interpreted as HSL). // // Example usage: // // color := lipgloss.Color("#0000ff") // if lipgloss.IsDarkColor(color) { -// fmt.Println("It's dark!") +// fmt.Println("It's dark! I love darkness!") // } else { -// fmt.Println("It's light!") +// fmt.Println("It's light! Cover your eyes!") // } func IsDarkColor(c color.Color) bool { col, ok := colorful.MakeColor(c) From 7e7e96ab3036d59d89837fa888e1afaf1a6793d6 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Fri, 11 Oct 2024 15:28:44 -0400 Subject: [PATCH 04/32] chore(lint): mute integer conversion warnings (G115) --- color.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/color.go b/color.go index 0a87ba4f..ebae78b0 100644 --- a/color.go +++ b/color.go @@ -67,20 +67,20 @@ func Color(c any) color.Color { return h } else if i, err := strconv.Atoi(c); err == nil { if i < 16 { //nolint:gomnd - return ansi.BasicColor(i) + return ansi.BasicColor(i) //nolint:gosec } else if i < 256 { //nolint:gomnd - return ansi.ExtendedColor(i) + return ansi.ExtendedColor(i) //nolint:gosec } - return ansi.TrueColor(i) + return ansi.TrueColor(i) //nolint:gosec } return noColor case int: if c < 16 { - return ansi.BasicColor(c) + return ansi.BasicColor(c) //nolint:gosec } else if c < 256 { - return ansi.ExtendedColor(c) + return ansi.ExtendedColor(c) //nolint:gosec } - return ansi.TrueColor(c) + return ansi.TrueColor(c) //nolint:gosec case color.Color: return c } From 5d63b45ccc8118a73826a17ae609d843e1b37bd4 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Fri, 11 Oct 2024 15:50:34 -0400 Subject: [PATCH 05/32] chore: make adaptive color workflow more explicit --- adaptive/adaptive.go | 47 ------------------------ adaptive/color.go | 11 ------ color.go | 4 ++- query.go | 56 +++++++++++++++++++++++++++++ adaptive/terminal.go => terminal.go | 2 +- 5 files changed, 60 insertions(+), 60 deletions(-) delete mode 100644 adaptive/adaptive.go delete mode 100644 adaptive/color.go create mode 100644 query.go rename adaptive/terminal.go => terminal.go (99%) diff --git a/adaptive/adaptive.go b/adaptive/adaptive.go deleted file mode 100644 index 23db9c42..00000000 --- a/adaptive/adaptive.go +++ /dev/null @@ -1,47 +0,0 @@ -package adaptive - -import ( - "os" - - "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/x/term" -) - -// Stdin, Stdout, and HasDarkBackground are the standard input, output, and -// default background color value to use. They can be overridden by the -// importing program. -var ( - Stdin = os.Stdin - Stdout = os.Stdout - HasDarkBackground = true -) - -// colorFn is the light-dark Lip Gloss color function to use to determine the -// appropriate color based on the terminal's background color. -// When a program imports this package, it will query the terminal's background -// color and use it to determine whether to use the light or dark color. -var colorFn lipgloss.Adapt - -func init() { - Query() -} - -// Query queries the terminal's background color and updates the color function -// accordingly. -func Query() { - colorFn = lipgloss.Adapt(func() bool { - state, err := term.MakeRaw(Stdin.Fd()) - if err != nil { - return HasDarkBackground - } - - defer term.Restore(Stdin.Fd(), state) //nolint:errcheck - - bg, err := queryBackgroundColor(Stdin, Stdout) - if err == nil { - return lipgloss.IsDarkColor(bg) - } - - return HasDarkBackground - }()) -} diff --git a/adaptive/color.go b/adaptive/color.go deleted file mode 100644 index ac049263..00000000 --- a/adaptive/color.go +++ /dev/null @@ -1,11 +0,0 @@ -package adaptive - -import ( - "image/color" -) - -// Color returns the color that should be used based on the terminal's -// background color. -func Color(light, dark any) color.Color { - return colorFn.Color(light, dark) -} diff --git a/color.go b/color.go index ebae78b0..246091f9 100644 --- a/color.go +++ b/color.go @@ -135,7 +135,9 @@ type ANSIColor = ansi.ExtendedColor // // In standalone Lip Gloss, the workflow is simpler: // -// ... +// hasDarkBG, _ := lipgloss.HasDarkBackground(os.Stdin, os.Stdout) +// adaptive := lipgloss.Adapt(hasDarkBG) +// myHotColor := adaptive.Color("#ff0000", "#0000ff") type Adapt bool // Color returns the color that should be used based on the terminal's diff --git a/query.go b/query.go new file mode 100644 index 00000000..c9b91c69 --- /dev/null +++ b/query.go @@ -0,0 +1,56 @@ +package lipgloss + +import ( + "image/color" + "os" + + "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/x/term" +) + +// BackgroundColor queries the terminal's background color. Typically, you'll +// want to query against stdin and either stdout or stderr, depending on what +// you're writing to. +// +// This function is intended for standalone Lip Gloss use only. If you're using +// Bubble Tea, listen for tea.BackgroundColorMsg in your update function. +func BackgroundColor(in *os.File, out *os.File) (color.Color, error) { + state, err := term.MakeRaw(in.Fd()) + if err != nil { + return nil, err + } + + defer term.Restore(in.Fd(), state) //nolint:errcheck + + bg, err := queryBackgroundColor(in, out) + if err == nil { + return nil, err + } + + return bg, nil +} + +// HasDarkBackground detects whether the terminal has a light or dark +// background. It's a convenience function that wraps [BackgroundColor] and +// [lipgloss.IsDarkColor]. +// +// Typically, you'll want to query against stdin and either stdout or stderr +// depending on what you're writing to. +// +// hasDarkBG, _ := HasDarkBackground(os.Stdin, os.Stdout) +// adaptive := Adapt(hasDarkBG) +// myHotColor := Color("#ff0000", "#0000ff") +// +// This is intedded for use in standalone Lip Gloss only. In Bubble Tea, listen +// for tea.BackgroundColorMsg in your update function. +// +// case tea.BackgroundColorMsg: +// hasDarkBackground = msg.IsDark() +func HasDarkBackground(in *os.File, out *os.File) (bool, error) { + bg, err := BackgroundColor(in, out) + if err != nil { + return false, err + } + + return lipgloss.IsDarkColor(bg), nil +} diff --git a/adaptive/terminal.go b/terminal.go similarity index 99% rename from adaptive/terminal.go rename to terminal.go index 27c530e2..3ddf8a87 100644 --- a/adaptive/terminal.go +++ b/terminal.go @@ -1,4 +1,4 @@ -package adaptive +package lipgloss import ( "fmt" From ea8092f0582667e77cd13bee54f8199ece8cf0bb Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 10:09:14 -0400 Subject: [PATCH 06/32] fix(adaptive): return dark background by default Co-authored-by: Ayman Bagabas --- query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query.go b/query.go index c9b91c69..8be027de 100644 --- a/query.go +++ b/query.go @@ -49,7 +49,7 @@ func BackgroundColor(in *os.File, out *os.File) (color.Color, error) { func HasDarkBackground(in *os.File, out *os.File) (bool, error) { bg, err := BackgroundColor(in, out) if err != nil { - return false, err + return true, err } return lipgloss.IsDarkColor(bg), nil From d6e77aab2d4b6a848ded4fbd3d36e23f56dc0d3b Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 10:13:53 -0400 Subject: [PATCH 07/32] fix(adaptive): fix GoDoc Co-authored-by: Ayman Bagabas --- color.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/color.go b/color.go index 246091f9..4e9e4385 100644 --- a/color.go +++ b/color.go @@ -122,10 +122,10 @@ type ANSIColor = ansi.ExtendedColor // In practice, there are slightly different workflows between Bubble Tea and // Lip Gloss standalone. // -// In Bubble Tea listen for tea.BackgroundColorMessage, which automatically +// In Bubble Tea listen for tea.BackgroundColorMsg, which automatically // flows through Update on start, and whenever the background color changes: // -// case tea.BackgroundColorMessage: +// case tea.BackgroundColorMsg: // m.hasDarkBackground = msg.IsDark() // // Later, when you're rendering: From 790b508a7cd21751d7e9b578dbe89e83485b59ce Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 13:09:03 -0400 Subject: [PATCH 08/32] fix: background color detect Co-authored with @aymanbagabas --- query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query.go b/query.go index 8be027de..0e13db12 100644 --- a/query.go +++ b/query.go @@ -23,7 +23,7 @@ func BackgroundColor(in *os.File, out *os.File) (color.Color, error) { defer term.Restore(in.Fd(), state) //nolint:errcheck bg, err := queryBackgroundColor(in, out) - if err == nil { + if err != nil { return nil, err } From d8ccecc695fc729a75b389dc85e3947d9d3c0f4f Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 14:11:08 -0400 Subject: [PATCH 09/32] chore: improve errors in background color query --- go.mod | 3 ++- go.sum | 6 ++++-- query.go | 10 +++++++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 53e5803e..cad77f11 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,8 @@ go 1.18 require ( github.com/aymanbagabas/go-udiff v0.2.0 - github.com/charmbracelet/x/ansi v0.2.3 + github.com/charmbracelet/colorprofile v0.1.2 + github.com/charmbracelet/x/ansi v0.3.2 github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a github.com/charmbracelet/x/input v0.2.0 github.com/charmbracelet/x/term v0.2.0 diff --git a/go.sum b/go.sum index 3734b92b..4325c39f 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,10 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= -github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= -github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/colorprofile v0.1.2 h1:nuB1bd/yAExT4fkcZvpqtQ2N5/8cJHSRIKb6CzT7lAM= +github.com/charmbracelet/colorprofile v0.1.2/go.mod h1:1htIKZYeI4TQs+OykPvpuBTUbUJxBYeSYBDIZuejMj0= +github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY= +github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a h1:G99klV19u0QnhiizODirwVksQB91TJKV/UaTnACcG30= github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/charmbracelet/x/input v0.2.0 h1:1Sv+y/flcqUfUH2PXNIDKDIdT2G8smOnGOgawqhwy8A= diff --git a/query.go b/query.go index 0e13db12..c510950e 100644 --- a/query.go +++ b/query.go @@ -1,10 +1,11 @@ package lipgloss import ( + "errors" + "fmt" "image/color" "os" - "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/x/term" ) @@ -49,8 +50,11 @@ func BackgroundColor(in *os.File, out *os.File) (color.Color, error) { func HasDarkBackground(in *os.File, out *os.File) (bool, error) { bg, err := BackgroundColor(in, out) if err != nil { - return true, err + return true, fmt.Errorf("could not detect background color: %w", err) + } + if bg == nil { + return true, errors.New("detected background color is nil") } - return lipgloss.IsDarkColor(bg), nil + return IsDarkColor(bg), nil } From 01159e4df60361c0e0b679a63ede5a59f4d8f7c8 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 14:12:39 -0400 Subject: [PATCH 10/32] chore: add functions for printing colors with automatic downsampling --- standalone/write.go | 104 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 standalone/write.go diff --git a/standalone/write.go b/standalone/write.go new file mode 100644 index 00000000..5789a57f --- /dev/null +++ b/standalone/write.go @@ -0,0 +1,104 @@ +package standalone + +import ( + "fmt" + "io" + "os" + + "github.com/charmbracelet/colorprofile" + "github.com/charmbracelet/lipgloss" +) + +var ( + Writer = colorprofile.NewWriter(os.Stdout, os.Environ()) +) + +// Println to stdout, automatically downsampling colors when necessary, ending +// with a trailing newline. +// +// Example: +// +// str := lipgloss.NewStyle(). +// Foreground(lipgloss.Color("#6a00ff")). +// Render("breakfast") +// +// Println("Time for a", str, "sandwich!") +func Println(v ...interface{}) (n int, err error) { + return fmt.Fprintln(Writer, v...) +} + +// Print formatted text to stdout, automatically downsampling colors when +// necessary. +// +// Example: +// +// str := lipgloss.NewStyle(). +// Foreground(lipgloss.Color("#6a00ff")). +// Render("knuckle") +// +// Printf("Time for a %s sandwich!\n", str) +func Printf(format string, v ...interface{}) (n int, err error) { + return fmt.Fprintf(Writer, format, v...) +} + +// Print to stdout, automatically downsampling colors when necessary. +// +// Example: +// +// str := lipgloss.NewStyle(). +// Foreground(lipgloss.Color("#6a00ff")). +// Render("Who wants marmalade?\n") +// +// Print(str) +func Print(v ...interface{}) (n int, err error) { + return fmt.Fprint(Writer, v...) +} + +// Fprint pritnts to the given writer, automatically downsampling colors when +// necessary. +// +// Example: +// +// str := lipgloss.NewStyle(). +// Foreground(lipgloss.Color("#6a00ff")). +// Render("guzzle") +// +// Fprint(os.Stderr, "I %s horchata pretty much all the time.\n", str) +func Fprint(w io.Writer, v ...interface{}) (n int, err error) { + w = colorprofile.NewWriter(w, os.Environ()) + return fmt.Fprint(w, v...) +} + +// Fprint pritnts to the given writer, automatically downsampling colors when +// necessary, and ending with a trailing newline. +// +// Example: +// +// str := lipgloss.NewStyle(). +// Foreground(lipgloss.Color("#6a00ff")). +// Render("Sandwich time!") +// +// Fprintln(os.Stderr, str) +func Fprintln(w io.Writer, v ...interface{}) (n int, err error) { + w = colorprofile.NewWriter(w, os.Environ()) + return fmt.Fprintln(w, v...) +} + +// Fprintf prints text to a writer, against the given format, automatically +// downsampling colors when necessary. +// +// Example: +// +// str := lipgloss.NewStyle(). +// Foreground(lipgloss.Color("#6a00ff")). +// Render("artichokes") +// +// Fprintf(os.Stderr, "I really love %s!\n", food) +func Fprintf(w io.Writer, format string, v ...interface{}) (n int, err error) { + return fmt.Fprintf(colorprofile.NewWriter(w, os.Environ()), format, v...) +} + +// HasDarkBackground returns whether or not the terminal has a dark background. +func HasDarkBackground() (bool, error) { + return lipgloss.HasDarkBackground(os.Stdin, os.Stdout) +} From dfd38cedd2faafce3ff0cafd73bb9dffabe70db5 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 15:03:16 -0400 Subject: [PATCH 11/32] chore: remove rogue logfile --- examples/debug.txt | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 examples/debug.txt diff --git a/examples/debug.txt b/examples/debug.txt deleted file mode 100644 index 43478688..00000000 --- a/examples/debug.txt +++ /dev/null @@ -1,4 +0,0 @@ -2024/05/09 16:27:51 Init Color profile: TrueColor -2024/05/09 16:27:51 NoColor env: true -2024/05/09 16:27:51 Color profile: Ascii -2024/05/09 16:27:51 Has light background: false From 95516629d92e97b5482512763258fb6286b40054 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 15:08:22 -0400 Subject: [PATCH 12/32] docs(examples): add v2 adaptive color examples --- examples/adaptive/bubbletea/main.go | 150 +++++++++++++++++++++++++++ examples/adaptive/standalone/main.go | 68 ++++++++++++ 2 files changed, 218 insertions(+) create mode 100644 examples/adaptive/bubbletea/main.go create mode 100644 examples/adaptive/standalone/main.go diff --git a/examples/adaptive/bubbletea/main.go b/examples/adaptive/bubbletea/main.go new file mode 100644 index 00000000..85909dc5 --- /dev/null +++ b/examples/adaptive/bubbletea/main.go @@ -0,0 +1,150 @@ +package main + +import ( + "fmt" + "os" + + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/lipgloss" +) + +// Style definitions. +type styles struct { + frame, + paragraph, + text, + keyword, + activeButton, + inactiveButton lipgloss.Style +} + +// Styles are initialized based on the background color of the terminal. +func newStyles(backgroundIsDark bool) (s *styles) { + s = new(styles) + + // Create a new helper function for choosing either a light or dark color + // based on the detected background color. + adaptive := lipgloss.Adapt(backgroundIsDark) + + // Define some styles. adaptive.Color() can be used to choose the + // appropriate light or dark color based on the detected background color. + s.frame = lipgloss.NewStyle(). + Border(lipgloss.RoundedBorder()). + BorderForeground(adaptive.Color("#0000ff", "#6200ff")). + Padding(1, 3). + Margin(1, 3) + s.paragraph = lipgloss.NewStyle(). + Width(40). + MarginBottom(1). + Align(lipgloss.Center) + s.text = lipgloss.NewStyle(). + Foreground(adaptive.Color("#0000ff", "#bdbdbd")) + s.keyword = lipgloss.NewStyle(). + Foreground(adaptive.Color("#0000ff", "#04b87c")). + Bold(true) + + // You can also use octal format for colors, i.e 0x#ff38ec. + s.activeButton = lipgloss.NewStyle(). + Padding(0, 3). + Background(lipgloss.Color(0xf347ff)). + Foreground(lipgloss.Color(0xfaffcc)) + s.inactiveButton = s.activeButton. + Background(lipgloss.Color(0x545454)) + return s +} + +type model struct { + styles *styles + yes bool + chosen bool +} + +func (m model) Init() (tea.Model, tea.Cmd) { + // Query for the background color on start. + return m, tea.BackgroundColor +} + +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + + // Bubble Tea automatically detects the background color on start. We + // listen for the response here, then initialize our styles accordingly. + case tea.BackgroundColorMsg: + m.styles = newStyles(msg.IsDark()) + return m, nil + + case tea.KeyPressMsg: + switch msg.String() { + case "q", "esc", "ctrl+c": + return m, tea.Quit + case "enter": + m.chosen = true + return m, tea.Quit + case "left", "right", "h", "l": + m.yes = !m.yes + case "y": + m.yes = true + m.chosen = true + return m, tea.Quit + case "n": + m.yes = false + m.chosen = true + return m, tea.Quit + } + } + + return m, nil +} + +func (m model) View() string { + if m.styles == nil { + // We haven't received tea.BackgroundColorMsg yet. Don't worry, it'll + // be here in a flash. + return "" + } + if m.chosen { + // We're about to exit, so wipe the UI. + return "" + } + + var ( + s = m.styles + y = "Yes" + n = "No" + ) + + if m.yes { + y = s.activeButton.Render(y) + n = s.inactiveButton.Render(n) + } else { + y = s.inactiveButton.Render(y) + n = s.activeButton.Render(n) + } + + return s.frame.Render( + lipgloss.JoinVertical(lipgloss.Center, + s.paragraph.Render( + s.text.Render("Are you sure you want to eat that ")+ + s.keyword.Render("moderatly ripe")+ + s.text.Render(" banana?"), + ), + y+" "+n, + ), + ) +} + +func main() { + m, err := tea.NewProgram(model{}).Run() + if err != nil { + fmt.Fprintf(os.Stderr, "Uh oh: %v", err) + os.Exit(1) + } + + if m := m.(model); m.chosen { + if m.yes { + fmt.Println("Are you sure? It's not ripe yet.") + } else { + fmt.Println("Well, alright. It was probably good, though.") + } + } +} diff --git a/examples/adaptive/standalone/main.go b/examples/adaptive/standalone/main.go new file mode 100644 index 00000000..6f7c1038 --- /dev/null +++ b/examples/adaptive/standalone/main.go @@ -0,0 +1,68 @@ +// This is an example showing how to work with colors when using Lip Gloss +// as a standalone package, i.e. outside of Bubble Tea. +package main + +import ( + "fmt" + "os" + + "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/standalone" +) + +func main() { + // Query for the background color. We only need to do this once, and only + // when using Lip Gloss standalone. + // + // In Bubble Tea listen for tea.BackgroundColorMsg in your Update. + hasDarkBG, err := lipgloss.HasDarkBackground(os.Stdin, os.Stdout) + if err != nil { + fmt.Fprintf(os.Stderr, "Could not detect background color: %v\n", err) + os.Exit(1) + } + + // Create a new helper function for choosing either a light or dark color + // based on the detected background color. + adaptive := lipgloss.Adapt(hasDarkBG) + + // Define some styles. adaptive.Color() can be used to choose the + // appropriate light or dark color based on the detected background color. + frameStyle := lipgloss.NewStyle(). + Border(lipgloss.RoundedBorder()). + BorderForeground(adaptive.Color("#0000ff", "#6200ff")). + Padding(1, 3). + Margin(1, 3) + paragraphStyle := lipgloss.NewStyle(). + Width(40). + MarginBottom(1). + Align(lipgloss.Center) + textStyle := lipgloss.NewStyle(). + Foreground(adaptive.Color("#0000ff", "#bdbdbd")) + keywordStyle := lipgloss.NewStyle(). + Foreground(adaptive.Color("#0000ff", "#04b87c")). + Bold(true) + + // You can also use octal format for colors, i.e 0x#ff38ec. + activeButton := lipgloss.NewStyle(). + Padding(0, 3). + Background(lipgloss.Color(0xf347ff)). + Foreground(lipgloss.Color(0xfaffcc)) + inactiveButton := activeButton. + Background(lipgloss.Color(0x545454)) + + // Build layout. + text := paragraphStyle.Render( + textStyle.Render("Are you sure you want to eat that ") + + keywordStyle.Render("moderatly ripe") + + textStyle.Render(" banana?"), + ) + buttons := activeButton.Render("Yes") + " " + inactiveButton.Render("No") + block := frameStyle.Render( + lipgloss.JoinVertical(lipgloss.Center, text, buttons), + ) + + // Print the block to stdout. It's important to use the standalone package + // to ensure that colors are downsampled correctly. If output isn't a + // TTY (i.e. we're logging to a file) colors will be stripped entirely. + standalone.Println(block) +} From b423a325c8c8d06de26c137eeb1f026f940db27c Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 15:40:34 -0400 Subject: [PATCH 13/32] chore: cleanup writer implementations --- standalone/write.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/standalone/write.go b/standalone/write.go index 5789a57f..80bb1e8d 100644 --- a/standalone/write.go +++ b/standalone/write.go @@ -9,9 +9,9 @@ import ( "github.com/charmbracelet/lipgloss" ) -var ( - Writer = colorprofile.NewWriter(os.Stdout, os.Environ()) -) +// Writer is the default writer that prints to stdout, automatically +// downsampling colors when necessary. +var Writer = colorprofile.NewWriter(os.Stdout, os.Environ()) // Println to stdout, automatically downsampling colors when necessary, ending // with a trailing newline. @@ -65,8 +65,7 @@ func Print(v ...interface{}) (n int, err error) { // // Fprint(os.Stderr, "I %s horchata pretty much all the time.\n", str) func Fprint(w io.Writer, v ...interface{}) (n int, err error) { - w = colorprofile.NewWriter(w, os.Environ()) - return fmt.Fprint(w, v...) + return fmt.Fprint(colorprofile.NewWriter(w, os.Environ()), v...) } // Fprint pritnts to the given writer, automatically downsampling colors when @@ -80,8 +79,7 @@ func Fprint(w io.Writer, v ...interface{}) (n int, err error) { // // Fprintln(os.Stderr, str) func Fprintln(w io.Writer, v ...interface{}) (n int, err error) { - w = colorprofile.NewWriter(w, os.Environ()) - return fmt.Fprintln(w, v...) + return fmt.Fprintln(colorprofile.NewWriter(w, os.Environ()), v...) } // Fprintf prints text to a writer, against the given format, automatically From c143751680167a06a92b81188027f11421e48601 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 16:12:43 -0400 Subject: [PATCH 14/32] docs(examples): move adaptive color examples --- examples/{adaptive => color}/bubbletea/main.go | 0 examples/{adaptive => color}/standalone/main.go | 8 ++++++-- 2 files changed, 6 insertions(+), 2 deletions(-) rename examples/{adaptive => color}/bubbletea/main.go (100%) rename examples/{adaptive => color}/standalone/main.go (87%) diff --git a/examples/adaptive/bubbletea/main.go b/examples/color/bubbletea/main.go similarity index 100% rename from examples/adaptive/bubbletea/main.go rename to examples/color/bubbletea/main.go diff --git a/examples/adaptive/standalone/main.go b/examples/color/standalone/main.go similarity index 87% rename from examples/adaptive/standalone/main.go rename to examples/color/standalone/main.go index 6f7c1038..9285b9b9 100644 --- a/examples/adaptive/standalone/main.go +++ b/examples/color/standalone/main.go @@ -1,5 +1,9 @@ -// This is an example showing how to work with colors when using Lip Gloss -// as a standalone package, i.e. outside of Bubble Tea. +// This example illustrates how to detect the terminal's background color and +// choose either light or dark colors accordingly when using Lip Gloss in a. +// standalone fashion, i.e. independent of Bubble Tea. +// +// For an example of how to do this in a Bubble Tea program, see the +// 'bubbletea' example. package main import ( From 78be932cf8086cb46d206c325b0843671680de91 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 16:16:35 -0400 Subject: [PATCH 15/32] docs(examples): update layout example for Lip Gloss v2 --- examples/go.mod | 2 +- examples/layout/main.go | 35 ++++++++++++++++++++++++++++------- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index ad4f4945..1b21b407 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -6,7 +6,7 @@ replace github.com/charmbracelet/lipgloss => ../ replace github.com/charmbracelet/lipgloss/list => ../list -replace github.com/charmbracelet/lipgloss/adaptive => ../adaptive +replace github.com/charmbracelet/lipgloss/table => ../table require ( github.com/charmbracelet/lipgloss v0.11.0 diff --git a/examples/layout/main.go b/examples/layout/main.go index d329961e..e8e0994c 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/lipgloss/adaptive" "github.com/lucasb-eyer/go-colorful" "golang.org/x/term" ) @@ -20,17 +19,39 @@ const ( // wrapping. width = 96 + // How wide to render various columns in the layout. columnWidth = 30 ) +var hasDarkBG bool + +func init() { + var err error + + // Detect the background color. + hasDarkBG, err = lipgloss.HasDarkBackground(os.Stdin, os.Stdout) + if err != nil { + fmt.Fprintf(os.Stderr, "Could not detect background color: %v\n", err) + os.Exit(1) + } +} + +// Create a new helper function for choosing either a light or dark color based +// on the detected background color. +// +// lipgloss.Adapt returns a function whose signature looks like this: +// +// func (lightColor, darkColor string) chosenColor string +var adaptive = lipgloss.Adapt(hasDarkBG) + // Style definitions. var ( // General. - subtle = adaptive.AdaptiveColor("#D9DCCF", "#383838") - highlight = adaptive.AdaptiveColor("#874BFD", "#7D56F4") - special = adaptive.AdaptiveColor("#43BF6D", "#73F59F") + subtle = adaptive.Color("#D9DCCF", "#383838") + highlight = adaptive.Color("#874BFD", "#7D56F4") + special = adaptive.Color("#43BF6D", "#73F59F") divider = lipgloss.NewStyle(). SetString("•"). @@ -142,7 +163,7 @@ var ( listDone = func(s string) string { return checkMark + lipgloss.NewStyle(). Strikethrough(true). - Foreground(adaptive.AdaptiveColor("#969B86", "#696969")). + Foreground(adaptive.Color("#969B86", "#696969")). Render(s) } @@ -164,8 +185,8 @@ var ( Padding(0, 1) statusBarStyle = lipgloss.NewStyle(). - Foreground(adaptive.AdaptiveColor("#343433", "#C1C6B2")). - Background(adaptive.AdaptiveColor("#D9DCCF", "#353533")) + Foreground(adaptive.Color("#343433", "#C1C6B2")). + Background(adaptive.Color("#D9DCCF", "#353533")) statusStyle = lipgloss.NewStyle(). Inherit(statusBarStyle). From ebe9e2af6a808b55d2d03bef2632d516baac31c8 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Tue, 8 Oct 2024 10:55:26 -0400 Subject: [PATCH 16/32] chore: update tests and remove unused code --- color_test.go | 179 ++--------------------------- list/list_test.go | 3 +- runes_test.go | 11 +- style_test.go | 96 ++++------------ table/table_test.go | 30 ++++- tree/testdata/TestRootStyle.golden | 6 +- tree/tree_test.go | 7 +- 7 files changed, 66 insertions(+), 266 deletions(-) diff --git a/color_test.go b/color_test.go index 7cec7af7..519e5821 100644 --- a/color_test.go +++ b/color_test.go @@ -1,7 +1,6 @@ package lipgloss import ( - "image/color" "testing" ) @@ -31,8 +30,8 @@ func TestHexToColor(t *testing.T) { } for i, tc := range tt { - h := hexToColor(tc.input) - o := uint(h.R)<<16 + uint(h.G)<<8 + uint(h.B) + r, g, b, _ := Color(tc.input).RGBA() + o := uint(r>>8)<<16 + uint(g>>8)<<8 + uint(b>>8) if o != tc.expected { t.Errorf("expected %X, got %X (test #%d)", tc.expected, o, i+1) } @@ -41,145 +40,26 @@ func TestHexToColor(t *testing.T) { func TestRGBA(t *testing.T) { tt := []struct { - profile Profile - darkBg bool - input TerminalColor + input string expected uint }{ // lipgloss.Color { - TrueColor, - true, - Color("#FF0000"), - 0xFF0000, - }, - { - TrueColor, - true, - Color("9"), - 0xFF0000, - }, - { - TrueColor, - true, - Color("21"), - 0x0000FF, - }, - // lipgloss.AdaptiveColor - { - TrueColor, - true, - AdaptiveColor{Light: "#0000FF", Dark: "#FF0000"}, - 0xFF0000, - }, - { - TrueColor, - false, - AdaptiveColor{Light: "#0000FF", Dark: "#FF0000"}, - 0x0000FF, - }, - { - TrueColor, - true, - AdaptiveColor{Light: "21", Dark: "9"}, + "#FF0000", 0xFF0000, }, { - TrueColor, - false, - AdaptiveColor{Light: "21", Dark: "9"}, - 0x0000FF, - }, - // lipgloss.CompleteColor - { - TrueColor, - true, - CompleteColor{TrueColor: "#FF0000", ANSI256: "231", ANSI: "12"}, + "9", 0xFF0000, }, { - ANSI256, - true, - CompleteColor{TrueColor: "#FF0000", ANSI256: "231", ANSI: "12"}, - 0xFFFFFF, - }, - { - ANSI, - true, - CompleteColor{TrueColor: "#FF0000", ANSI256: "231", ANSI: "12"}, + "21", 0x0000FF, }, - { - TrueColor, - true, - CompleteColor{TrueColor: "", ANSI256: "231", ANSI: "12"}, - 0x000000, - }, - // lipgloss.CompleteAdaptiveColor - // dark - { - TrueColor, - true, - CompleteAdaptiveColor{ - Light: CompleteColor{TrueColor: "#0000FF", ANSI256: "231", ANSI: "12"}, - Dark: CompleteColor{TrueColor: "#FF0000", ANSI256: "231", ANSI: "12"}, - }, - 0xFF0000, - }, - { - ANSI256, - true, - CompleteAdaptiveColor{ - Light: CompleteColor{TrueColor: "#FF0000", ANSI256: "21", ANSI: "12"}, - Dark: CompleteColor{TrueColor: "#FF0000", ANSI256: "231", ANSI: "12"}, - }, - 0xFFFFFF, - }, - { - ANSI, - true, - CompleteAdaptiveColor{ - Light: CompleteColor{TrueColor: "#FF0000", ANSI256: "231", ANSI: "9"}, - Dark: CompleteColor{TrueColor: "#FF0000", ANSI256: "231", ANSI: "12"}, - }, - 0x0000FF, - }, - // light - { - TrueColor, - false, - CompleteAdaptiveColor{ - Light: CompleteColor{TrueColor: "#0000FF", ANSI256: "231", ANSI: "12"}, - Dark: CompleteColor{TrueColor: "#FF0000", ANSI256: "231", ANSI: "12"}, - }, - 0x0000FF, - }, - { - ANSI256, - false, - CompleteAdaptiveColor{ - Light: CompleteColor{TrueColor: "#FF0000", ANSI256: "21", ANSI: "12"}, - Dark: CompleteColor{TrueColor: "#FF0000", ANSI256: "231", ANSI: "12"}, - }, - 0x0000FF, - }, - { - ANSI, - false, - CompleteAdaptiveColor{ - Light: CompleteColor{TrueColor: "#FF0000", ANSI256: "231", ANSI: "9"}, - Dark: CompleteColor{TrueColor: "#FF0000", ANSI256: "231", ANSI: "12"}, - }, - 0xFF0000, - }, } - r := DefaultRenderer() for i, tc := range tt { - r.SetColorProfile(tc.profile) - r.SetHasDarkBackground(tc.darkBg) - - r, g, b, _ := tc.input.color(r).RGBA() + r, g, b, _ := Color(tc.input).RGBA() o := uint(r/256)<<16 + uint(g/256)<<8 + uint(b/256) if o != tc.expected { @@ -187,48 +67,3 @@ func TestRGBA(t *testing.T) { } } } - -// hexToColor translates a hex color string (#RRGGBB or #RGB) into a color.RGB, -// which satisfies the color.Color interface. If an invalid string is passed -// black with 100% opacity will be returned: or, in hex format, 0x000000FF. -func hexToColor(hex string) (c color.RGBA) { - c.A = 0xFF - - if hex == "" || hex[0] != '#' { - return c - } - - const ( - fullFormat = 7 // #RRGGBB - shortFormat = 4 // #RGB - ) - - switch len(hex) { - case fullFormat: - const offset = 4 - c.R = hexToByte(hex[1])<= '0' && b <= '9': - return b - '0' - case b >= 'a' && b <= 'f': - return b - 'a' + offset - case b >= 'A' && b <= 'F': - return b - 'A' + offset - } - // Invalid, but just return 0. - return 0 -} diff --git a/list/list_test.go b/list/list_test.go index b5a0a947..8a20444a 100644 --- a/list/list_test.go +++ b/list/list_test.go @@ -9,6 +9,7 @@ import ( "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/list" "github.com/charmbracelet/lipgloss/tree" + "github.com/charmbracelet/x/ansi" ) // XXX: can't write multi-line examples if the underlying string uses @@ -194,7 +195,7 @@ func TestComplexSublist(t *testing.T) { C. bar • Baz ` - assertEqual(t, expected, l.String()) + assertEqual(t, expected, ansi.Strip(l.String())) } func TestMultiline(t *testing.T) { diff --git a/runes_test.go b/runes_test.go index be36150d..bab31a8a 100644 --- a/runes_test.go +++ b/runes_test.go @@ -1,7 +1,6 @@ package lipgloss import ( - "strings" "testing" ) @@ -55,14 +54,10 @@ func TestStyleRunes(t *testing.T) { t.Run(tc.name, func(t *testing.T) { res := fn(tc.input, tc.indices) if res != tc.expected { - t.Errorf("Expected:\n\n`%s`\n`%s`\n\nActual Output:\n\n`%s`\n`%s`\n\n", - tc.expected, formatEscapes(tc.expected), - res, formatEscapes(res)) + t.Errorf("Expected:\n\n`%q`\n`%q`\n\nActual Output:\n\n`%q`\n`%q`\n\n", + tc.expected, tc.expected, + res, res) } }) } } - -func formatEscapes(str string) string { - return strings.ReplaceAll(str, "\x1b", "\\x1b") -} diff --git a/style_test.go b/style_test.go index ede9ac93..001a1aac 100644 --- a/style_test.go +++ b/style_test.go @@ -15,19 +15,19 @@ func TestUnderline(t *testing.T) { }{ { NewStyle().Underline(true), - "\x1b[4;4ma\x1b[0m\x1b[4;4mb\x1b[0m\x1b[4m \x1b[0m\x1b[4;4mc\x1b[0m", + "\x1b[4;4ma\x1b[m\x1b[4;4mb\x1b[m\x1b[4m \x1b[m\x1b[4;4mc\x1b[m", }, { NewStyle().Underline(true).UnderlineSpaces(true), - "\x1b[4;4ma\x1b[0m\x1b[4;4mb\x1b[0m\x1b[4m \x1b[0m\x1b[4;4mc\x1b[0m", + "\x1b[4;4ma\x1b[m\x1b[4;4mb\x1b[m\x1b[4m \x1b[m\x1b[4;4mc\x1b[m", }, { NewStyle().Underline(true).UnderlineSpaces(false), - "\x1b[4;4ma\x1b[0m\x1b[4;4mb\x1b[0m \x1b[4;4mc\x1b[0m", + "\x1b[4;4ma\x1b[m\x1b[4;4mb\x1b[m \x1b[4;4mc\x1b[m", }, { NewStyle().UnderlineSpaces(true), - "ab\x1b[4m \x1b[0mc", + "ab\x1b[4m \x1b[mc", }, } @@ -35,9 +35,9 @@ func TestUnderline(t *testing.T) { s := tc.style.SetString("ab c") res := s.Render() if res != tc.expected { - t.Errorf("Test %d, expected:\n\n`%s`\n`%s`\n\nActual output:\n\n`%s`\n`%s`\n\n", - i, tc.expected, formatEscapes(tc.expected), - res, formatEscapes(res)) + t.Errorf("Test %d, expected:\n`%q`\n\nActual output:\n`%q`\n\n", + i, tc.expected, + res) } } } @@ -51,19 +51,19 @@ func TestStrikethrough(t *testing.T) { }{ { NewStyle().Strikethrough(true), - "\x1b[9ma\x1b[0m\x1b[9mb\x1b[0m\x1b[9m \x1b[0m\x1b[9mc\x1b[0m", + "\x1b[9ma\x1b[m\x1b[9mb\x1b[m\x1b[9m \x1b[m\x1b[9mc\x1b[m", }, { NewStyle().Strikethrough(true).StrikethroughSpaces(true), - "\x1b[9ma\x1b[0m\x1b[9mb\x1b[0m\x1b[9m \x1b[0m\x1b[9mc\x1b[0m", + "\x1b[9ma\x1b[m\x1b[9mb\x1b[m\x1b[9m \x1b[m\x1b[9mc\x1b[m", }, { NewStyle().Strikethrough(true).StrikethroughSpaces(false), - "\x1b[9ma\x1b[0m\x1b[9mb\x1b[0m \x1b[9mc\x1b[0m", + "\x1b[9ma\x1b[m\x1b[9mb\x1b[m \x1b[9mc\x1b[m", }, { NewStyle().StrikethroughSpaces(true), - "ab\x1b[9m \x1b[0mc", + "ab\x1b[9m \x1b[mc", }, } @@ -71,9 +71,9 @@ func TestStrikethrough(t *testing.T) { s := tc.style.SetString("ab c") res := s.Render() if res != tc.expected { - t.Errorf("Test %d, expected:\n\n`%s`\n`%s`\n\nActual output:\n\n`%s`\n`%s`\n\n", - i, tc.expected, formatEscapes(tc.expected), - res, formatEscapes(res)) + t.Errorf("Test %d, expected:\n`%q`\n\nActual output:\n`%q`\n\n", + i, tc.expected, + res) } } } @@ -87,11 +87,7 @@ func TestStyleRender(t *testing.T) { }{ { NewStyle().Foreground(Color("#5A56E0")), - "\x1b[38;2;89;86;224mhello\x1b[m", - }, - { - NewStyle().Foreground(AdaptiveColor{Light: "#fffe12", Dark: "#5A56E0"}), - "\x1b[38;2;89;86;224mhello\x1b[m", + "\x1b[38;2;90;86;224mhello\x1b[m", }, { NewStyle().Bold(true), @@ -119,59 +115,9 @@ func TestStyleRender(t *testing.T) { s := tc.style.SetString("hello") res := s.Render() if res != tc.expected { - t.Errorf("Test %d, expected:\n\n`%s`\n`%s`\n\nActual output:\n\n`%s`\n`%s`\n\n", - i, tc.expected, formatEscapes(tc.expected), - res, formatEscapes(res)) - } - } -} - -func TestStyleCustomRender(t *testing.T) { - tt := []struct { - style Style - expected string - }{ - { - NewStyle().Foreground(Color("#5A56E0")), - "\x1b[38;2;89;86;224mhello\x1b[m", - }, - { - NewStyle().Foreground(AdaptiveColor{Light: "#fffe12", Dark: "#5A56E0"}), - "\x1b[38;2;255;254;18mhello\x1b[m", - }, - { - NewStyle().Bold(true), - "\x1b[1mhello\x1b[m", - }, - { - NewStyle().Italic(true), - "\x1b[3mhello\x1b[m", - }, - { - NewStyle().Underline(true), - "\x1b[4;4mh\x1b[m\x1b[4;4me\x1b[m\x1b[4;4ml\x1b[m\x1b[4;4ml\x1b[m\x1b[4;4mo\x1b[m", - }, - { - NewStyle().Blink(true), - "\x1b[5mhello\x1b[m", - }, - { - NewStyle().Faint(true), - "\x1b[2mhello\x1b[m", - }, - { - NewStyle().Faint(true), - "\x1b[2mhello\x1b[m", - }, - } - - for i, tc := range tt { - s := tc.style.SetString("hello") - res := s.Render() - if res != tc.expected { - t.Errorf("Test %d, expected:\n\n`%s`\n`%s`\n\nActual output:\n\n`%s`\n`%s`\n\n", - i, tc.expected, formatEscapes(tc.expected), - res, formatEscapes(res)) + t.Errorf("Test %d, expected:\n`%q`\n\nActual output:\n`%q`\n\n", + i, tc.expected, + res) } } } @@ -454,9 +400,9 @@ func TestStyleValue(t *testing.T) { for i, tc := range tt { res := tc.style.Render(tc.text) if res != tc.expected { - t.Errorf("Test %d, expected:\n\n`%s`\n`%s`\n\nActual output:\n\n`%s`\n`%s`\n\n", - i, tc.expected, formatEscapes(tc.expected), - res, formatEscapes(res)) + t.Errorf("Test %d, expected:\n`%q`\n\nActual output:\n`%q`\n\n", + i, tc.expected, + res) } } } diff --git a/table/table_test.go b/table/table_test.go index 8f14a00d..7e687558 100644 --- a/table/table_test.go +++ b/table/table_test.go @@ -5,6 +5,7 @@ import ( "testing" "unicode" + "github.com/aymanbagabas/go-udiff" "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/x/ansi" ) @@ -91,9 +92,7 @@ func TestTableExample(t *testing.T) { └──────────┴───────────────────────────────┴─────────────────┘ `) - if table.String() != expected { - t.Fatalf("expected:\n\n%s\n\ngot:\n\n%s", expected, table.String()) - } + assertEqual(t, expected, ansi.Strip(table.String())) } func TestTableEmpty(t *testing.T) { @@ -992,3 +991,28 @@ func stripString(str string) string { return strings.Join(lines, "\n") } + +// assertEqual verifies the strings are equal, assuming its terminal output. +func assertEqual(tb testing.TB, want, got string) { + tb.Helper() + + want = trimSpace(want) + got = trimSpace(got) + + diff := udiff.Unified("want", "got", want, got) + if diff != "" { + tb.Fatalf("\nwant:\n\n%s\n\ngot:\n\n%s\n\ndiff:\n\n%s\n\n", want, got, diff) + } +} + +func trimSpace(s string) string { + var result []string //nolint: prealloc + ss := strings.Split(s, "\n") + for i, line := range ss { + if strings.TrimSpace(line) == "" && (i == 0 || i == len(ss)-1) { + continue + } + result = append(result, strings.TrimRightFunc(line, unicode.IsSpace)) + } + return strings.Join(result, "\n") +} diff --git a/tree/testdata/TestRootStyle.golden b/tree/testdata/TestRootStyle.golden index feacf4cd..f6b11fc5 100644 --- a/tree/testdata/TestRootStyle.golden +++ b/tree/testdata/TestRootStyle.golden @@ -1,3 +1,3 @@ -Root -├── Foo -└── Baz \ No newline at end of file +Root +├── Foo +└── Baz \ No newline at end of file diff --git a/tree/tree_test.go b/tree/tree_test.go index 3ee1fd34..3f4cca3f 100644 --- a/tree/tree_test.go +++ b/tree/tree_test.go @@ -10,8 +10,8 @@ import ( "github.com/charmbracelet/lipgloss/list" "github.com/charmbracelet/lipgloss/table" "github.com/charmbracelet/lipgloss/tree" + "github.com/charmbracelet/x/ansi" "github.com/charmbracelet/x/exp/golden" - "github.com/muesli/termenv" ) func TestTree(t *testing.T) { @@ -272,7 +272,7 @@ func TestTreeCustom(t *testing.T) { -> -> Quuux -> Baz ` - assertEqual(t, want, tree.String()) + assertEqual(t, want, ansi.Strip(tree.String())) } func TestTreeMultilineNode(t *testing.T) { @@ -413,7 +413,6 @@ Root } func TestRootStyle(t *testing.T) { - lipgloss.SetColorProfile(termenv.TrueColor) tree := tree.New(). Root("Root"). Child( @@ -423,7 +422,7 @@ func TestRootStyle(t *testing.T) { RootStyle(lipgloss.NewStyle().Background(lipgloss.Color("#5A56E0"))). ItemStyle(lipgloss.NewStyle().Background(lipgloss.Color("#04B575"))) - golden.RequireEqual(t, []byte(tree.String())) + golden.RequireEqual(t, []byte(ansi.Strip(tree.String()))) } func TestAt(t *testing.T) { From e36ce873c60fdf46de7f3e5163e37722f9f69227 Mon Sep 17 00:00:00 2001 From: bashbunni Date: Thu, 10 Oct 2024 13:50:55 -0700 Subject: [PATCH 17/32] wip(examples): various updates for Lip Gloss v2 --- examples/go.mod | 19 +++++++++++-------- examples/go.sum | 26 ++++++++++++++++---------- examples/layout/main.go | 7 ++++--- examples/ssh/main.go | 12 ++++++------ examples/table/pokemon/main.go | 11 +++++------ go.mod | 4 ---- go.sum | 10 ---------- 7 files changed, 42 insertions(+), 47 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 1b21b407..96d1f5ce 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -9,11 +9,13 @@ replace github.com/charmbracelet/lipgloss/list => ../list replace github.com/charmbracelet/lipgloss/table => ../table require ( - github.com/charmbracelet/lipgloss v0.11.0 + github.com/charmbracelet/bubbletea/v2 v2.0.0-alpha.1 + github.com/charmbracelet/colorprofile v0.1.2 + github.com/charmbracelet/lipgloss v0.13.0 github.com/charmbracelet/ssh v0.0.0-20240401141849-854cddfa2917 github.com/charmbracelet/wish v1.4.0 + github.com/charmbracelet/x/term v0.2.0 github.com/lucasb-eyer/go-colorful v1.2.0 - golang.org/x/term v0.21.0 ) require ( @@ -22,19 +24,19 @@ require ( github.com/charmbracelet/bubbletea v0.25.0 // indirect github.com/charmbracelet/keygen v0.5.0 // indirect github.com/charmbracelet/log v0.4.0 // indirect - github.com/charmbracelet/x/ansi v0.2.3 // indirect + github.com/charmbracelet/x/ansi v0.3.2 // indirect github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651 // indirect github.com/charmbracelet/x/exp/term v0.0.0-20240328150354-ab9afc214dfd // indirect github.com/charmbracelet/x/input v0.2.0 // indirect - github.com/charmbracelet/x/term v0.2.0 // indirect + github.com/charmbracelet/x/windows v0.2.0 // indirect github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect github.com/creack/pty v1.1.21 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-localereader v0.0.1 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect - github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.2 // indirect @@ -42,7 +44,8 @@ require ( github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.24.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.14.0 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index 01386b0b..d8589557 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -5,6 +5,10 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM= github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg= +github.com/charmbracelet/bubbletea/v2 v2.0.0-alpha.1 h1:OZtpLCsuuPplC+1oyUo+/eAN7e9MC2UyZWKlKrVlUnw= +github.com/charmbracelet/bubbletea/v2 v2.0.0-alpha.1/go.mod h1:j0gn4ft5CE7NDYNZjAA3hBM8t2OPjI8urxuAD0oR4w8= +github.com/charmbracelet/colorprofile v0.1.2 h1:nuB1bd/yAExT4fkcZvpqtQ2N5/8cJHSRIKb6CzT7lAM= +github.com/charmbracelet/colorprofile v0.1.2/go.mod h1:1htIKZYeI4TQs+OykPvpuBTUbUJxBYeSYBDIZuejMj0= github.com/charmbracelet/keygen v0.5.0 h1:XY0fsoYiCSM9axkrU+2ziE6u6YjJulo/b9Dghnw6MZc= github.com/charmbracelet/keygen v0.5.0/go.mod h1:DfvCgLHxZ9rJxdK0DGw3C/LkV4SgdGbnliHcObV3L+8= github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM= @@ -13,8 +17,8 @@ github.com/charmbracelet/ssh v0.0.0-20240401141849-854cddfa2917 h1:NZKjJ7d/pzk/A github.com/charmbracelet/ssh v0.0.0-20240401141849-854cddfa2917/go.mod h1:8/Ve8iGRRIGFM1kepYfRF2pEOF5Y3TEZYoJaA54228U= github.com/charmbracelet/wish v1.4.0 h1:pL1uVP/YuYgJheHEj98teZ/n6pMYnmlZq/fcHvomrfc= github.com/charmbracelet/wish v1.4.0/go.mod h1:ew4/MjJVfW/akEO9KmrQHQv1F7bQRGscRMrA+KtovTk= -github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= -github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY= +github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651 h1:3RXpZWGWTOeVXCTv0Dnzxdv/MhNUkBfEcbaTY0zrTQI= github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0= github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a h1:G99klV19u0QnhiizODirwVksQB91TJKV/UaTnACcG30= @@ -24,6 +28,8 @@ github.com/charmbracelet/x/input v0.2.0 h1:1Sv+y/flcqUfUH2PXNIDKDIdT2G8smOnGOgaw github.com/charmbracelet/x/input v0.2.0/go.mod h1:KUSFIS6uQymtnr5lHVSOK9j8RvwTD4YHnWnzJUYnd/M= github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= +github.com/charmbracelet/x/windows v0.2.0 h1:ilXA1GJjTNkgOm94CLPeSz7rar54jtFatdmoiONPuEw= +github.com/charmbracelet/x/windows v0.2.0/go.mod h1:ZibNFR49ZFqCXgP76sYanisxRyC+EYrBE7TTknD8s1s= github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= @@ -40,10 +46,10 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= @@ -62,13 +68,13 @@ golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= diff --git a/examples/layout/main.go b/examples/layout/main.go index e8e0994c..3a80ceae 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -8,8 +8,8 @@ import ( "strings" "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/x/term" "github.com/lucasb-eyer/go-colorful" - "golang.org/x/term" ) const ( @@ -209,7 +209,7 @@ var ( ) func main() { - physicalWidth, _, _ := term.GetSize(int(os.Stdout.Fd())) + physicalWidth, _, _ := term.GetSize(os.Stdout.Fd()) doc := strings.Builder{} // Tabs @@ -356,7 +356,8 @@ func main() { } // Okay, let's print it - lipgloss.Println(docStyle.Render(doc.String())) + fmt.Println(docStyle.Render(doc.String())) + } func colorGrid(xSteps, ySteps int) [][]string { diff --git a/examples/ssh/main.go b/examples/ssh/main.go index 6a6dbf33..b5596ec9 100644 --- a/examples/ssh/main.go +++ b/examples/ssh/main.go @@ -12,13 +12,13 @@ package main import ( "fmt" "log" + "os" "strings" + "github.com/charmbracelet/colorprofile" "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/lipgloss/adaptive" "github.com/charmbracelet/ssh" "github.com/charmbracelet/wish" - "github.com/lucasb-eyer/go-colorful" ) // Available styles. @@ -66,7 +66,8 @@ func handler(next ssh.Handler) ssh.Handler { environ := sess.Environ() environ = append(environ, fmt.Sprintf("TERM=%s", pty.Term)) - output := adaptive.NewOutput(pty.Slave, pty.Slave, environ) + // output := colorprofile.NewOutput(pty.Slave, pty.Slave, environ) + output := colorprofile.NewWriter(pty.Slave, environ) width := pty.Window.Width // Initialize new styles against the renderer. @@ -75,7 +76,7 @@ func handler(next ssh.Handler) ssh.Handler { str := strings.Builder{} fmt.Fprintf(&str, "\n\nProfile: %s\n%s %s %s %s %s", - output.ColorProfile().String(), + colorprofile.Detect(os.Stdout, environ), styles.bold, styles.faint, styles.italic, @@ -102,8 +103,7 @@ func handler(next ssh.Handler) ssh.Handler { styles.cyan, styles.gray, ) - - col, _ := colorful.MakeColor(output.BackgroundColor) + // check if the client has a dark bg? fmt.Fprintf(&str, "%s %t %s\n\n", styles.bold.UnsetString().Render("Has dark background?"), output.HasDarkBackground(), col.Hex()) diff --git a/examples/table/pokemon/main.go b/examples/table/pokemon/main.go index 5c25eee9..2849d10a 100644 --- a/examples/table/pokemon/main.go +++ b/examples/table/pokemon/main.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "os" + "image/color" "strings" "github.com/charmbracelet/lipgloss" @@ -10,11 +10,10 @@ import ( ) func main() { - re := lipgloss.NewRenderer(os.Stdout) - baseStyle := re.NewStyle().Padding(0, 1) + baseStyle := lipgloss.NewStyle().Padding(0, 1) headerStyle := baseStyle.Foreground(lipgloss.Color("252")).Bold(true) selectedStyle := baseStyle.Foreground(lipgloss.Color("#01BE85")).Background(lipgloss.Color("#00432F")) - typeColors := map[string]lipgloss.Color{ + typeColors := map[string]color.Color{ "Bug": lipgloss.Color("#D7FF87"), "Electric": lipgloss.Color("#FDFF90"), "Fire": lipgloss.Color("#FF7698"), @@ -25,7 +24,7 @@ func main() { "Poison": lipgloss.Color("#7D5AFC"), "Water": lipgloss.Color("#00E2C7"), } - dimTypeColors := map[string]lipgloss.Color{ + dimTypeColors := map[string]color.Color{ "Bug": lipgloss.Color("#97AD64"), "Electric": lipgloss.Color("#FCFF5F"), "Fire": lipgloss.Color("#BA5F75"), @@ -78,7 +77,7 @@ func main() { t := table.New(). Border(lipgloss.NormalBorder()). - BorderStyle(re.NewStyle().Foreground(lipgloss.Color("238"))). + BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("238"))). Headers(CapitalizeHeaders(headers)...). Width(80). Rows(data...). diff --git a/go.mod b/go.mod index cad77f11..9d3919c7 100644 --- a/go.mod +++ b/go.mod @@ -14,16 +14,12 @@ require ( github.com/charmbracelet/x/input v0.2.0 github.com/charmbracelet/x/term v0.2.0 github.com/lucasb-eyer/go-colorful v1.2.0 - github.com/muesli/termenv v0.15.2 github.com/rivo/uniseg v0.4.7 golang.org/x/sys v0.24.0 ) require ( - github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect ) diff --git a/go.sum b/go.sum index 4325c39f..cd526952 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= -github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= github.com/charmbracelet/colorprofile v0.1.2 h1:nuB1bd/yAExT4fkcZvpqtQ2N5/8cJHSRIKb6CzT7lAM= @@ -16,21 +14,13 @@ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= -github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= From d724ce666a9733df9b9d15685bee86183deced53 Mon Sep 17 00:00:00 2001 From: bashbunni Date: Thu, 10 Oct 2024 15:45:26 -0700 Subject: [PATCH 18/32] docs(examples): fixes for Lip Gloss v2 --- examples/go.mod | 5 ++++- examples/go.sum | 4 ++-- examples/list/sublist/main.go | 4 ++-- examples/ssh/main.go | 13 +++++++------ examples/table/chess/main.go | 4 +--- examples/table/languages/main.go | 19 ++++++++----------- examples/table/mindy/main.go | 6 ++---- 7 files changed, 26 insertions(+), 29 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 96d1f5ce..cc252208 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -11,7 +11,7 @@ replace github.com/charmbracelet/lipgloss/table => ../table require ( github.com/charmbracelet/bubbletea/v2 v2.0.0-alpha.1 github.com/charmbracelet/colorprofile v0.1.2 - github.com/charmbracelet/lipgloss v0.13.0 + github.com/charmbracelet/lipgloss v0.13.1-0.20240822211938-b89f1a3db2a4 github.com/charmbracelet/ssh v0.0.0-20240401141849-854cddfa2917 github.com/charmbracelet/wish v1.4.0 github.com/charmbracelet/x/term v0.2.0 @@ -49,3 +49,6 @@ require ( golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.14.0 // indirect ) + +// replace with log v2 +replace github.com/charmbracelet/log => github.com/charmbracelet/log v0.4.1-0.20241010222913-47ce960d4847 diff --git a/examples/go.sum b/examples/go.sum index d8589557..ee76067e 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -11,8 +11,8 @@ github.com/charmbracelet/colorprofile v0.1.2 h1:nuB1bd/yAExT4fkcZvpqtQ2N5/8cJHSR github.com/charmbracelet/colorprofile v0.1.2/go.mod h1:1htIKZYeI4TQs+OykPvpuBTUbUJxBYeSYBDIZuejMj0= github.com/charmbracelet/keygen v0.5.0 h1:XY0fsoYiCSM9axkrU+2ziE6u6YjJulo/b9Dghnw6MZc= github.com/charmbracelet/keygen v0.5.0/go.mod h1:DfvCgLHxZ9rJxdK0DGw3C/LkV4SgdGbnliHcObV3L+8= -github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM= -github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM= +github.com/charmbracelet/log v0.4.1-0.20241010222913-47ce960d4847 h1:3uto8OPDaseTS92giSw/8GfVQ+TCjcVE+QOaf8lT0Zc= +github.com/charmbracelet/log v0.4.1-0.20241010222913-47ce960d4847/go.mod h1:3UCs04fasl8pA1HoNNJ8HCYCaKoeMBZrNXo9iy5F0vY= github.com/charmbracelet/ssh v0.0.0-20240401141849-854cddfa2917 h1:NZKjJ7d/pzk/AfcJYEzmF8M48JlIrrY00RR5JdDc3io= github.com/charmbracelet/ssh v0.0.0-20240401141849-854cddfa2917/go.mod h1:8/Ve8iGRRIGFM1kepYfRF2pEOF5Y3TEZYoJaA54228U= github.com/charmbracelet/wish v1.4.0 h1:pL1uVP/YuYgJheHEj98teZ/n6pMYnmlZq/fcHvomrfc= diff --git a/examples/list/sublist/main.go b/examples/list/sublist/main.go index 3f0a48cd..e1189a7d 100644 --- a/examples/list/sublist/main.go +++ b/examples/list/sublist/main.go @@ -27,7 +27,7 @@ func main() { dim := lipgloss.Color("250") highlight := lipgloss.Color("#EE6FF8") - special := lipgloss.AdaptiveColor{Light: "#43BF6D", Dark: "#73F59F"} + special := lipgloss.Color("#73F59F") checklistEnumStyle := func(items list.Items, index int) lipgloss.Style { switch index { @@ -54,7 +54,7 @@ func main() { case 1, 2, 4: return lipgloss.NewStyle(). Strikethrough(true). - Foreground(lipgloss.AdaptiveColor{Light: "#969B86", Dark: "#696969"}) + Foreground(lipgloss.Color("#696969")) default: return lipgloss.NewStyle() } diff --git a/examples/ssh/main.go b/examples/ssh/main.go index b5596ec9..86ef4426 100644 --- a/examples/ssh/main.go +++ b/examples/ssh/main.go @@ -103,19 +103,20 @@ func handler(next ssh.Handler) ssh.Handler { styles.cyan, styles.gray, ) - // check if the client has a dark bg? - fmt.Fprintf(&str, "%s %t %s\n\n", styles.bold.UnsetString().Render("Has dark background?"), - output.HasDarkBackground(), - col.Hex()) + // TODO recheck if the client has a dark bg? + // see https://github.com/charmbracelet/lipgloss/pull/359 + // fmt.Fprintf(&str, "%s %t %s\n\n", styles.bold.UnsetString().Render("Has dark background?"), + // output.HasDarkBackground(), + // col.Hex()) block := lipgloss.Place(width, lipgloss.Height(str.String()), lipgloss.Center, lipgloss.Center, str.String(), lipgloss.WithWhitespaceChars("/"), - lipgloss.WithWhitespaceStyle(lipgloss.NewStyle().Foreground(output.AdaptiveColor(lipgloss.Color(250), lipgloss.Color(236)))), + lipgloss.WithWhitespaceStyle(lipgloss.NewStyle().Foreground(lipgloss.Color(236))), ) // Render to client. - output.Println(block) + output.WriteString(block) next(sess) } diff --git a/examples/table/chess/main.go b/examples/table/chess/main.go index a69a9bc4..67a741ea 100644 --- a/examples/table/chess/main.go +++ b/examples/table/chess/main.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "os" "strings" "github.com/charmbracelet/lipgloss" @@ -10,8 +9,7 @@ import ( ) func main() { - re := lipgloss.NewRenderer(os.Stdout) - labelStyle := re.NewStyle().Foreground(lipgloss.Color("241")) + labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("241")) board := [][]string{ {"♜", "♞", "♝", "♛", "♚", "♝", "♞", "♜"}, diff --git a/examples/table/languages/main.go b/examples/table/languages/main.go index b0e94d82..687f6f7a 100644 --- a/examples/table/languages/main.go +++ b/examples/table/languages/main.go @@ -2,32 +2,29 @@ package main import ( "fmt" - "os" "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/table" ) const ( - purple = lipgloss.Color("99") - gray = lipgloss.Color("245") - lightGray = lipgloss.Color("241") + purple = "99" + gray = "245" + lightGray = "241" ) func main() { - re := lipgloss.NewRenderer(os.Stdout) - var ( // HeaderStyle is the lipgloss style used for the table headers. - HeaderStyle = re.NewStyle().Foreground(purple).Bold(true).Align(lipgloss.Center) + HeaderStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(purple)).Bold(true).Align(lipgloss.Center) // CellStyle is the base lipgloss style used for the table rows. - CellStyle = re.NewStyle().Padding(0, 1).Width(14) + CellStyle = lipgloss.NewStyle().Padding(0, 1).Width(14) // OddRowStyle is the lipgloss style used for odd-numbered table rows. - OddRowStyle = CellStyle.Foreground(gray) + OddRowStyle = CellStyle.Foreground(lipgloss.Color(gray)) // EvenRowStyle is the lipgloss style used for even-numbered table rows. - EvenRowStyle = CellStyle.Foreground(lightGray) + EvenRowStyle = CellStyle.Foreground(lipgloss.Color(lightGray)) // BorderStyle is the lipgloss style used for the table border. - BorderStyle = lipgloss.NewStyle().Foreground(purple) + BorderStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(purple)) ) rows := [][]string{ diff --git a/examples/table/mindy/main.go b/examples/table/mindy/main.go index f58fff38..78863230 100644 --- a/examples/table/mindy/main.go +++ b/examples/table/mindy/main.go @@ -2,16 +2,14 @@ package main import ( "fmt" - "os" "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/table" ) func main() { - re := lipgloss.NewRenderer(os.Stdout) - labelStyle := re.NewStyle().Width(3).Align(lipgloss.Right) - swatchStyle := re.NewStyle().Width(6) + labelStyle := lipgloss.NewStyle().Width(3).Align(lipgloss.Right) + swatchStyle := lipgloss.NewStyle().Width(6) data := [][]string{} for i := 0; i < 13; i += 8 { From 9cb1f6b9e39671cb7481ffd2aa3f5af5f175a2d1 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 17:00:23 -0400 Subject: [PATCH 19/32] docs(examples): use Lip Gloss (colorprofile) writer in layout example --- examples/layout/main.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/layout/main.go b/examples/layout/main.go index 3a80ceae..ee2dd9cc 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/standalone" "github.com/charmbracelet/x/term" "github.com/lucasb-eyer/go-colorful" ) @@ -355,9 +356,10 @@ func main() { docStyle = docStyle.MaxWidth(physicalWidth) } - // Okay, let's print it - fmt.Println(docStyle.Render(doc.String())) - + // Okay, let's print it. We use a special Lipgloss writer to downsample + // colors to the terminal's color palette. And, if output's not a TTY, we + // will remove color entirely. + standalone.Println(docStyle.Render(doc.String())) } func colorGrid(xSteps, ySteps int) [][]string { From 5d44e47121fd8a0ba3f4781b3c01452ca3ca3e2d Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 17:01:26 -0400 Subject: [PATCH 20/32] docs(examples): show background detection status in layout example --- examples/layout/main.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/layout/main.go b/examples/layout/main.go index ee2dd9cc..ce9b98e9 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -335,12 +335,19 @@ func main() { { w := lipgloss.Width + lightDarkState := func(v bool) string { + if v { + return "Dark" + } + return "Light" + }(hasDarkBG) + statusKey := statusStyle.Render("STATUS") encoding := encodingStyle.Render("UTF-8") fishCake := fishCakeStyle.Render("🍥 Fish Cake") statusVal := statusText. Width(width - w(statusKey) - w(encoding) - w(fishCake)). - Render("Ravishing") + Render("Ravishingly " + lightDarkState + "!") bar := lipgloss.JoinHorizontal(lipgloss.Top, statusKey, From 805e5a4863efbb7b042d6855551a3538d53d2d5b Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 17:12:07 -0400 Subject: [PATCH 21/32] docs(examples): fix background detection in layout example --- examples/layout/main.go | 294 ++++++++++++++++++++-------------------- 1 file changed, 149 insertions(+), 145 deletions(-) diff --git a/examples/layout/main.go b/examples/layout/main.go index ce9b98e9..eae40a57 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -24,7 +24,14 @@ const ( columnWidth = 30 ) -var hasDarkBG bool +var ( + // Whether the detected background color is dark. We detect this in init(). + hasDarkBG bool + + // A helper function for choosing either a light or dark color based on the + // detected background color. We create this in init(). + adaptive lipgloss.Adapt +) func init() { var err error @@ -35,185 +42,182 @@ func init() { fmt.Fprintf(os.Stderr, "Could not detect background color: %v\n", err) os.Exit(1) } + + // Create a new helper function for choosing either a light or dark color + // based on the detected background color. + adaptive = lipgloss.Adapt(hasDarkBG) } -// Create a new helper function for choosing either a light or dark color based -// on the detected background color. -// -// lipgloss.Adapt returns a function whose signature looks like this: -// -// func (lightColor, darkColor string) chosenColor string -var adaptive = lipgloss.Adapt(hasDarkBG) +func main() { -// Style definitions. -var ( + // Style definitions. + var ( - // General. + // General. - subtle = adaptive.Color("#D9DCCF", "#383838") - highlight = adaptive.Color("#874BFD", "#7D56F4") - special = adaptive.Color("#43BF6D", "#73F59F") + subtle = adaptive.Color("#D9DCCF", "#383838") + highlight = adaptive.Color("#874BFD", "#7D56F4") + special = adaptive.Color("#43BF6D", "#73F59F") - divider = lipgloss.NewStyle(). - SetString("•"). - Padding(0, 1). - Foreground(subtle). - String() + divider = lipgloss.NewStyle(). + SetString("•"). + Padding(0, 1). + Foreground(subtle). + String() - url = lipgloss.NewStyle().Foreground(special).Render + url = lipgloss.NewStyle().Foreground(special).Render - // Tabs. + // Tabs. - activeTabBorder = lipgloss.Border{ - Top: "─", - Bottom: " ", - Left: "│", - Right: "│", - TopLeft: "╭", - TopRight: "╮", - BottomLeft: "┘", - BottomRight: "└", - } + activeTabBorder = lipgloss.Border{ + Top: "─", + Bottom: " ", + Left: "│", + Right: "│", + TopLeft: "╭", + TopRight: "╮", + BottomLeft: "┘", + BottomRight: "└", + } - tabBorder = lipgloss.Border{ - Top: "─", - Bottom: "─", - Left: "│", - Right: "│", - TopLeft: "╭", - TopRight: "╮", - BottomLeft: "┴", - BottomRight: "┴", - } + tabBorder = lipgloss.Border{ + Top: "─", + Bottom: "─", + Left: "│", + Right: "│", + TopLeft: "╭", + TopRight: "╮", + BottomLeft: "┴", + BottomRight: "┴", + } - tab = lipgloss.NewStyle(). - Border(tabBorder, true). - BorderForeground(highlight). - Padding(0, 1) + tab = lipgloss.NewStyle(). + Border(tabBorder, true). + BorderForeground(highlight). + Padding(0, 1) - activeTab = tab.Border(activeTabBorder, true) + activeTab = tab.Border(activeTabBorder, true) - tabGap = tab. - BorderTop(false). - BorderLeft(false). - BorderRight(false) + tabGap = tab. + BorderTop(false). + BorderLeft(false). + BorderRight(false) - // Title. + // Title. - titleStyle = lipgloss.NewStyle(). - MarginLeft(1). - MarginRight(5). - Padding(0, 1). - Italic(true). - Foreground(lipgloss.Color("#FFF7DB")). - SetString("Lip Gloss") + titleStyle = lipgloss.NewStyle(). + MarginLeft(1). + MarginRight(5). + Padding(0, 1). + Italic(true). + Foreground(lipgloss.Color("#FFF7DB")). + SetString("Lip Gloss") - descStyle = lipgloss.NewStyle().MarginTop(1) + descStyle = lipgloss.NewStyle().MarginTop(1) - infoStyle = lipgloss.NewStyle(). - BorderStyle(lipgloss.NormalBorder()). - BorderTop(true). - BorderForeground(subtle) + infoStyle = lipgloss.NewStyle(). + BorderStyle(lipgloss.NormalBorder()). + BorderTop(true). + BorderForeground(subtle) - // Dialog. + // Dialog. + + dialogBoxStyle = lipgloss.NewStyle(). + Border(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("#874BFD")). + Padding(1, 0). + BorderTop(true). + BorderLeft(true). + BorderRight(true). + BorderBottom(true) - dialogBoxStyle = lipgloss.NewStyle(). - Border(lipgloss.RoundedBorder()). - BorderForeground(lipgloss.Color("#874BFD")). - Padding(1, 0). - BorderTop(true). - BorderLeft(true). - BorderRight(true). - BorderBottom(true) - - buttonStyle = lipgloss.NewStyle(). - Foreground(lipgloss.Color("#FFF7DB")). - Background(lipgloss.Color("#888B7E")). - Padding(0, 3). - MarginTop(1) - - activeButtonStyle = buttonStyle. + buttonStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("#FFF7DB")). - Background(lipgloss.Color("#F25D94")). - MarginRight(2). - Underline(true) + Background(lipgloss.Color("#888B7E")). + Padding(0, 3). + MarginTop(1) - // List. + activeButtonStyle = buttonStyle. + Foreground(lipgloss.Color("#FFF7DB")). + Background(lipgloss.Color("#F25D94")). + MarginRight(2). + Underline(true) - list = lipgloss.NewStyle(). - Border(lipgloss.NormalBorder(), false, true, false, false). - BorderForeground(subtle). - MarginRight(2). - Height(8). - Width(columnWidth + 1) + // List. - listHeader = lipgloss.NewStyle(). - BorderStyle(lipgloss.NormalBorder()). - BorderBottom(true). + list = lipgloss.NewStyle(). + Border(lipgloss.NormalBorder(), false, true, false, false). BorderForeground(subtle). MarginRight(2). - Render + Height(8). + Width(columnWidth + 1) - listItem = lipgloss.NewStyle().PaddingLeft(2).Render + listHeader = lipgloss.NewStyle(). + BorderStyle(lipgloss.NormalBorder()). + BorderBottom(true). + BorderForeground(subtle). + MarginRight(2). + Render - checkMark = lipgloss.NewStyle().SetString("✓"). - Foreground(special). - PaddingRight(1). - String() + listItem = lipgloss.NewStyle().PaddingLeft(2).Render - listDone = func(s string) string { - return checkMark + lipgloss.NewStyle(). - Strikethrough(true). - Foreground(adaptive.Color("#969B86", "#696969")). - Render(s) - } + checkMark = lipgloss.NewStyle().SetString("✓"). + Foreground(special). + PaddingRight(1). + String() - // Paragraphs/History. + listDone = func(s string) string { + return checkMark + lipgloss.NewStyle(). + Strikethrough(true). + Foreground(adaptive.Color("#969B86", "#696969")). + Render(s) + } - historyStyle = lipgloss.NewStyle(). - Align(lipgloss.Left). - Foreground(lipgloss.Color("#FAFAFA")). - Background(highlight). - Margin(1, 3, 0, 0). - Padding(1, 2). - Height(19). - Width(columnWidth) + // Paragraphs/History. - // Status Bar. + historyStyle = lipgloss.NewStyle(). + Align(lipgloss.Left). + Foreground(lipgloss.Color("#FAFAFA")). + Background(highlight). + Margin(1, 3, 0, 0). + Padding(1, 2). + Height(19). + Width(columnWidth) - statusNugget = lipgloss.NewStyle(). - Foreground(lipgloss.Color("#FFFDF5")). - Padding(0, 1) + // Status Bar. - statusBarStyle = lipgloss.NewStyle(). - Foreground(adaptive.Color("#343433", "#C1C6B2")). - Background(adaptive.Color("#D9DCCF", "#353533")) + statusNugget = lipgloss.NewStyle(). + Foreground(lipgloss.Color("#FFFDF5")). + Padding(0, 1) - statusStyle = lipgloss.NewStyle(). - Inherit(statusBarStyle). - Foreground(lipgloss.Color("#FFFDF5")). - Background(lipgloss.Color("#FF5F87")). - Padding(0, 1). - MarginRight(1) + statusBarStyle = lipgloss.NewStyle(). + Foreground(adaptive.Color("#343433", "#C1C6B2")). + Background(adaptive.Color("#D9DCCF", "#353533")) - encodingStyle = statusNugget. - Background(lipgloss.Color("#A550DF")). - Align(lipgloss.Right) + statusStyle = lipgloss.NewStyle(). + Inherit(statusBarStyle). + Foreground(lipgloss.Color("#FFFDF5")). + Background(lipgloss.Color("#FF5F87")). + Padding(0, 1). + MarginRight(1) - statusText = lipgloss.NewStyle().Inherit(statusBarStyle) + encodingStyle = statusNugget. + Background(lipgloss.Color("#A550DF")). + Align(lipgloss.Right) - fishCakeStyle = statusNugget.Background(lipgloss.Color("#6124DF")) + statusText = lipgloss.NewStyle().Inherit(statusBarStyle) - // Page. + fishCakeStyle = statusNugget.Background(lipgloss.Color("#6124DF")) - docStyle = lipgloss.NewStyle().Padding(1, 2, 1, 2) -) + // Page. + + docStyle = lipgloss.NewStyle().Padding(1, 2, 1, 2) + ) -func main() { physicalWidth, _, _ := term.GetSize(os.Stdout.Fd()) doc := strings.Builder{} - // Tabs + // Tabs. { row := lipgloss.JoinHorizontal( lipgloss.Top, @@ -228,7 +232,7 @@ func main() { doc.WriteString(row + "\n\n") } - // Title + // Title. { var ( colors = colorGrid(1, 5) @@ -253,7 +257,7 @@ func main() { doc.WriteString(row + "\n\n") } - // Dialog + // Dialog. { okButton := activeButtonStyle.Render("Yes") cancelButton := buttonStyle.Render("Maybe") @@ -272,7 +276,7 @@ func main() { doc.WriteString(dialog + "\n\n") } - // Color grid + // Color grid. colors := func() string { colors := colorGrid(14, 8) @@ -313,7 +317,7 @@ func main() { doc.WriteString(lipgloss.JoinHorizontal(lipgloss.Top, lists, colors)) - // Marmalade history + // Marmalade history. { const ( historyA = "The Romans learned from the Greeks that quinces slowly cooked with honey would “set” when cool. The Apicius gives a recipe for preserving whole quinces, stems and leaves attached, in a bath of honey diluted with defrutum: Roman marmalade. Preserves of quince and lemon appear (along with rose, apple, plum and pear) in the Book of ceremonies of the Byzantine Emperor Constantine VII Porphyrogennetos." @@ -331,16 +335,16 @@ func main() { doc.WriteString("\n\n") } - // Status bar + // Status bar. { w := lipgloss.Width - lightDarkState := func(v bool) string { - if v { + lightDarkState := func() string { + if hasDarkBG { return "Dark" } return "Light" - }(hasDarkBG) + }() statusKey := statusStyle.Render("STATUS") encoding := encodingStyle.Render("UTF-8") From 54e84cd952850ff3fbdb6c769ea229cefdafabb1 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Oct 2024 17:27:39 -0400 Subject: [PATCH 22/32] docs(examples): re-add background color detect to ssh; fix profile --- examples/ssh/main.go | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/examples/ssh/main.go b/examples/ssh/main.go index 86ef4426..1d23243b 100644 --- a/examples/ssh/main.go +++ b/examples/ssh/main.go @@ -12,7 +12,6 @@ package main import ( "fmt" "log" - "os" "strings" "github.com/charmbracelet/colorprofile" @@ -66,7 +65,6 @@ func handler(next ssh.Handler) ssh.Handler { environ := sess.Environ() environ = append(environ, fmt.Sprintf("TERM=%s", pty.Term)) - // output := colorprofile.NewOutput(pty.Slave, pty.Slave, environ) output := colorprofile.NewWriter(pty.Slave, environ) width := pty.Window.Width @@ -76,7 +74,7 @@ func handler(next ssh.Handler) ssh.Handler { str := strings.Builder{} fmt.Fprintf(&str, "\n\nProfile: %s\n%s %s %s %s %s", - colorprofile.Detect(os.Stdout, environ), + colorprofile.Detect(pty.Slave, environ), styles.bold, styles.faint, styles.italic, @@ -103,11 +101,22 @@ func handler(next ssh.Handler) ssh.Handler { styles.cyan, styles.gray, ) - // TODO recheck if the client has a dark bg? - // see https://github.com/charmbracelet/lipgloss/pull/359 - // fmt.Fprintf(&str, "%s %t %s\n\n", styles.bold.UnsetString().Render("Has dark background?"), - // output.HasDarkBackground(), - // col.Hex()) + + hasDarkBG, err := lipgloss.HasDarkBackground(pty.Slave, pty.Slave) + if err != nil { + log.Print("Could not detect background color: %w", err) + return + } + + fmt.Fprintf(&str, "%s %s\n\n", + styles.bold.UnsetString().Render("Has dark background?"), + func() string { + if hasDarkBG { + return "Yep." + } + return "Nope!" + }(), + ) block := lipgloss.Place(width, lipgloss.Height(str.String()), lipgloss.Center, lipgloss.Center, str.String(), From 067d0851e8ce3cec09dfe277462b1421e99b2fc0 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Thu, 17 Oct 2024 12:27:46 -0400 Subject: [PATCH 23/32] feat: move writers to top level package --- standalone/write.go => writer.go | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) rename standalone/write.go => writer.go (84%) diff --git a/standalone/write.go b/writer.go similarity index 84% rename from standalone/write.go rename to writer.go index 80bb1e8d..ee47c9c2 100644 --- a/standalone/write.go +++ b/writer.go @@ -1,4 +1,4 @@ -package standalone +package lipgloss import ( "fmt" @@ -6,7 +6,6 @@ import ( "os" "github.com/charmbracelet/colorprofile" - "github.com/charmbracelet/lipgloss" ) // Writer is the default writer that prints to stdout, automatically @@ -18,7 +17,7 @@ var Writer = colorprofile.NewWriter(os.Stdout, os.Environ()) // // Example: // -// str := lipgloss.NewStyle(). +// str := NewStyle(). // Foreground(lipgloss.Color("#6a00ff")). // Render("breakfast") // @@ -32,7 +31,7 @@ func Println(v ...interface{}) (n int, err error) { // // Example: // -// str := lipgloss.NewStyle(). +// str := NewStyle(). // Foreground(lipgloss.Color("#6a00ff")). // Render("knuckle") // @@ -45,7 +44,7 @@ func Printf(format string, v ...interface{}) (n int, err error) { // // Example: // -// str := lipgloss.NewStyle(). +// str := NewStyle(). // Foreground(lipgloss.Color("#6a00ff")). // Render("Who wants marmalade?\n") // @@ -59,7 +58,7 @@ func Print(v ...interface{}) (n int, err error) { // // Example: // -// str := lipgloss.NewStyle(). +// str := NewStyle(). // Foreground(lipgloss.Color("#6a00ff")). // Render("guzzle") // @@ -73,7 +72,7 @@ func Fprint(w io.Writer, v ...interface{}) (n int, err error) { // // Example: // -// str := lipgloss.NewStyle(). +// str := NewStyle(). // Foreground(lipgloss.Color("#6a00ff")). // Render("Sandwich time!") // @@ -87,7 +86,7 @@ func Fprintln(w io.Writer, v ...interface{}) (n int, err error) { // // Example: // -// str := lipgloss.NewStyle(). +// str := NewStyle(). // Foreground(lipgloss.Color("#6a00ff")). // Render("artichokes") // @@ -95,8 +94,3 @@ func Fprintln(w io.Writer, v ...interface{}) (n int, err error) { func Fprintf(w io.Writer, format string, v ...interface{}) (n int, err error) { return fmt.Fprintf(colorprofile.NewWriter(w, os.Environ()), format, v...) } - -// HasDarkBackground returns whether or not the terminal has a dark background. -func HasDarkBackground() (bool, error) { - return lipgloss.HasDarkBackground(os.Stdin, os.Stdout) -} From 6fa7bb662fc252a8718df87134af41bf1abe3922 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Thu, 17 Oct 2024 12:28:42 -0400 Subject: [PATCH 24/32] docs(examples): use colorprofile writer in all examples --- examples/color/standalone/main.go | 15 ++++++++------- examples/layout/main.go | 3 +-- examples/list/duckduckgoose/main.go | 5 ++--- examples/list/glow/main.go | 5 +---- examples/list/grocery/main.go | 4 +--- examples/list/roman/main.go | 4 +--- examples/list/simple/main.go | 5 ++--- examples/list/sublist/main.go | 4 +--- examples/table/ansi/main.go | 4 +--- examples/table/chess/main.go | 9 +++++++-- examples/table/languages/main.go | 4 +--- examples/table/mindy/main.go | 2 +- examples/table/pokemon/main.go | 3 ++- examples/tree/background/main.go | 4 +--- examples/tree/files/main.go | 3 +-- examples/tree/makeup/main.go | 4 +--- examples/tree/rounded/main.go | 4 +--- examples/tree/simple/main.go | 5 ++--- examples/tree/styles/main.go | 5 ++--- examples/tree/toggle/main.go | 4 +--- 20 files changed, 38 insertions(+), 58 deletions(-) diff --git a/examples/color/standalone/main.go b/examples/color/standalone/main.go index 9285b9b9..5cab95ef 100644 --- a/examples/color/standalone/main.go +++ b/examples/color/standalone/main.go @@ -11,7 +11,6 @@ import ( "os" "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/lipgloss/standalone" ) func main() { @@ -46,10 +45,9 @@ func main() { Foreground(adaptive.Color("#0000ff", "#04b87c")). Bold(true) - // You can also use octal format for colors, i.e 0x#ff38ec. activeButton := lipgloss.NewStyle(). Padding(0, 3). - Background(lipgloss.Color(0xf347ff)). + Background(lipgloss.Color(0xf347ff)). // you can also use octal format for colors, i.e 0x#ff38ec. Foreground(lipgloss.Color(0xfaffcc)) inactiveButton := activeButton. Background(lipgloss.Color(0x545454)) @@ -65,8 +63,11 @@ func main() { lipgloss.JoinVertical(lipgloss.Center, text, buttons), ) - // Print the block to stdout. It's important to use the standalone package - // to ensure that colors are downsampled correctly. If output isn't a - // TTY (i.e. we're logging to a file) colors will be stripped entirely. - standalone.Println(block) + // Print the block to stdout. It's important to use Lip Gloss's print + // functions to ensure that colors are downsampled correctly. If output + // isn't a TTY (i.e. we're logging to a file) colors will be stripped + // entirely. + // + // Note that in Bubble Tea downsampling happens automatically. + lipgloss.Println(block) } diff --git a/examples/layout/main.go b/examples/layout/main.go index eae40a57..a1a033e5 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/lipgloss/standalone" "github.com/charmbracelet/x/term" "github.com/lucasb-eyer/go-colorful" ) @@ -370,7 +369,7 @@ func main() { // Okay, let's print it. We use a special Lipgloss writer to downsample // colors to the terminal's color palette. And, if output's not a TTY, we // will remove color entirely. - standalone.Println(docStyle.Render(doc.String())) + lipgloss.Println(docStyle.Render(doc.String())) } func colorGrid(xSteps, ySteps int) [][]string { diff --git a/examples/list/duckduckgoose/main.go b/examples/list/duckduckgoose/main.go index 7ff6eb5e..1f5b03f9 100644 --- a/examples/list/duckduckgoose/main.go +++ b/examples/list/duckduckgoose/main.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/list" ) @@ -22,5 +20,6 @@ func main() { ItemStyle(itemStyle). EnumeratorStyle(enumStyle). Enumerator(duckDuckGooseEnumerator) - fmt.Println(l) + + lipgloss.Println(l) } diff --git a/examples/list/glow/main.go b/examples/list/glow/main.go index d2f1d48d..a004ebf1 100644 --- a/examples/list/glow/main.go +++ b/examples/list/glow/main.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/list" ) @@ -59,6 +57,5 @@ func main() { l.Item(d.String()) } - fmt.Println() - fmt.Println(l) + lipgloss.Print("\n", l, "\n") } diff --git a/examples/list/grocery/main.go b/examples/list/grocery/main.go index 548a8735..218b6223 100644 --- a/examples/list/grocery/main.go +++ b/examples/list/grocery/main.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/list" ) @@ -71,5 +69,5 @@ func main() { EnumeratorStyleFunc(enumStyleFunc). ItemStyleFunc(itemStyleFunc) - fmt.Println(l) + lipgloss.Println(l) } diff --git a/examples/list/roman/main.go b/examples/list/roman/main.go index 791b8e8e..e4b82ef3 100644 --- a/examples/list/roman/main.go +++ b/examples/list/roman/main.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/list" ) @@ -22,5 +20,5 @@ func main() { EnumeratorStyle(enumeratorStyle). ItemStyle(itemStyle) - fmt.Println(l) + lipgloss.Println(l) } diff --git a/examples/list/simple/main.go b/examples/list/simple/main.go index 3a6da490..4a0c17b3 100644 --- a/examples/list/simple/main.go +++ b/examples/list/simple/main.go @@ -1,8 +1,7 @@ package main import ( - "fmt" - + "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/list" ) @@ -18,5 +17,5 @@ func main() { ).Enumerator(list.Roman), "G", ) - fmt.Println(l) + lipgloss.Println(l) } diff --git a/examples/list/sublist/main.go b/examples/list/sublist/main.go index e1189a7d..d6cd1c43 100644 --- a/examples/list/sublist/main.go +++ b/examples/list/sublist/main.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/list" "github.com/charmbracelet/lipgloss/table" @@ -210,7 +208,7 @@ func main() { ). Item("xoxo, Charm_™") - fmt.Println(l) + lipgloss.Println(l) } func colorGrid(xSteps, ySteps int) [][]string { diff --git a/examples/table/ansi/main.go b/examples/table/ansi/main.go index 66d457d5..092bed32 100644 --- a/examples/table/ansi/main.go +++ b/examples/table/ansi/main.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/table" ) @@ -14,5 +12,5 @@ func main() { t.Row("Bubble Tea", s("Milky")) t.Row("Milk Tea", s("Also milky")) t.Row("Actual milk", s("Milky as well")) - fmt.Println(t.Render()) + lipgloss.Println(t.Render()) } diff --git a/examples/table/chess/main.go b/examples/table/chess/main.go index 67a741ea..d49025d4 100644 --- a/examples/table/chess/main.go +++ b/examples/table/chess/main.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "strings" "github.com/charmbracelet/lipgloss" @@ -34,5 +33,11 @@ func main() { ranks := labelStyle.Render(strings.Join([]string{" A", "B", "C", "D", "E", "F", "G", "H "}, " ")) files := labelStyle.Render(strings.Join([]string{" 1", "2", "3", "4", "5", "6", "7", "8 "}, "\n\n ")) - fmt.Println(lipgloss.JoinVertical(lipgloss.Right, lipgloss.JoinHorizontal(lipgloss.Center, files, t.Render()), ranks) + "\n") + lipgloss.Println( + lipgloss.JoinVertical( + lipgloss.Right, + lipgloss.JoinHorizontal(lipgloss.Center, files, t.Render()), + ranks, + ) + "\n", + ) } diff --git a/examples/table/languages/main.go b/examples/table/languages/main.go index 687f6f7a..aed0dfd0 100644 --- a/examples/table/languages/main.go +++ b/examples/table/languages/main.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/table" ) @@ -67,5 +65,5 @@ func main() { t.Row("English", "You look absolutely fabulous.", "How's it going?") - fmt.Println(t) + lipgloss.Println(t) } diff --git a/examples/table/mindy/main.go b/examples/table/mindy/main.go index 78863230..b6666400 100644 --- a/examples/table/mindy/main.go +++ b/examples/table/mindy/main.go @@ -41,7 +41,7 @@ func main() { } }) - fmt.Println(t) + lipgloss.Println(t) } const rowLength = 12 diff --git a/examples/table/pokemon/main.go b/examples/table/pokemon/main.go index 2849d10a..424da5db 100644 --- a/examples/table/pokemon/main.go +++ b/examples/table/pokemon/main.go @@ -108,5 +108,6 @@ func main() { } return baseStyle.Foreground(lipgloss.Color("252")) }) - fmt.Println(t) + + lipgloss.Println(t) } diff --git a/examples/tree/background/main.go b/examples/tree/background/main.go index a38ca626..e87cfb6f 100644 --- a/examples/tree/background/main.go +++ b/examples/tree/background/main.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/tree" ) @@ -35,5 +33,5 @@ func main() { Child("Chapter 2.2"), ) - fmt.Println(t) + lipgloss.Println(t) } diff --git a/examples/tree/files/main.go b/examples/tree/files/main.go index 9e6250b8..2f712c97 100644 --- a/examples/tree/files/main.go +++ b/examples/tree/files/main.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "os" "path/filepath" @@ -24,5 +23,5 @@ func main() { return nil }) - fmt.Println(t) + lipgloss.Println(t) } diff --git a/examples/tree/makeup/main.go b/examples/tree/makeup/main.go index b6dca57d..0da00394 100644 --- a/examples/tree/makeup/main.go +++ b/examples/tree/makeup/main.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/tree" ) @@ -30,5 +28,5 @@ func main() { RootStyle(rootStyle). ItemStyle(itemStyle) - fmt.Println(t) + lipgloss.Println(t) } diff --git a/examples/tree/rounded/main.go b/examples/tree/rounded/main.go index c32dae3a..10f8f4b5 100644 --- a/examples/tree/rounded/main.go +++ b/examples/tree/rounded/main.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/tree" ) @@ -33,5 +31,5 @@ func main() { ), ).ItemStyle(itemStyle).EnumeratorStyle(enumeratorStyle).Enumerator(tree.RoundedEnumerator) - fmt.Println(t) + lipgloss.Println(t) } diff --git a/examples/tree/simple/main.go b/examples/tree/simple/main.go index 3969f156..2cf8c21e 100644 --- a/examples/tree/simple/main.go +++ b/examples/tree/simple/main.go @@ -1,8 +1,7 @@ package main import ( - "fmt" - + "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/tree" ) @@ -23,5 +22,5 @@ func main() { Child("OpenBSD"), ) - fmt.Println(t) + lipgloss.Println(t) } diff --git a/examples/tree/styles/main.go b/examples/tree/styles/main.go index 9950b1f4..8859c8ff 100644 --- a/examples/tree/styles/main.go +++ b/examples/tree/styles/main.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/tree" ) @@ -22,5 +20,6 @@ func main() { "Milk", ). EnumeratorStyle(purple) - fmt.Println(t) + + lipgloss.Println(t) } diff --git a/examples/tree/toggle/main.go b/examples/tree/toggle/main.go index 0664e98f..255b4711 100644 --- a/examples/tree/toggle/main.go +++ b/examples/tree/toggle/main.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/tree" ) @@ -88,5 +86,5 @@ func main() { dir{"maas", false, s}, ) - fmt.Println(s.block.Render(t.String())) + lipgloss.Println(s.block.Render(t.String())) } From 8dc8bdc45484178bd842d3b395934eb6d1d27394 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Thu, 17 Oct 2024 13:51:40 -0400 Subject: [PATCH 25/32] chore(lint): ignore error wrap checks in writers --- writer.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/writer.go b/writer.go index ee47c9c2..ba3e25ca 100644 --- a/writer.go +++ b/writer.go @@ -22,8 +22,8 @@ var Writer = colorprofile.NewWriter(os.Stdout, os.Environ()) // Render("breakfast") // // Println("Time for a", str, "sandwich!") -func Println(v ...interface{}) (n int, err error) { - return fmt.Fprintln(Writer, v...) +func Println(v ...interface{}) (int, error) { + return fmt.Fprintln(Writer, v...) //nolint:wrapcheck } // Print formatted text to stdout, automatically downsampling colors when @@ -36,8 +36,8 @@ func Println(v ...interface{}) (n int, err error) { // Render("knuckle") // // Printf("Time for a %s sandwich!\n", str) -func Printf(format string, v ...interface{}) (n int, err error) { - return fmt.Fprintf(Writer, format, v...) +func Printf(format string, v ...interface{}) (int, error) { + return fmt.Fprintf(Writer, format, v...) //nolint:wrapcheck } // Print to stdout, automatically downsampling colors when necessary. @@ -49,8 +49,8 @@ func Printf(format string, v ...interface{}) (n int, err error) { // Render("Who wants marmalade?\n") // // Print(str) -func Print(v ...interface{}) (n int, err error) { - return fmt.Fprint(Writer, v...) +func Print(v ...interface{}) (int, error) { + return fmt.Fprint(Writer, v...) //nolint:wrapcheck } // Fprint pritnts to the given writer, automatically downsampling colors when @@ -63,8 +63,8 @@ func Print(v ...interface{}) (n int, err error) { // Render("guzzle") // // Fprint(os.Stderr, "I %s horchata pretty much all the time.\n", str) -func Fprint(w io.Writer, v ...interface{}) (n int, err error) { - return fmt.Fprint(colorprofile.NewWriter(w, os.Environ()), v...) +func Fprint(w io.Writer, v ...interface{}) (int, error) { + return fmt.Fprint(colorprofile.NewWriter(w, os.Environ()), v...) //nolint:wrapcheck } // Fprint pritnts to the given writer, automatically downsampling colors when @@ -77,8 +77,8 @@ func Fprint(w io.Writer, v ...interface{}) (n int, err error) { // Render("Sandwich time!") // // Fprintln(os.Stderr, str) -func Fprintln(w io.Writer, v ...interface{}) (n int, err error) { - return fmt.Fprintln(colorprofile.NewWriter(w, os.Environ()), v...) +func Fprintln(w io.Writer, v ...interface{}) (int, error) { + return fmt.Fprintln(colorprofile.NewWriter(w, os.Environ()), v...) //nolint:wrapcheck } // Fprintf prints text to a writer, against the given format, automatically @@ -91,6 +91,6 @@ func Fprintln(w io.Writer, v ...interface{}) (n int, err error) { // Render("artichokes") // // Fprintf(os.Stderr, "I really love %s!\n", food) -func Fprintf(w io.Writer, format string, v ...interface{}) (n int, err error) { - return fmt.Fprintf(colorprofile.NewWriter(w, os.Environ()), format, v...) +func Fprintf(w io.Writer, format string, v ...interface{}) (int, error) { + return fmt.Fprintf(colorprofile.NewWriter(w, os.Environ()), format, v...) //nolint:wrapcheck } From 70d7cb608c71e48206b3144546d6d3ee139c2493 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Thu, 17 Oct 2024 15:24:40 -0400 Subject: [PATCH 26/32] chore: rename Adapt back to LightDark --- color.go | 18 +++++++++--------- examples/color/bubbletea/main.go | 8 ++++---- examples/color/standalone/main.go | 2 +- examples/layout/main.go | 16 ++++++++-------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/color.go b/color.go index 4e9e4385..ca581816 100644 --- a/color.go +++ b/color.go @@ -113,11 +113,11 @@ func (c RGBColor) RGBA() (r, g, b, a uint32) { // colorB := lipgloss.ANSIColor(134) type ANSIColor = ansi.ExtendedColor -// Adapt is a simple helper type that can be used to choose the appropriate +// LightDark is a simple helper type that can be used to choose the appropriate // color based on whether the terminal has a light or dark background. // -// adaptive := lipgloss.Adapt(hasDarkBackground) -// theRightColor := adaptive.Color("#0000ff", "#ff0000") +// lightDark := lipgloss.LightDark(hasDarkBackground) +// theRightColor := lightDark.Color("#0000ff", "#ff0000") // // In practice, there are slightly different workflows between Bubble Tea and // Lip Gloss standalone. @@ -130,19 +130,19 @@ type ANSIColor = ansi.ExtendedColor // // Later, when you're rendering: // -// adaptive := lipgloss.Adapt(m.hasDarkBackground) -// myHotColor := adaptive.Color("#ff0000", "#0000ff") +// lightDark := lipgloss.LightDark(m.hasDarkBackground) +// myHotColor := lightDark.Color("#ff0000", "#0000ff") // // In standalone Lip Gloss, the workflow is simpler: // // hasDarkBG, _ := lipgloss.HasDarkBackground(os.Stdin, os.Stdout) -// adaptive := lipgloss.Adapt(hasDarkBG) -// myHotColor := adaptive.Color("#ff0000", "#0000ff") -type Adapt bool +// lightDark := lipgloss.LightDark(hasDarkBG) +// myHotColor := lightDark.Color("#ff0000", "#0000ff") +type LightDark bool // Color returns the color that should be used based on the terminal's // background color. -func (a Adapt) Color(light, dark any) color.Color { +func (a LightDark) Color(light, dark any) color.Color { if bool(a) { return Color(dark) } diff --git a/examples/color/bubbletea/main.go b/examples/color/bubbletea/main.go index 85909dc5..36b399ab 100644 --- a/examples/color/bubbletea/main.go +++ b/examples/color/bubbletea/main.go @@ -24,13 +24,13 @@ func newStyles(backgroundIsDark bool) (s *styles) { // Create a new helper function for choosing either a light or dark color // based on the detected background color. - adaptive := lipgloss.Adapt(backgroundIsDark) + lightDark := lipgloss.LightDark(backgroundIsDark) // Define some styles. adaptive.Color() can be used to choose the // appropriate light or dark color based on the detected background color. s.frame = lipgloss.NewStyle(). Border(lipgloss.RoundedBorder()). - BorderForeground(adaptive.Color("#0000ff", "#6200ff")). + BorderForeground(lightDark.Color("#0000ff", "#6200ff")). Padding(1, 3). Margin(1, 3) s.paragraph = lipgloss.NewStyle(). @@ -38,9 +38,9 @@ func newStyles(backgroundIsDark bool) (s *styles) { MarginBottom(1). Align(lipgloss.Center) s.text = lipgloss.NewStyle(). - Foreground(adaptive.Color("#0000ff", "#bdbdbd")) + Foreground(lightDark.Color("#0000ff", "#bdbdbd")) s.keyword = lipgloss.NewStyle(). - Foreground(adaptive.Color("#0000ff", "#04b87c")). + Foreground(lightDark.Color("#0000ff", "#04b87c")). Bold(true) // You can also use octal format for colors, i.e 0x#ff38ec. diff --git a/examples/color/standalone/main.go b/examples/color/standalone/main.go index 5cab95ef..5be49cc6 100644 --- a/examples/color/standalone/main.go +++ b/examples/color/standalone/main.go @@ -26,7 +26,7 @@ func main() { // Create a new helper function for choosing either a light or dark color // based on the detected background color. - adaptive := lipgloss.Adapt(hasDarkBG) + adaptive := lipgloss.LightDark(hasDarkBG) // Define some styles. adaptive.Color() can be used to choose the // appropriate light or dark color based on the detected background color. diff --git a/examples/layout/main.go b/examples/layout/main.go index a1a033e5..c42c999c 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -29,7 +29,7 @@ var ( // A helper function for choosing either a light or dark color based on the // detected background color. We create this in init(). - adaptive lipgloss.Adapt + lightDark lipgloss.LightDark ) func init() { @@ -44,7 +44,7 @@ func init() { // Create a new helper function for choosing either a light or dark color // based on the detected background color. - adaptive = lipgloss.Adapt(hasDarkBG) + lightDark = lipgloss.LightDark(hasDarkBG) } func main() { @@ -54,9 +54,9 @@ func main() { // General. - subtle = adaptive.Color("#D9DCCF", "#383838") - highlight = adaptive.Color("#874BFD", "#7D56F4") - special = adaptive.Color("#43BF6D", "#73F59F") + subtle = lightDark.Color("#D9DCCF", "#383838") + highlight = lightDark.Color("#874BFD", "#7D56F4") + special = lightDark.Color("#43BF6D", "#73F59F") divider = lipgloss.NewStyle(). SetString("•"). @@ -168,7 +168,7 @@ func main() { listDone = func(s string) string { return checkMark + lipgloss.NewStyle(). Strikethrough(true). - Foreground(adaptive.Color("#969B86", "#696969")). + Foreground(lightDark.Color("#969B86", "#696969")). Render(s) } @@ -190,8 +190,8 @@ func main() { Padding(0, 1) statusBarStyle = lipgloss.NewStyle(). - Foreground(adaptive.Color("#343433", "#C1C6B2")). - Background(adaptive.Color("#D9DCCF", "#353533")) + Foreground(lightDark.Color("#343433", "#C1C6B2")). + Background(lightDark.Color("#D9DCCF", "#353533")) statusStyle = lipgloss.NewStyle(). Inherit(statusBarStyle). From bfae28f25defab55b8543a781e8531b7a595ec91 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Thu, 17 Oct 2024 16:15:43 -0400 Subject: [PATCH 27/32] docs(examples): improve light/dark colors in color examples --- examples/color/bubbletea/main.go | 25 ++++++++++++++----------- examples/color/standalone/main.go | 15 ++++++++------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/examples/color/bubbletea/main.go b/examples/color/bubbletea/main.go index 36b399ab..46143aab 100644 --- a/examples/color/bubbletea/main.go +++ b/examples/color/bubbletea/main.go @@ -30,7 +30,7 @@ func newStyles(backgroundIsDark bool) (s *styles) { // appropriate light or dark color based on the detected background color. s.frame = lipgloss.NewStyle(). Border(lipgloss.RoundedBorder()). - BorderForeground(lightDark.Color("#0000ff", "#6200ff")). + BorderForeground(lightDark.Color("#C5ADF9", "#864EFF")). Padding(1, 3). Margin(1, 3) s.paragraph = lipgloss.NewStyle(). @@ -38,29 +38,31 @@ func newStyles(backgroundIsDark bool) (s *styles) { MarginBottom(1). Align(lipgloss.Center) s.text = lipgloss.NewStyle(). - Foreground(lightDark.Color("#0000ff", "#bdbdbd")) + Foreground(lightDark.Color("#696969", "#bdbdbd")) s.keyword = lipgloss.NewStyle(). - Foreground(lightDark.Color("#0000ff", "#04b87c")). + Foreground(lightDark.Color("#37CD96", "#22C78A")). Bold(true) - // You can also use octal format for colors, i.e 0x#ff38ec. s.activeButton = lipgloss.NewStyle(). Padding(0, 3). - Background(lipgloss.Color(0xf347ff)). - Foreground(lipgloss.Color(0xfaffcc)) + Background(lipgloss.Color(0xFF6AD2)). // you can also use octal format for colors, i.e 0xff38ec. + Foreground(lipgloss.Color(0xFFFCC2)) s.inactiveButton = s.activeButton. - Background(lipgloss.Color(0x545454)) + Background(lightDark.Color(0x988F95, 0x978692)). + Foreground(lightDark.Color(0xFDFCE3, 0xFBFAE7)) return s } type model struct { - styles *styles - yes bool - chosen bool + styles *styles + yes bool + chosen bool + aborted bool } func (m model) Init() (tea.Model, tea.Cmd) { // Query for the background color on start. + m.yes = true return m, tea.BackgroundColor } @@ -76,6 +78,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.KeyPressMsg: switch msg.String() { case "q", "esc", "ctrl+c": + m.aborted = true return m, tea.Quit case "enter": m.chosen = true @@ -102,7 +105,7 @@ func (m model) View() string { // be here in a flash. return "" } - if m.chosen { + if m.chosen || m.aborted { // We're about to exit, so wipe the UI. return "" } diff --git a/examples/color/standalone/main.go b/examples/color/standalone/main.go index 5be49cc6..091756b1 100644 --- a/examples/color/standalone/main.go +++ b/examples/color/standalone/main.go @@ -26,13 +26,13 @@ func main() { // Create a new helper function for choosing either a light or dark color // based on the detected background color. - adaptive := lipgloss.LightDark(hasDarkBG) + lightDark := lipgloss.LightDark(hasDarkBG) // Define some styles. adaptive.Color() can be used to choose the // appropriate light or dark color based on the detected background color. frameStyle := lipgloss.NewStyle(). Border(lipgloss.RoundedBorder()). - BorderForeground(adaptive.Color("#0000ff", "#6200ff")). + BorderForeground(lightDark.Color("#C5ADF9", "#864EFF")). Padding(1, 3). Margin(1, 3) paragraphStyle := lipgloss.NewStyle(). @@ -40,17 +40,18 @@ func main() { MarginBottom(1). Align(lipgloss.Center) textStyle := lipgloss.NewStyle(). - Foreground(adaptive.Color("#0000ff", "#bdbdbd")) + Foreground(lightDark.Color("#696969", "#bdbdbd")) keywordStyle := lipgloss.NewStyle(). - Foreground(adaptive.Color("#0000ff", "#04b87c")). + Foreground(lightDark.Color("#37CD96", "#22C78A")). Bold(true) activeButton := lipgloss.NewStyle(). Padding(0, 3). - Background(lipgloss.Color(0xf347ff)). // you can also use octal format for colors, i.e 0x#ff38ec. - Foreground(lipgloss.Color(0xfaffcc)) + Background(lipgloss.Color(0xFF6AD2)). // you can also use octal format for colors, i.e 0xff38ec. + Foreground(lipgloss.Color(0xFFFCC2)) inactiveButton := activeButton. - Background(lipgloss.Color(0x545454)) + Background(lightDark.Color(0x988F95, 0x978692)). + Foreground(lightDark.Color(0xFDFCE3, 0xFBFAE7)) // Build layout. text := paragraphStyle.Render( From 83dd196f3a5999684fc4f5dd576f511850f90ee9 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Thu, 17 Oct 2024 16:16:31 -0400 Subject: [PATCH 28/32] chore(deps): use current v2-exp branch in Bubble Tea in examples --- examples/go.mod | 2 +- examples/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index cc252208..914b3cf0 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -9,7 +9,7 @@ replace github.com/charmbracelet/lipgloss/list => ../list replace github.com/charmbracelet/lipgloss/table => ../table require ( - github.com/charmbracelet/bubbletea/v2 v2.0.0-alpha.1 + github.com/charmbracelet/bubbletea/v2 v2.0.0-alpha.1.0.20241016204941-d95e2750ec12 github.com/charmbracelet/colorprofile v0.1.2 github.com/charmbracelet/lipgloss v0.13.1-0.20240822211938-b89f1a3db2a4 github.com/charmbracelet/ssh v0.0.0-20240401141849-854cddfa2917 diff --git a/examples/go.sum b/examples/go.sum index ee76067e..c611d60f 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -5,8 +5,8 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM= github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg= -github.com/charmbracelet/bubbletea/v2 v2.0.0-alpha.1 h1:OZtpLCsuuPplC+1oyUo+/eAN7e9MC2UyZWKlKrVlUnw= -github.com/charmbracelet/bubbletea/v2 v2.0.0-alpha.1/go.mod h1:j0gn4ft5CE7NDYNZjAA3hBM8t2OPjI8urxuAD0oR4w8= +github.com/charmbracelet/bubbletea/v2 v2.0.0-alpha.1.0.20241016204941-d95e2750ec12 h1:w1Dt/pl0gXE6PO2U+EUMoeMiSHe07/RR1Slcy9cH6kQ= +github.com/charmbracelet/bubbletea/v2 v2.0.0-alpha.1.0.20241016204941-d95e2750ec12/go.mod h1:8vhUTCIihfP3GfyyfznbOU7XyFe/ID1n7pdh/uT5Rug= github.com/charmbracelet/colorprofile v0.1.2 h1:nuB1bd/yAExT4fkcZvpqtQ2N5/8cJHSRIKb6CzT7lAM= github.com/charmbracelet/colorprofile v0.1.2/go.mod h1:1htIKZYeI4TQs+OykPvpuBTUbUJxBYeSYBDIZuejMj0= github.com/charmbracelet/keygen v0.5.0 h1:XY0fsoYiCSM9axkrU+2ziE6u6YjJulo/b9Dghnw6MZc= From 6faf40aad31025ed89dcd3686aa4e1eb0971d56d Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Thu, 17 Oct 2024 16:27:07 -0400 Subject: [PATCH 29/32] chore: simplify LightDark API --- color.go | 32 ++++++++++++++++++++----------- examples/color/bubbletea/main.go | 10 +++++----- examples/color/standalone/main.go | 10 +++++----- examples/layout/main.go | 14 +++++++------- 4 files changed, 38 insertions(+), 28 deletions(-) diff --git a/color.go b/color.go index ca581816..d21c92b8 100644 --- a/color.go +++ b/color.go @@ -113,11 +113,23 @@ func (c RGBColor) RGBA() (r, g, b, a uint32) { // colorB := lipgloss.ANSIColor(134) type ANSIColor = ansi.ExtendedColor +// LightDarkFunc is a function that returns a color based on whether the +// terminal has a light or dark background. You can create one of these with +// [LightDark]. +// +// Example: +// +// lightDark := lipgloss.LightDark(hasDarkBackground) +// myHotColor := lightDark("#ff0000", "#0000ff") +// +// For more info see [LightDark]. +type LightDarkFunc func(light, dark any) color.Color + // LightDark is a simple helper type that can be used to choose the appropriate // color based on whether the terminal has a light or dark background. // // lightDark := lipgloss.LightDark(hasDarkBackground) -// theRightColor := lightDark.Color("#0000ff", "#ff0000") +// theRightColor := lightDark("#0000ff", "#ff0000") // // In practice, there are slightly different workflows between Bubble Tea and // Lip Gloss standalone. @@ -131,22 +143,20 @@ type ANSIColor = ansi.ExtendedColor // Later, when you're rendering: // // lightDark := lipgloss.LightDark(m.hasDarkBackground) -// myHotColor := lightDark.Color("#ff0000", "#0000ff") +// myHotColor := lightDark("#ff0000", "#0000ff") // // In standalone Lip Gloss, the workflow is simpler: // // hasDarkBG, _ := lipgloss.HasDarkBackground(os.Stdin, os.Stdout) // lightDark := lipgloss.LightDark(hasDarkBG) -// myHotColor := lightDark.Color("#ff0000", "#0000ff") -type LightDark bool - -// Color returns the color that should be used based on the terminal's -// background color. -func (a LightDark) Color(light, dark any) color.Color { - if bool(a) { - return Color(dark) +// myHotColor := lightDark("#ff0000", "#0000ff") +func LightDark(isDark bool) LightDarkFunc { + return func(light, dark any) color.Color { + if isDark { + return Color(dark) + } + return Color(light) } - return Color(light) } // IsDarkColor returns whether the given color is dark (based on the luminance diff --git a/examples/color/bubbletea/main.go b/examples/color/bubbletea/main.go index 46143aab..a144f5c7 100644 --- a/examples/color/bubbletea/main.go +++ b/examples/color/bubbletea/main.go @@ -30,7 +30,7 @@ func newStyles(backgroundIsDark bool) (s *styles) { // appropriate light or dark color based on the detected background color. s.frame = lipgloss.NewStyle(). Border(lipgloss.RoundedBorder()). - BorderForeground(lightDark.Color("#C5ADF9", "#864EFF")). + BorderForeground(lightDark("#C5ADF9", "#864EFF")). Padding(1, 3). Margin(1, 3) s.paragraph = lipgloss.NewStyle(). @@ -38,9 +38,9 @@ func newStyles(backgroundIsDark bool) (s *styles) { MarginBottom(1). Align(lipgloss.Center) s.text = lipgloss.NewStyle(). - Foreground(lightDark.Color("#696969", "#bdbdbd")) + Foreground(lightDark("#696969", "#bdbdbd")) s.keyword = lipgloss.NewStyle(). - Foreground(lightDark.Color("#37CD96", "#22C78A")). + Foreground(lightDark("#37CD96", "#22C78A")). Bold(true) s.activeButton = lipgloss.NewStyle(). @@ -48,8 +48,8 @@ func newStyles(backgroundIsDark bool) (s *styles) { Background(lipgloss.Color(0xFF6AD2)). // you can also use octal format for colors, i.e 0xff38ec. Foreground(lipgloss.Color(0xFFFCC2)) s.inactiveButton = s.activeButton. - Background(lightDark.Color(0x988F95, 0x978692)). - Foreground(lightDark.Color(0xFDFCE3, 0xFBFAE7)) + Background(lightDark(0x988F95, 0x978692)). + Foreground(lightDark(0xFDFCE3, 0xFBFAE7)) return s } diff --git a/examples/color/standalone/main.go b/examples/color/standalone/main.go index 091756b1..b71c4308 100644 --- a/examples/color/standalone/main.go +++ b/examples/color/standalone/main.go @@ -32,7 +32,7 @@ func main() { // appropriate light or dark color based on the detected background color. frameStyle := lipgloss.NewStyle(). Border(lipgloss.RoundedBorder()). - BorderForeground(lightDark.Color("#C5ADF9", "#864EFF")). + BorderForeground(lightDark("#C5ADF9", "#864EFF")). Padding(1, 3). Margin(1, 3) paragraphStyle := lipgloss.NewStyle(). @@ -40,9 +40,9 @@ func main() { MarginBottom(1). Align(lipgloss.Center) textStyle := lipgloss.NewStyle(). - Foreground(lightDark.Color("#696969", "#bdbdbd")) + Foreground(lightDark("#696969", "#bdbdbd")) keywordStyle := lipgloss.NewStyle(). - Foreground(lightDark.Color("#37CD96", "#22C78A")). + Foreground(lightDark("#37CD96", "#22C78A")). Bold(true) activeButton := lipgloss.NewStyle(). @@ -50,8 +50,8 @@ func main() { Background(lipgloss.Color(0xFF6AD2)). // you can also use octal format for colors, i.e 0xff38ec. Foreground(lipgloss.Color(0xFFFCC2)) inactiveButton := activeButton. - Background(lightDark.Color(0x988F95, 0x978692)). - Foreground(lightDark.Color(0xFDFCE3, 0xFBFAE7)) + Background(lightDark(0x988F95, 0x978692)). + Foreground(lightDark(0xFDFCE3, 0xFBFAE7)) // Build layout. text := paragraphStyle.Render( diff --git a/examples/layout/main.go b/examples/layout/main.go index c42c999c..e594acf1 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -29,7 +29,7 @@ var ( // A helper function for choosing either a light or dark color based on the // detected background color. We create this in init(). - lightDark lipgloss.LightDark + lightDark lipgloss.LightDarkFunc ) func init() { @@ -54,9 +54,9 @@ func main() { // General. - subtle = lightDark.Color("#D9DCCF", "#383838") - highlight = lightDark.Color("#874BFD", "#7D56F4") - special = lightDark.Color("#43BF6D", "#73F59F") + subtle = lightDark("#D9DCCF", "#383838") + highlight = lightDark("#874BFD", "#7D56F4") + special = lightDark("#43BF6D", "#73F59F") divider = lipgloss.NewStyle(). SetString("•"). @@ -168,7 +168,7 @@ func main() { listDone = func(s string) string { return checkMark + lipgloss.NewStyle(). Strikethrough(true). - Foreground(lightDark.Color("#969B86", "#696969")). + Foreground(lightDark("#969B86", "#696969")). Render(s) } @@ -190,8 +190,8 @@ func main() { Padding(0, 1) statusBarStyle = lipgloss.NewStyle(). - Foreground(lightDark.Color("#343433", "#C1C6B2")). - Background(lightDark.Color("#D9DCCF", "#353533")) + Foreground(lightDark("#343433", "#C1C6B2")). + Background(lightDark("#D9DCCF", "#353533")) statusStyle = lipgloss.NewStyle(). Inherit(statusBarStyle). From 0d5d57aa0699537b8625749c54af91237189b0bb Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Thu, 17 Oct 2024 17:11:17 -0400 Subject: [PATCH 30/32] docs(examples): restore removed light-dark (formerly adaptive) colors --- examples/list/sublist/main.go | 15 +++++++++++++-- examples/ssh/main.go | 4 +++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/examples/list/sublist/main.go b/examples/list/sublist/main.go index d6cd1c43..fd3f7086 100644 --- a/examples/list/sublist/main.go +++ b/examples/list/sublist/main.go @@ -1,6 +1,9 @@ package main import ( + "fmt" + "os" + "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/list" "github.com/charmbracelet/lipgloss/table" @@ -8,6 +11,14 @@ import ( ) func main() { + hasDarkBG, err := lipgloss.HasDarkBackground(os.Stdin, os.Stdout) + if err != nil { + fmt.Fprintf(os.Stderr, "Could not detect background color: %v\n", err) + os.Exit(1) + } + + lightDark := lipgloss.LightDark(hasDarkBG) + purple := lipgloss.NewStyle(). Foreground(lipgloss.Color("99")). MarginRight(1) @@ -25,7 +36,7 @@ func main() { dim := lipgloss.Color("250") highlight := lipgloss.Color("#EE6FF8") - special := lipgloss.Color("#73F59F") + special := lightDark("#43BF6D", "#73F59F") checklistEnumStyle := func(items list.Items, index int) lipgloss.Style { switch index { @@ -52,7 +63,7 @@ func main() { case 1, 2, 4: return lipgloss.NewStyle(). Strikethrough(true). - Foreground(lipgloss.Color("#696969")) + Foreground(lightDark("#969B86", "#696969")) default: return lipgloss.NewStyle() } diff --git a/examples/ssh/main.go b/examples/ssh/main.go index 1d23243b..fd8383d1 100644 --- a/examples/ssh/main.go +++ b/examples/ssh/main.go @@ -108,6 +108,8 @@ func handler(next ssh.Handler) ssh.Handler { return } + lightDark := lipgloss.LightDark(hasDarkBG) + fmt.Fprintf(&str, "%s %s\n\n", styles.bold.UnsetString().Render("Has dark background?"), func() string { @@ -121,7 +123,7 @@ func handler(next ssh.Handler) ssh.Handler { block := lipgloss.Place(width, lipgloss.Height(str.String()), lipgloss.Center, lipgloss.Center, str.String(), lipgloss.WithWhitespaceChars("/"), - lipgloss.WithWhitespaceStyle(lipgloss.NewStyle().Foreground(lipgloss.Color(236))), + lipgloss.WithWhitespaceStyle(lipgloss.NewStyle().Foreground(lightDark(250, 236))), ) // Render to client. From 4b0b6a2ac54d17aac3f5beb2e8733a67fbb41246 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Thu, 17 Oct 2024 21:21:28 -0400 Subject: [PATCH 31/32] docs(examples): remove cool FP-like expression Co-authored-by: Ayman Bagabas --- examples/layout/main.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/layout/main.go b/examples/layout/main.go index e594acf1..039a2e76 100644 --- a/examples/layout/main.go +++ b/examples/layout/main.go @@ -338,12 +338,10 @@ func main() { { w := lipgloss.Width - lightDarkState := func() string { - if hasDarkBG { - return "Dark" - } - return "Light" - }() + lightDarkState := "Light" + if hasDarkBG { + lightDarkState = "Dark" + } statusKey := statusStyle.Render("STATUS") encoding := encodingStyle.Render("UTF-8") From 7256ef29b6001882bdd9ad23c7bd18cf0f1554c3 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Thu, 17 Oct 2024 21:17:25 -0400 Subject: [PATCH 32/32] chore(lint): wrap error in BackgroundColor() --- query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query.go b/query.go index c510950e..3dd68099 100644 --- a/query.go +++ b/query.go @@ -18,7 +18,7 @@ import ( func BackgroundColor(in *os.File, out *os.File) (color.Color, error) { state, err := term.MakeRaw(in.Fd()) if err != nil { - return nil, err + return nil, fmt.Errorf("error setting raw state to detect background color: %w", err) } defer term.Restore(in.Fd(), state) //nolint:errcheck