Skip to content

Commit

Permalink
ref(renderer): change renderer impl
Browse files Browse the repository at this point in the history
  • Loading branch information
aymanbagabas committed Mar 3, 2023
1 parent 1eab58f commit e3dd3d8
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 52 deletions.
47 changes: 17 additions & 30 deletions renderer.go
Expand Up @@ -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 {
Expand All @@ -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.
Expand Down
10 changes: 6 additions & 4 deletions renderer_test.go
Expand Up @@ -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")
}
Expand All @@ -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")
}
Expand Down
7 changes: 7 additions & 0 deletions set.go
Expand Up @@ -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:
Expand Down
19 changes: 3 additions & 16 deletions style.go
Expand Up @@ -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(opts ...StyleOption) Style {
return renderer.NewStyle(opts...)
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 (r *Renderer) NewStyle(opts ...StyleOption) Style {
func (r *Renderer) NewStyle() Style {
s := Style{r: r}
for _, opt := range opts {
opt(&s)
}
return s
}

Expand Down
11 changes: 9 additions & 2 deletions style_test.go
@@ -1,6 +1,7 @@
package lipgloss

import (
"io/ioutil"
"reflect"
"testing"

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -323,7 +330,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",
},
}
Expand Down

0 comments on commit e3dd3d8

Please sign in to comment.