Skip to content

Commit

Permalink
feat: make Lipgloss Style thread-safe
Browse files Browse the repository at this point in the history
  • Loading branch information
muesli committed Oct 6, 2022
1 parent ae7c84f commit 1db7974
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 110 deletions.
18 changes: 18 additions & 0 deletions get.go
Expand Up @@ -397,11 +397,17 @@ func (s Style) GetFrameSize() (x, y int) {

// Returns whether or not the given property is set.
func (s Style) isSet(k propKey) bool {
s.mtx.RLock()
defer s.mtx.RUnlock()

_, exists := s.rules[k]
return exists
}

func (s Style) getAsBool(k propKey, defaultVal bool) bool {
s.mtx.RLock()
defer s.mtx.RUnlock()

v, ok := s.rules[k]
if !ok {
return defaultVal
Expand All @@ -413,6 +419,9 @@ func (s Style) getAsBool(k propKey, defaultVal bool) bool {
}

func (s Style) getAsColor(k propKey) TerminalColor {
s.mtx.RLock()
defer s.mtx.RUnlock()

v, ok := s.rules[k]
if !ok {
return NoColor{}
Expand All @@ -424,6 +433,9 @@ func (s Style) getAsColor(k propKey) TerminalColor {
}

func (s Style) getAsInt(k propKey) int {
s.mtx.RLock()
defer s.mtx.RUnlock()

v, ok := s.rules[k]
if !ok {
return 0
Expand All @@ -435,6 +447,9 @@ func (s Style) getAsInt(k propKey) int {
}

func (s Style) getAsPosition(k propKey) Position {
s.mtx.RLock()
defer s.mtx.RUnlock()

v, ok := s.rules[k]
if !ok {
return Position(0)
Expand All @@ -446,6 +461,9 @@ func (s Style) getAsPosition(k propKey) Position {
}

func (s Style) getBorderStyle() Border {
s.mtx.RLock()
defer s.mtx.RUnlock()

v, ok := s.rules[borderStyleKey]
if !ok {
return noBorder
Expand Down
3 changes: 3 additions & 0 deletions set.go
Expand Up @@ -10,6 +10,9 @@ func (s *Style) init() {

// Set a value on the underlying rules map.
func (s *Style) set(key propKey, value interface{}) {
s.mtx.Lock()
defer s.mtx.Unlock()

s.init()

switch v := value.(type) {
Expand Down
36 changes: 31 additions & 5 deletions style.go
Expand Up @@ -2,6 +2,7 @@ package lipgloss

import (
"strings"
"sync"
"unicode"

"github.com/muesli/reflow/truncate"
Expand Down Expand Up @@ -75,15 +76,17 @@ const (
// A set of properties.
type rules map[propKey]interface{}

// 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
// incase the underlying implementation changes.
// NewStyle returns a new, empty Style. Use this rather than a Style{}
// primitive to ensure the style is properly initialized.
func NewStyle() Style {
return Style{}
return Style{
mtx: &sync.RWMutex{},
}
}

// Style contains a set of rules that comprise a style as a whole.
type Style struct {
mtx *sync.RWMutex
rules map[propKey]interface{}
value string
}
Expand All @@ -94,24 +97,36 @@ type Style struct {
// as when using fmt.Sprintf. You can also simply define a style and render out
// strings directly with Style.Render.
func (s Style) SetString(str string) Style {
s.mtx.Lock()
defer s.mtx.Unlock()

s.value = str
return s
}

// Value returns the raw, unformatted, underlying string value for this style.
func (s Style) Value() string {
s.mtx.RLock()
defer s.mtx.RUnlock()

return s.value
}

// String implements stringer for a Style, returning the rendered result based
// on the rules in this style. An underlying string value must be set with
// Style.SetString prior to using this method.
func (s Style) String() string {
return s.Render(s.value)
s.mtx.RLock()
defer s.mtx.RUnlock()

return s.render(s.value)
}

// Copy returns a copy of this style, including any underlying string values.
func (s Style) Copy() Style {
s.mtx.RLock()
defer s.mtx.RUnlock()

o := NewStyle()
o.init()
for k, v := range s.rules {
Expand All @@ -127,6 +142,9 @@ func (s Style) Copy() Style {
//
// Margins, padding, and underlying string values are not inherited.
func (s Style) Inherit(i Style) Style {
i.mtx.RLock()
defer i.mtx.RUnlock()

s.init()

for k, v := range i.rules {
Expand Down Expand Up @@ -154,6 +172,14 @@ func (s Style) Inherit(i Style) Style {

// Render applies the defined style formatting to a given string.
func (s Style) Render(str string) string {
s.mtx.RLock()
defer s.mtx.RUnlock()

return s.render(str)
}

// Internal render method, mutex must be held by caller.
func (s Style) render(str string) string {
var (
te termenv.Style
teSpace termenv.Style
Expand Down

0 comments on commit 1db7974

Please sign in to comment.