Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make Lipgloss Style thread-safe (mutex) #141

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
25 changes: 23 additions & 2 deletions style.go
Expand Up @@ -2,6 +2,7 @@ package lipgloss

import (
"strings"
"sync"
"unicode"

"github.com/muesli/reflow/truncate"
Expand Down Expand Up @@ -98,17 +99,22 @@ func NewStyle(opts ...StyleOption) Style {
// 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 {
s := Style{r: r}
s := Style{
mtx: &sync.RWMutex{},
r: r,
}
for _, opt := range opts {
opt(&s)
}
return s
}

// Style contains a set of rules that comprise a style as a whole.
// It is safe for concurrent use by multiple goroutines.
type Style struct {
mtx *sync.RWMutex
r *Renderer
rules map[propKey]interface{}
rules rules
value string
}

Expand All @@ -124,12 +130,18 @@ func joinString(strs ...string) string {
// as when using fmt.Sprintf. You can also simply define a style and render out
// strings directly with Style.Render.
func (s Style) SetString(strs ...string) Style {
s.mtx.Lock()
defer s.mtx.Unlock()

s.value = joinString(strs...)
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
}

Expand All @@ -142,6 +154,9 @@ func (s Style) String() string {

// 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 @@ -158,6 +173,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 @@ -185,6 +203,9 @@ func (s Style) Inherit(i Style) Style {

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

if s.r == nil {
s.r = DefaultRenderer()
}
Expand Down