Skip to content

Commit

Permalink
feat!: introduce color profiles and use term/ansi for styles
Browse files Browse the repository at this point in the history
This introduces color profiles similar to Termenv color profiles.
Plus, it switches to using Charmbracelet term & term/ansi to query
terminal background color for the default renderer, and construct styles.

However, it breaks the renderer API since it doesn't depend on Termenv
anymore.
  • Loading branch information
aymanbagabas committed Mar 28, 2024
1 parent 9a9f026 commit a5e85e1
Show file tree
Hide file tree
Showing 18 changed files with 883 additions and 223 deletions.
16 changes: 12 additions & 4 deletions align.go
Expand Up @@ -3,14 +3,22 @@ package lipgloss
import (
"strings"

<<<<<<< HEAD

Check failure on line 6 in align.go

View workflow job for this annotation

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

missing import path

Check failure on line 6 in align.go

View workflow job for this annotation

GitHub Actions / test (~1.18, ubuntu-latest)

expected 'STRING', found '<<'

Check failure on line 6 in align.go

View workflow job for this annotation

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

missing import path

Check failure on line 6 in align.go

View workflow job for this annotation

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

missing import path

Check failure on line 6 in align.go

View workflow job for this annotation

GitHub Actions / test (^1, macos-latest)

missing import path

Check failure on line 6 in align.go

View workflow job for this annotation

GitHub Actions / test (~1.18, ubuntu-latest)

expected 'STRING', found '<<'

Check failure on line 6 in align.go

View workflow job for this annotation

GitHub Actions / lint

missing import path (typecheck)

Check failure on line 6 in align.go

View workflow job for this annotation

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

missing import path

Check failure on line 6 in align.go

View workflow job for this annotation

GitHub Actions / lint

missing import path (typecheck)

Check failure on line 6 in align.go

View workflow job for this annotation

GitHub Actions / lint-soft

missing import path (typecheck)

Check failure on line 6 in align.go

View workflow job for this annotation

GitHub Actions / lint-soft

missing import path (typecheck)
"github.com/charmbracelet/x/exp/term/ansi"
=======

Check failure on line 8 in align.go

View workflow job for this annotation

GitHub Actions / lint

missing import path (typecheck)

Check failure on line 8 in align.go

View workflow job for this annotation

GitHub Actions / lint

missing import path (typecheck)

Check failure on line 8 in align.go

View workflow job for this annotation

GitHub Actions / lint-soft

missing import path (typecheck)

Check failure on line 8 in align.go

View workflow job for this annotation

GitHub Actions / lint-soft

missing import path (typecheck)
<<<<<<< HEAD
"github.com/muesli/reflow/ansi"
>>>>>>> dd49ed05492e (feat!: introduce color profiles and use term/ansi for styles)

Check failure on line 11 in align.go

View workflow job for this annotation

GitHub Actions / lint

missing import path (typecheck)

Check failure on line 11 in align.go

View workflow job for this annotation

GitHub Actions / lint

missing import path (typecheck)

Check failure on line 11 in align.go

View workflow job for this annotation

GitHub Actions / lint-soft

missing import path (typecheck)

Check failure on line 11 in align.go

View workflow job for this annotation

GitHub Actions / lint-soft

missing import path (typecheck)
"github.com/muesli/termenv"

Check failure on line 12 in align.go

View workflow job for this annotation

GitHub Actions / lint

expected declaration, found "github.com/muesli/termenv" (typecheck)

Check failure on line 12 in align.go

View workflow job for this annotation

GitHub Actions / lint-soft

expected declaration, found "github.com/muesli/termenv" (typecheck)
=======
"github.com/charmbracelet/x/exp/term/ansi"
>>>>>>> d3d126dc69c7 (feat!: introduce color profiles and use term/ansi for styles)
)

