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 Feb 28, 2023
1 parent a74950e commit 4f88d6c
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 81 deletions.
12 changes: 6 additions & 6 deletions get.go
Expand Up @@ -397,12 +397,12 @@ func (s Style) GetFrameSize() (x, y int) {

// Returns whether or not the given property is set.
func (s Style) isSet(k propKey) bool {
_, exists := s.rules[k]
_, exists := s.rules.Load(k)
return exists
}

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

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

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

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

func (s Style) getBorderStyle() Border {
v, ok := s.rules[borderStyleKey]
v, ok := s.rules.Load(borderStyleKey)
if !ok {
return noBorder
}
Expand Down
8 changes: 5 additions & 3 deletions set.go
@@ -1,10 +1,12 @@
package lipgloss

import "sync"

// This could (should) probably just be moved into NewStyle(). We've broken it
// out, so we can call it in a lazy way.
func (s *Style) init() {
if s.rules == nil {
s.rules = make(rules)
s.rules = &sync.Map{}
}
}

Expand All @@ -18,9 +20,9 @@ func (s *Style) set(key propKey, value interface{}) {
// them at zero or above. We could use uints instead, but the
// conversions are a little tedious, so we're sticking with ints for
// sake of usability.
s.rules[key] = max(0, v)
s.rules.Store(key, max(0, v))
default:
s.rules[key] = v
s.rules.Store(key, v)
}
}

Expand Down
40 changes: 27 additions & 13 deletions style.go
Expand Up @@ -2,6 +2,7 @@ package lipgloss

import (
"strings"
"sync"
"unicode"

"github.com/muesli/reflow/truncate"
Expand Down Expand Up @@ -108,7 +109,7 @@ func (r *Renderer) NewStyle(opts ...StyleOption) Style {
// Style contains a set of rules that comprise a style as a whole.
type Style struct {
r *Renderer
rules map[propKey]interface{}
rules *sync.Map
value string
}

Expand Down Expand Up @@ -144,10 +145,14 @@ func (s Style) String() string {
func (s Style) Copy() Style {
o := NewStyle()
o.init()
for k, v := range s.rules {
o.rules[k] = v
}

s.init()
s.rules.Range(func(k, v interface{}) bool {
o.rules.Store(k, v)
return true
})
o.r = s.r

o.value = s.value
return o
}
Expand All @@ -160,31 +165,35 @@ func (s Style) Copy() Style {
func (s Style) Inherit(i Style) Style {
s.init()

for k, v := range i.rules {
i.rules.Range(func(k, v interface{}) bool {
switch k {
case marginTopKey, marginRightKey, marginBottomKey, marginLeftKey:
// Margins are not inherited
continue
return true
case paddingTopKey, paddingRightKey, paddingBottomKey, paddingLeftKey:
// Padding is not inherited
continue
return true
case backgroundKey:
// The margins also inherit the background color
if !s.isSet(marginBackgroundKey) && !i.isSet(marginBackgroundKey) {
s.rules[marginBackgroundKey] = v
s.rules.Store(marginBackgroundKey, v)
}
}

if _, exists := s.rules[k]; exists {
continue
if _, exists := s.rules.Load(k); exists {
return true
}
s.rules[k] = v
}

s.rules.Store(k, v)
return true
})

return s
}

// Render applies the defined style formatting to a given string.
func (s Style) Render(strs ...string) string {
s.init()
if s.r == nil {
s.r = DefaultRenderer()
}
Expand Down Expand Up @@ -236,7 +245,12 @@ func (s Style) Render(strs ...string) string {
useSpaceStyler = underlineSpaces || strikethroughSpaces
)

if len(s.rules) == 0 {
var l int
s.rules.Range(func(k, v interface{}) bool {
l++
return false
})
if l == 0 {
return str
}

Expand Down

0 comments on commit 4f88d6c

Please sign in to comment.