Option to set whitespace color in place functions + whitespace renderer

This commit is contained in:
Christian Rocha 2021-03-26 15:57:47 -04:00
parent 25d9c64aa9
commit 73f6cab6ac
No known key found for this signature in database
GPG Key ID: D6CC7A16E5878018
4 changed files with 78 additions and 14 deletions

View File

@ -13,6 +13,7 @@ var (
// ColorType is an interface used in color specifications.
type ColorType interface {
value() string
color() termenv.Color
}
// NoColor is used to specify the absence of color styling. When this is active
@ -29,6 +30,10 @@ func (n NoColor) value() string {
return ""
}
func (n NoColor) color() termenv.Color {
return color("")
}
var noColor = NoColor{}
// Color specifies a color by hex or ANSI value. For example:
@ -42,6 +47,10 @@ func (c Color) value() string {
return string(c)
}
func (c Color) color() termenv.Color {
return color(string(c))
}
// AdaptiveColor provides color options for light and dark backgrounds. The
// appropriate color with be returned based on the darkness of the terminal
// background color determined at runtime.
@ -61,3 +70,7 @@ func (a AdaptiveColor) value() string {
}
return a.Light
}
func (a AdaptiveColor) color() termenv.Color {
return color(a.value())
}

View File

@ -31,14 +31,14 @@ const (
// Place places a string or text block vertically in an unstyled box of a given
// width or height.
func Place(width, height int, hPos, vPos Position, str string) string {
return PlaceVertical(height, vPos, PlaceHorizontal(width, hPos, str))
func Place(width, height int, hPos, vPos Position, str string, opts ...WhitespaceOption) string {
return PlaceVertical(height, vPos, PlaceHorizontal(width, hPos, str, opts...), opts...)
}
// PlaceHorizontal places a string or text block horizontally in an unstyled
// block of a given width. If the given width is shorter than the max width of
// the string (measured by it's longest line) this will be a noöp.
func PlaceHorizontal(width int, pos Position, str string) string {
func PlaceHorizontal(width int, pos Position, str string, opts ...WhitespaceOption) string {
lines, contentWidth := getLines(str)
gap := width - contentWidth
@ -46,16 +46,21 @@ func PlaceHorizontal(width int, pos Position, str string) string {
return str
}
ws := &whitespace{}
for _, opt := range opts {
opt(ws)
}
var b strings.Builder
for i, l := range lines {
switch pos {
case Left:
b.WriteString(l)
b.WriteString(strings.Repeat(" ", gap))
b.WriteString(ws.render(gap))
case Right:
b.WriteString(strings.Repeat(" ", gap))
b.WriteString(ws.render(gap))
b.WriteString(l)
default: // somewhere in the middle
@ -63,9 +68,9 @@ func PlaceHorizontal(width int, pos Position, str string) string {
left := gap - split
right := gap - left
b.WriteString(strings.Repeat(" ", left))
b.WriteString(ws.render(left))
b.WriteString(l)
b.WriteString(strings.Repeat(" ", right))
b.WriteString(ws.render(right))
}
if i < len(lines)-1 {
@ -79,7 +84,7 @@ func PlaceHorizontal(width int, pos Position, str string) string {
// PlaceVertical places a string or text block vertically in an unstyled block
// of a given height. If the given height is shorter than the height of the
// string (measured by it's newlines) then this will be a noöp.
func PlaceVertical(height int, pos Position, str string) string {
func PlaceVertical(height int, pos Position, str string, opts ...WhitespaceOption) string {
contentHeight := strings.Count(str, "\n") + 1
gap := height - contentHeight
@ -87,14 +92,20 @@ func PlaceVertical(height int, pos Position, str string) string {
return str
}
ws := &whitespace{}
for _, opt := range opts {
opt(ws)
}
_, width := getLines(str)
emptyLine := strings.Repeat(" ", width)
emptyLine := ws.render(width)
b := strings.Builder{}
switch pos {
case Top:
b.WriteString(str)
b.WriteRune('\n')
for i := 0; i < gap; i++ {
b.WriteString(emptyLine)
if i < gap-1 {
@ -115,10 +126,8 @@ func PlaceVertical(height int, pos Position, str string) string {
b.WriteString(str)
for i := 0; i < bottom; i++ {
b.WriteRune('\n')
b.WriteString(emptyLine)
if i < bottom-1 {
b.WriteRune('\n')
}
}
}

View File

@ -207,7 +207,7 @@ func (s Style) Render(str string) string {
}
if fg != noColor {
fgc := color(fg.value())
fgc := fg.color()
te = te.Foreground(fgc)
te.Foreground(fgc)
if styleWhitespace {
@ -219,7 +219,7 @@ func (s Style) Render(str string) string {
}
if bg != noColor {
bgc := color(bg.value())
bgc := bg.color()
te = te.Background(bgc)
if colorWhitespace {
teWhitespace = teWhitespace.Background(bgc)

42
whitespace.go Normal file
View File

@ -0,0 +1,42 @@
package lipgloss
import (
"strings"
"github.com/muesli/reflow/ansi"
"github.com/muesli/termenv"
)
// whitespace is a whitespace renderer.
type whitespace struct {
style termenv.Style
chars string
}
// Render spacespace.
func (w whitespace) render(width int) string {
if w.chars == "" {
w.chars = " "
}
charWidth := ansi.PrintableRuneWidth(w.chars)
line := strings.Repeat(w.chars, width/charWidth)
// Fill in gaps with spaces
short := width - ansi.PrintableRuneWidth(line)
if short > 0 {
line += strings.Repeat(" ", short)
}
return w.style.Styled(line)
}
// WhiteSpaceOption sets a styling rule for rendering whitespace.
type WhitespaceOption func(*whitespace)
// WithWhiteSpaceBackground sets the background color of the whitespace.
func WithWhitespaceBackground(c Color) WhitespaceOption {
return func(w *whitespace) {
w.style = w.style.Background(c.color())
}
}