Skip to content

Commit

Permalink
feat!: purify lipgloss Style
Browse files Browse the repository at this point in the history
  • Loading branch information
aymanbagabas committed May 10, 2024
1 parent 61f326c commit ac39caa
Show file tree
Hide file tree
Showing 24 changed files with 282 additions and 331 deletions.
2 changes: 1 addition & 1 deletion align.go
Expand Up @@ -3,7 +3,7 @@ package lipgloss
import (
"strings"

"github.com/charmbracelet/x/exp/term/ansi"
"github.com/charmbracelet/x/ansi"
)

// Perform text alignment. If the string is multi-lined, we also make all lines
Expand Down
13 changes: 6 additions & 7 deletions borders.go
Expand Up @@ -3,7 +3,7 @@ package lipgloss
import (
"strings"

"github.com/charmbracelet/x/exp/term/ansi"
"github.com/charmbracelet/x/ansi"
"github.com/rivo/uniseg"
)

Expand Down Expand Up @@ -406,14 +406,13 @@ func (s Style) styleBorder(border string, fg, bg TerminalColor) string {
return border
}

p := s.r.ColorProfile()

var style ansi.Style
if fg != noColor && p > Ascii {
style = style.ForegroundColor(fg.color(s.r))
isColorable := s.profile < Ascii
if fg != noColor && isColorable {
style = style.ForegroundColor(fg.color(s.profile, s.hasLightBackground))
}
if bg != noColor && p > Ascii {
style = style.BackgroundColor(bg.color(s.r))
if bg != noColor && isColorable {
style = style.BackgroundColor(bg.color(s.profile, s.hasLightBackground))
}

return style.Styled(border)
Expand Down
33 changes: 16 additions & 17 deletions color.go
Expand Up @@ -3,13 +3,13 @@ package lipgloss
import (
"image/color"

"github.com/charmbracelet/x/exp/term/ansi"
"github.com/charmbracelet/x/ansi"
"github.com/lucasb-eyer/go-colorful"
)

// TerminalColor is a color intended to be rendered in the terminal.
type TerminalColor interface {
color(*Renderer) ansi.Color
color(p Profile, hasLightBg bool) ansi.Color
}

var noColor = NoColor{}
Expand All @@ -23,7 +23,7 @@ var noColor = NoColor{}
// var style = someStyle.Copy().Background(lipgloss.NoColor{})
type NoColor struct{}

func (NoColor) color(*Renderer) ansi.Color {
func (NoColor) color(Profile, bool) ansi.Color {
return color.Black
}

Expand All @@ -42,8 +42,8 @@ func (n NoColor) RGBA() (r, g, b, a uint32) {
// hexColor := lipgloss.Color("#0000ff")
type Color string

func (c Color) color(r *Renderer) ansi.Color {
return r.ColorProfile().Color(string(c))
func (c Color) color(p Profile, _ bool) ansi.Color {
return p.Color(string(c))
}

// ANSIColor is a color specified by an ANSI256 color value.
Expand All @@ -54,8 +54,8 @@ func (c Color) color(r *Renderer) ansi.Color {
// colorB := lipgloss.ANSIColor(134)
type ANSIColor uint8

func (ac ANSIColor) color(r *Renderer) ansi.Color {
return r.ColorProfile().Convert(ansi.ExtendedColor(ac))
func (ac ANSIColor) color(p Profile, _ bool) ansi.Color {
return p.Convert(ansi.ExtendedColor(ac))
}

// AdaptiveColor provides color options for light and dark backgrounds. The
Expand All @@ -70,11 +70,11 @@ type AdaptiveColor struct {
Dark string
}

func (ac AdaptiveColor) color(r *Renderer) ansi.Color {
if r.HasDarkBackground() {
return Color(ac.Dark).color(r)
func (ac AdaptiveColor) color(p Profile, hasLightBg bool) ansi.Color {
if hasLightBg {
return Color(ac.Light).color(p, hasLightBg)
}
return Color(ac.Light).color(r)
return Color(ac.Dark).color(p, hasLightBg)
}

// CompleteColor specifies exact values for truecolor, ANSI256, and ANSI color
Expand All @@ -85,8 +85,7 @@ type CompleteColor struct {
ANSI string
}

func (c CompleteColor) color(r *Renderer) ansi.Color {
p := r.ColorProfile()
func (c CompleteColor) color(p Profile, hasLightBg bool) ansi.Color {
switch p { //nolint:exhaustive
case TrueColor:
return p.Color(c.TrueColor)
Expand All @@ -107,11 +106,11 @@ type CompleteAdaptiveColor struct {
Dark CompleteColor
}

func (cac CompleteAdaptiveColor) color(r *Renderer) ansi.Color {
if r.HasDarkBackground() {
return cac.Dark.color(r)
func (cac CompleteAdaptiveColor) color(p Profile, hasLightBg bool) ansi.Color {
if hasLightBg {
return cac.Light.color(p, hasLightBg)
}
return cac.Light.color(r)
return cac.Light.color(p, hasLightBg)
}

// ConvertToRGB converts a Color to a colorful.Color.
Expand Down
32 changes: 32 additions & 0 deletions default.go
@@ -0,0 +1,32 @@
package lipgloss

import (
"os"

"github.com/charmbracelet/x/term"

Check failure on line 6 in default.go

View workflow job for this annotation

GitHub Actions / test-goos

github.com/charmbracelet/x/term@v0.1.0: replacement directory ../x/term does not exist

Check failure on line 6 in default.go

View workflow job for this annotation

GitHub Actions / coverage (^1, ubuntu-latest)

github.com/charmbracelet/x/term@v0.1.0: replacement directory ../x/term does not exist
)

var (
// ColorProfile is the color profile used by lipgloss.
// This is the default color profile used to create new styles.
// By default, it allows for 24-bit color (TrueColor), decorations, and
// doesn't do color conversion.
ColorProfile Profile

// HasLightBackground is true if the terminal has a light background.
// This is the default value used to create new styles.
HasLightBackground bool
)

// UseDefault will set the default color profile and background color detection
// from the given terminal file descriptors and environment variables.
func UseDefault(in term.File, out term.File, env []string) {
ColorProfile = DetectColorProfile(out, env)
HasLightBackground = QueryHasLightBackground(in, out)
}

// UseStdDefaults will set the default color profile and background color
// detection from the standard input, output, and OS environment variables.
func UseStdDefaults() {
UseDefault(os.Stdin, os.Stdout, os.Environ())
}
26 changes: 26 additions & 0 deletions defaults/defaults.go
@@ -0,0 +1,26 @@
// Package defaults is a helper package that sets the default Lip Gloss profile
// and background color detection from the standard input, output, and OS
// environment variables.
//
// This is useful for standalone Lip Gloss applications that only use the
// standard input and output i.e. only run locally in a terminal.
// You can simply import this package to set the default profile and background
// color detection for Lip Gloss styles.
//
// package main
//
// import (
// "github.com/charmbracelet/lipgloss"
// _ "github.com/charmbracelet/lipgloss/defaults" // use std profile defaults
// )
//
// func main() {
// // Your code here
// }
package defaults

import "github.com/charmbracelet/lipgloss"

func init() {
lipgloss.UseStdDefaults()
}
47 changes: 38 additions & 9 deletions env.go
Expand Up @@ -5,7 +5,8 @@ import (
"strconv"
"strings"

"github.com/charmbracelet/x/exp/term"
"github.com/charmbracelet/x/term"
"github.com/lucasb-eyer/go-colorful"
)

// DetectColorProfile returns the color profile based on the terminal output,
Expand All @@ -16,7 +17,7 @@ import (
// CLICOLOR/CLICOLOR_FORCE environment variables.
//
// See https://no-color.org/ and https://bixense.com/clicolors/ for more information.
func DetectColorProfile(stdout *os.File, environ []string) Profile {
func DetectColorProfile(stdout term.File, environ []string) Profile {
if environ == nil {
environ = os.Environ()
}
Expand All @@ -27,20 +28,47 @@ func DetectColorProfile(stdout *os.File, environ []string) Profile {
p = NoTTY
}

if envNoColor(env) && p > Ascii {
if envNoColor(env) && p < Ascii {
return Ascii
}

if cliColorForced(env) && p <= Ascii {
if cliColorForced(env) && p >= Ascii {
p = ANSI
if cp := envColorProfile(env); cp > p {
if cp := envColorProfile(env); cp < p {
p = cp
}
}

return p
}

// QueryHasLightBackground returns true if the terminal has a light background.
func QueryHasLightBackground(in term.File, out term.File) bool {
if !term.IsTerminal(out.Fd()) {
return false
}

state, err := term.MakeRaw(in.Fd())
if err != nil {
return false
}

defer term.Restore(in.Fd(), state) // nolint:errcheck

c, err := term.QueryBackgroundColor(in, out)
if err != nil {
return false
}

col, ok := colorful.MakeColor(c)
if !ok {
return false
}

_, _, l := col.Hsl()
return l > 0.5
}

// EnvColorProfile returns the color profile based on environment variables.
//
// This respects the NO_COLOR and CLICOLOR/CLICOLOR_FORCE environment
Expand All @@ -54,13 +82,13 @@ func EnvColorProfile(environ []string) Profile {

env := environMap(environ)
p := envColorProfile(env)
if envNoColor(env) && p > Ascii {
if envNoColor(env) && p < Ascii {
return Ascii
}

if cliColorForced(env) && p <= Ascii {
if cliColorForced(env) && p >= Ascii {
p = ANSI
if cp := envColorProfile(env); cp > p {
if cp := envColorProfile(env); cp < p {
p = cp
}
}
Expand All @@ -86,8 +114,9 @@ func cliColorForced(env map[string]string) bool {

// envColorProfile returns infers the color profile from the environment.
func envColorProfile(env map[string]string) (p Profile) {
p = Ascii // Default to ASCII
setProfile := func(profile Profile) {
if profile > p {
if profile < p {
p = profile
}
}
Expand Down
15 changes: 15 additions & 0 deletions examples/box/main.go
@@ -0,0 +1,15 @@
package main

import (
"fmt"

"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/x/exp/term/ansi"
)

var box = lipgloss.NewStyle().Width(8).Height(8).Border(lipgloss.RoundedBorder())

func main() {
// fmt.Println(box.Render("สวัสดีสวัสดี" + "สวัสดีสวัสดี"))
fmt.Println(box.Render("สวัสดีสวัสดี" + ansi.SetHyperlink("http://example.com") + "สวัสดีสวัสดี" + ansi.ResetHyperlink()))
}
3 changes: 2 additions & 1 deletion examples/layout/main.go
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

"github.com/charmbracelet/lipgloss"
_ "github.com/charmbracelet/lipgloss/defaults" // use std profile defaults
"github.com/lucasb-eyer/go-colorful"
"golang.org/x/term"
)
Expand Down Expand Up @@ -243,7 +244,7 @@ func main() {
lipgloss.Center, lipgloss.Center,
dialogBoxStyle.Render(ui),
lipgloss.WithWhitespaceChars("猫咪"),
lipgloss.WithWhitespaceForeground(subtle),
lipgloss.WithWhitespaceStyle(lipgloss.NewStyle().Foreground(subtle)),
)

doc.WriteString(dialog + "\n\n")
Expand Down
30 changes: 30 additions & 0 deletions examples/newline/main.go
@@ -0,0 +1,30 @@
package main

import (
"fmt"

"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/x/exp/term/ansi"
)

func main() {
str := "1 "
red := lipgloss.Color("9")

style1 := lipgloss.NewStyle().
Foreground(red).
Render(str)

style2 := lipgloss.NewStyle().
Width(1).
Render(style1)

fmt.Println("Lipgloss")
fmt.Printf("Before Width: '%v'\n", style1)
fmt.Printf("After Width : '%v'\n", style2)
fmt.Println()

fmt.Println("ANSI")
fmt.Printf("ASCII Width : '%v'\n", ansi.Wrap(str, 1, ""))
fmt.Printf("ANSI Width : '%v'\n", ansi.Wrap(style1, 1, ""))
}
18 changes: 18 additions & 0 deletions examples/spaced/main.go
@@ -0,0 +1,18 @@
package main

import (
"fmt"

"github.com/charmbracelet/lipgloss"
)

func main() {
fancy := "Fancy"
fmt.Println(fancy)

fancyBold := lipgloss.NewStyle().Bold(true).Render(fancy)
fmt.Printf("%q\n", fancyBold)

fancyBoldStrikethrough := lipgloss.NewStyle().Strikethrough(true).Render(fancyBold)
fmt.Printf("%q\n", fancyBoldStrikethrough)
}
2 changes: 1 addition & 1 deletion get.go
Expand Up @@ -3,7 +3,7 @@ package lipgloss
import (
"strings"

"github.com/charmbracelet/x/exp/term/ansi"
"github.com/charmbracelet/x/ansi"
)

// GetBold returns the style's bold value. If no value is set false is returned.
Expand Down
9 changes: 7 additions & 2 deletions go.mod
Expand Up @@ -5,14 +5,19 @@ retract v0.7.0 // v0.7.0 introduces a bug that causes some apps to freeze.
go 1.18

require (
github.com/charmbracelet/x/exp/term v0.0.0-20240425164147-ba2a9512b05f
github.com/charmbracelet/x/ansi v0.1.0
github.com/charmbracelet/x/term v0.1.0
github.com/lucasb-eyer/go-colorful v1.2.0
github.com/rivo/uniseg v0.4.7
golang.org/x/sys v0.19.0
golang.org/x/sys v0.20.0
)

require (
github.com/charmbracelet/x/input v0.1.0 // indirect
github.com/charmbracelet/x/windows v0.1.0 // indirect
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
)

replace github.com/charmbracelet/x/term => ../x/term

0 comments on commit ac39caa

Please sign in to comment.