// Perform text alignment. If the string is multi-lined, we also make all lines
// the same width by padding them with spaces. If a termenv style is passed,
// use that to style the spaces added.
func alignTextHorizontal(str string, pos Position, width int, style *termenv.Style) string {
// the same width by padding them with spaces. If a style is passed, use that
// to style the spaces added.
func alignTextHorizontal(str string, pos Position, width int, style *style) string {
lines, widestLine := getLines(str)
var b strings.Builder

Expand Down Expand Up @@ -59,7 +67,7 @@ func alignTextHorizontal(str string, pos Position, width int, style *termenv.Sty
return b.String()
}

func alignTextVertical(str string, pos Position, height int, _ *termenv.Style) string {
func alignTextVertical(str string, pos Position, height int, _ *style) string {
strHeight := strings.Count(str, "\n") + 1
if height < strHeight {
return str
Expand Down
21 changes: 19 additions & 2 deletions ansi_windows.go
Expand Up @@ -6,7 +6,7 @@ package lipgloss
import (
"sync"

"github.com/muesli/termenv"
"golang.org/x/sys/windows"
)

var enableANSI sync.Once
Expand All @@ -17,6 +17,23 @@ var enableANSI sync.Once
// by default.
func enableLegacyWindowsANSI() {
enableANSI.Do(func() {
_, _ = termenv.EnableWindowsANSIConsole()
handle, err := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE)
if err != nil {
return
}

var mode uint32
err = windows.GetConsoleMode(handle, &mode)
if err != nil {
return
}

// See https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
if mode&windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING {
vtpmode := mode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
if err := windows.SetConsoleMode(handle, vtpmode); err != nil {
return
}
}
})
}
14 changes: 11 additions & 3 deletions borders.go
Expand Up @@ -3,8 +3,16 @@ package lipgloss
import (
"strings"

<<<<<<< HEAD

Check failure on line 6 in borders.go

View workflow job for this annotation

GitHub Actions / lint

missing import path (typecheck)

Check failure on line 6 in borders.go

View workflow job for this annotation

GitHub Actions / lint

missing import path (typecheck)

Check failure on line 6 in borders.go

View workflow job for this annotation

GitHub Actions / lint-soft

missing import path (typecheck)

Check failure on line 6 in borders.go

View workflow job for this annotation

GitHub Actions / lint-soft

missing import path (typecheck)
"github.com/charmbracelet/x/exp/term/ansi"
=======

Check failure on line 8 in borders.go

View workflow job for this annotation

GitHub Actions / lint

missing import path (typecheck)

Check failure on line 8 in borders.go

View workflow job for this annotation

GitHub Actions / lint

missing import path (typecheck)

Check failure on line 8 in borders.go

View workflow job for this annotation

GitHub Actions / lint-soft

missing import path (typecheck)

Check failure on line 8 in borders.go

View workflow job for this annotation

GitHub Actions / lint-soft

missing import path (typecheck)
<<<<<<< HEAD
"github.com/muesli/reflow/ansi"
>>>>>>> dd49ed05492e (feat!: introduce color profiles and use term/ansi for styles)

Check failure on line 11 in borders.go

View workflow job for this annotation

GitHub Actions / lint

missing import path (typecheck)

Check failure on line 11 in borders.go

View workflow job for this annotation

GitHub Actions / lint

missing import path (typecheck)

Check failure on line 11 in borders.go

View workflow job for this annotation

GitHub Actions / lint-soft

missing import path (typecheck)

Check failure on line 11 in borders.go

View workflow job for this annotation

GitHub Actions / lint-soft

missing import path (typecheck)
"github.com/muesli/termenv"

Check failure on line 12 in borders.go

View workflow job for this annotation

GitHub Actions / lint

expected declaration, found "github.com/muesli/termenv" (typecheck)

Check failure on line 12 in borders.go

View workflow job for this annotation

GitHub Actions / lint-soft

expected declaration, found "github.com/muesli/termenv" (typecheck)
=======
"github.com/charmbracelet/x/exp/term/ansi"
>>>>>>> d3d126dc69c7 (feat!: introduce color profiles and use term/ansi for styles)
"github.com/rivo/uniseg"
)

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

style := termenv.Style{}
style := s.r.ColorProfile().string()

if fg != noColor {
style = style.Foreground(fg.color(s.r))
style = style.ForegroundColor(fg.color(s.r))
}
if bg != noColor {
style = style.Background(bg.color(s.r))
style = style.BackgroundColor(bg.color(s.r))
}

return style.Styled(border)
Expand Down
49 changes: 28 additions & 21 deletions color.go
Expand Up @@ -3,12 +3,13 @@ package lipgloss
import (
"strconv"

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

// TerminalColor is a color intended to be rendered in the terminal.
type TerminalColor interface {
color(*Renderer) termenv.Color
color(*Renderer) ansi.Color
RGBA() (r, g, b, a uint32)
}

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

func (NoColor) color(*Renderer) termenv.Color {
return termenv.NoColor{}
func (NoColor) color(*Renderer) ansi.Color {
return nil
}

// RGBA returns the RGBA value of this color. Because we have to return
Expand All @@ -44,8 +45,8 @@ func (n NoColor) RGBA() (r, g, b, a uint32) {
// hexColor := lipgloss.Color("#0000ff")
type Color string

func (c Color) color(r *Renderer) termenv.Color {
return r.ColorProfile().Color(string(c))
func (c Color) color(r *Renderer) ansi.Color {
return r.ColorProfile().color(string(c))
}

// RGBA returns the RGBA value of this color. This satisfies the Go Color
Expand All @@ -55,7 +56,7 @@ func (c Color) color(r *Renderer) termenv.Color {
//
// Deprecated.
func (c Color) RGBA() (r, g, b, a uint32) {
return termenv.ConvertToRGB(c.color(renderer)).RGBA()
return c.color(DefaultRenderer()).RGBA()
}

// ANSIColor is a color specified by an ANSI color value. It's merely syntactic
Expand All @@ -69,7 +70,7 @@ func (c Color) RGBA() (r, g, b, a uint32) {
// colorB := lipgloss.Color("21")
type ANSIColor uint

func (ac ANSIColor) color(r *Renderer) termenv.Color {
func (ac ANSIColor) color(r *Renderer) ansi.Color {
return Color(strconv.FormatUint(uint64(ac), 10)).color(r)
}

Expand All @@ -96,7 +97,7 @@ type AdaptiveColor struct {
Dark string
}

func (ac AdaptiveColor) color(r *Renderer) termenv.Color {
func (ac AdaptiveColor) color(r *Renderer) ansi.Color {
if r.HasDarkBackground() {
return Color(ac.Dark).color(r)
}
Expand All @@ -110,7 +111,7 @@ func (ac AdaptiveColor) color(r *Renderer) termenv.Color {
//
// Deprecated.
func (ac AdaptiveColor) RGBA() (r, g, b, a uint32) {
return termenv.ConvertToRGB(ac.color(renderer)).RGBA()
return ac.color(DefaultRenderer()).RGBA()
}

// CompleteColor specifies exact values for truecolor, ANSI256, and ANSI color
Expand All @@ -121,17 +122,17 @@ type CompleteColor struct {
ANSI string
}

func (c CompleteColor) color(r *Renderer) termenv.Color {
func (c CompleteColor) color(r *Renderer) ansi.Color {
p := r.ColorProfile()
switch p { //nolint:exhaustive
case termenv.TrueColor:
return p.Color(c.TrueColor)
case termenv.ANSI256:
return p.Color(c.ANSI256)
case termenv.ANSI:
return p.Color(c.ANSI)
case TrueColor:
return p.color(c.TrueColor)
case ANSI256:
return p.color(c.ANSI256)
case ANSI:
return p.color(c.ANSI)
default:
return termenv.NoColor{}
return NoColor{}
}
}

Expand All @@ -143,7 +144,7 @@ func (c CompleteColor) color(r *Renderer) termenv.Color {
//
// Deprecated.
func (c CompleteColor) RGBA() (r, g, b, a uint32) {
return termenv.ConvertToRGB(c.color(renderer)).RGBA()
return c.color(DefaultRenderer()).RGBA()
}

// CompleteAdaptiveColor specifies exact values for truecolor, ANSI256, and ANSI color
Expand All @@ -154,7 +155,7 @@ type CompleteAdaptiveColor struct {
Dark CompleteColor
}

func (cac CompleteAdaptiveColor) color(r *Renderer) termenv.Color {
func (cac CompleteAdaptiveColor) color(r *Renderer) ansi.Color {
if r.HasDarkBackground() {
return cac.Dark.color(r)
}
Expand All @@ -168,5 +169,11 @@ func (cac CompleteAdaptiveColor) color(r *Renderer) termenv.Color {
//
// Deprecated.
func (cac CompleteAdaptiveColor) RGBA() (r, g, b, a uint32) {
return termenv.ConvertToRGB(cac.color(renderer)).RGBA()
return cac.color(DefaultRenderer()).RGBA()
}

// ConvertToRGB converts a Color to a colorful.Color.
func ConvertToRGB(c ansi.Color) colorful.Color {
ch, _ := colorful.MakeColor(c)
return ch
}

0 comments on commit a5e85e1

Please sign in to comment.