mirror of
https://github.com/charmbracelet/lipgloss.git
synced 2024-08-17 09:50:31 +03:00
ref(renderer): change renderer impl
This commit is contained in:
parent
d09532a91a
commit
c5382b35ef
47
renderer.go
47
renderer.go
@ -2,11 +2,12 @@ package lipgloss
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/muesli/termenv"
|
||||
)
|
||||
|
||||
var renderer = NewRenderer()
|
||||
var renderer = NewRenderer(os.Stdout)
|
||||
|
||||
// Renderer is a lipgloss terminal renderer.
|
||||
type Renderer struct {
|
||||
@ -22,43 +23,29 @@ func DefaultRenderer() *Renderer {
|
||||
return renderer
|
||||
}
|
||||
|
||||
// SetDefaultRenderer sets the default global renderer.
|
||||
func SetDefaultRenderer(r *Renderer) {
|
||||
renderer = r
|
||||
}
|
||||
|
||||
// NewRenderer creates a new Renderer.
|
||||
func NewRenderer(options ...RendererOption) *Renderer {
|
||||
//
|
||||
// w will be used to determine the terminal's color capabilities.
|
||||
func NewRenderer(w io.Writer, opts ...termenv.OutputOption) *Renderer {
|
||||
r := &Renderer{
|
||||
output: termenv.DefaultOutput(),
|
||||
}
|
||||
for _, option := range options {
|
||||
option(r)
|
||||
output: termenv.NewOutput(w, opts...),
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// WithOutput sets the io.Writer to be used for rendering.
|
||||
func WithOutput(w io.Writer) RendererOption {
|
||||
return WithTermenvOutput(termenv.NewOutput(w))
|
||||
// Output returns the termenv output.
|
||||
func (r *Renderer) Output() *termenv.Output {
|
||||
return r.output
|
||||
}
|
||||
|
||||
// WithTermenvOutput sets the termenv Output to use for rendering.
|
||||
func WithTermenvOutput(output *termenv.Output) RendererOption {
|
||||
return func(r *Renderer) {
|
||||
r.output = output
|
||||
}
|
||||
}
|
||||
|
||||
// WithDarkBackground can force the renderer to use a light/dark background.
|
||||
func WithDarkBackground(dark bool) RendererOption {
|
||||
return func(r *Renderer) {
|
||||
r.SetHasDarkBackground(dark)
|
||||
}
|
||||
}
|
||||
|
||||
// WithColorProfile sets the color profile on the renderer. This function is
|
||||
// primarily intended for testing. For details, see the note on
|
||||
// [Renderer.SetColorProfile].
|
||||
func WithColorProfile(p termenv.Profile) RendererOption {
|
||||
return func(r *Renderer) {
|
||||
r.SetColorProfile(p)
|
||||
}
|
||||
// SetOutput sets the termenv output.
|
||||
func (r *Renderer) SetOutput(o *termenv.Output) {
|
||||
r.output = o
|
||||
}
|
||||
|
||||
// ColorProfile returns the detected termenv color profile.
|
||||
|
@ -8,11 +8,13 @@ import (
|
||||
)
|
||||
|
||||
func TestRendererHasDarkBackground(t *testing.T) {
|
||||
r1 := NewRenderer(WithDarkBackground(false))
|
||||
r1 := NewRenderer(os.Stdout)
|
||||
r1.SetHasDarkBackground(false)
|
||||
if r1.HasDarkBackground() {
|
||||
t.Error("Expected renderer to have light background")
|
||||
}
|
||||
r2 := NewRenderer(WithDarkBackground(true))
|
||||
r2 := NewRenderer(os.Stdout)
|
||||
r2.SetHasDarkBackground(true)
|
||||
if !r2.HasDarkBackground() {
|
||||
t.Error("Expected renderer to have dark background")
|
||||
}
|
||||
@ -25,8 +27,8 @@ func TestRendererWithOutput(t *testing.T) {
|
||||
}
|
||||
defer f.Close()
|
||||
defer os.Remove(f.Name())
|
||||
output := termenv.NewOutput(f, termenv.WithProfile(termenv.TrueColor))
|
||||
r := NewRenderer(WithTermenvOutput(output))
|
||||
r := NewRenderer(f)
|
||||
r.SetColorProfile(termenv.TrueColor)
|
||||
if r.output.Profile != termenv.TrueColor {
|
||||
t.Error("Expected renderer to use true color")
|
||||
}
|
||||
|
7
set.go
7
set.go
@ -520,6 +520,13 @@ func (s Style) StrikethroughSpaces(v bool) Style {
|
||||
return s
|
||||
}
|
||||
|
||||
// Renderer sets the renderer for the style. This is useful for changing the
|
||||
// renderer for a style that is being used in a different context.
|
||||
func (s Style) Renderer(r *Renderer) Style {
|
||||
s.r = r
|
||||
return s
|
||||
}
|
||||
|
||||
// whichSidesInt is a helper method for setting values on sides of a block based
|
||||
// on the number of arguments. It follows the CSS shorthand rules for blocks
|
||||
// like margin, padding. and borders. Here are how the rules work:
|
||||
|
27
style.go
27
style.go
@ -75,33 +75,20 @@ const (
|
||||
// A set of properties.
|
||||
type rules map[propKey]interface{}
|
||||
|
||||
// StyleOption is a function that applies a style option to a Style.
|
||||
type StyleOption func(*Style)
|
||||
|
||||
// WithString sets the underlying string value for this style.
|
||||
func WithString(strs ...string) StyleOption {
|
||||
return func(s *Style) {
|
||||
s.value = joinString(strs...)
|
||||
}
|
||||
// NewStyle returns a new, empty Style. While it's syntactic sugar for the
|
||||
// Style{} primitive, it's recommended to use this function for creating styles
|
||||
// in case the underlying implementation changes. It takes an optional string
|
||||
// value to be set as the underlying string value for this style.
|
||||
func NewStyle() Style {
|
||||
return renderer.NewStyle()
|
||||
}
|
||||
|
||||
// NewStyle returns a new, empty Style. While it's syntactic sugar for the
|
||||
// Style{} primitive, it's recommended to use this function for creating styles
|
||||
// in case the underlying implementation changes. It takes an optional string
|
||||
// value to be set as the underlying string value for this style.
|
||||
func NewStyle(opts ...StyleOption) Style {
|
||||
return renderer.NewStyle(opts...)
|
||||
}
|
||||
|
||||
// NewStyle returns a new, empty Style. While it's syntactic sugar for the
|
||||
// Style{} primitive, it's recommended to use this function for creating styles
|
||||
// in case the underlying implementation changes. It takes an optional string
|
||||
// value to be set as the underlying string value for this style.
|
||||
func (r *Renderer) NewStyle(opts ...StyleOption) Style {
|
||||
func (r *Renderer) NewStyle() Style {
|
||||
s := Style{r: r}
|
||||
for _, opt := range opts {
|
||||
opt(&s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package lipgloss
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@ -58,7 +59,9 @@ func TestStyleRender(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStyleCustomRender(t *testing.T) {
|
||||
r := NewRenderer(WithColorProfile(termenv.TrueColor), WithDarkBackground(false))
|
||||
r := NewRenderer(ioutil.Discard)
|
||||
r.SetHasDarkBackground(false)
|
||||
r.SetColorProfile(termenv.TrueColor)
|
||||
tt := []struct {
|
||||
style Style
|
||||
expected string
|
||||
@ -91,6 +94,10 @@ func TestStyleCustomRender(t *testing.T) {
|
||||
r.NewStyle().Faint(true),
|
||||
"\x1b[2mhello\x1b[0m",
|
||||
},
|
||||
{
|
||||
NewStyle().Faint(true).Renderer(r),
|
||||
"\x1b[2mhello\x1b[0m",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tt {
|
||||
@ -104,6 +111,15 @@ func TestStyleCustomRender(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStyleRenderer(t *testing.T) {
|
||||
r := NewRenderer(ioutil.Discard)
|
||||
s1 := NewStyle().Bold(true)
|
||||
s2 := s1.Renderer(r)
|
||||
if s1.r == s2.r {
|
||||
t.Fatalf("expected different renderers")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueCopy(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@ -323,7 +339,7 @@ func TestStyleValue(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "new style with string",
|
||||
style: NewStyle(WithString("bar", "foobar")),
|
||||
style: NewStyle().SetString("bar", "foobar"),
|
||||
expected: "bar foobar foo",
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user