diff --git a/renderer.go b/renderer.go index 28ca477..099e4b4 100644 --- a/renderer.go +++ b/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. diff --git a/renderer_test.go b/renderer_test.go index 2be6430..7f05acd 100644 --- a/renderer_test.go +++ b/renderer_test.go @@ -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") } diff --git a/set.go b/set.go index 35dbcc8..f8bf9a2 100644 --- a/set.go +++ b/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: diff --git a/style.go b/style.go index 395529a..54f6d39 100644 --- a/style.go +++ b/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 } diff --git a/style_test.go b/style_test.go index d0a0ee0..5e1eb73 100644 --- a/style_test.go +++ b/style_test.go @@ -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", }, }