diff --git a/get.go b/get.go index 159792a6..965a78df 100644 --- a/get.go +++ b/get.go @@ -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 } @@ -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 } @@ -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 } @@ -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) } @@ -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 } diff --git a/set.go b/set.go index 38a0ed17..dc1c2c3b 100644 --- a/set.go +++ b/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{} } } @@ -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) } } diff --git a/style.go b/style.go index 395529a1..15e94307 100644 --- a/style.go +++ b/style.go @@ -2,6 +2,7 @@ package lipgloss import ( "strings" + "sync" "unicode" "github.com/muesli/reflow/truncate" @@ -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 } @@ -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 } @@ -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() } @@ -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 } diff --git a/unset.go b/unset.go index a8367898..322eb193 100644 --- a/unset.go +++ b/unset.go @@ -2,158 +2,158 @@ package lipgloss // UnsetBold removes the bold style rule, if set. func (s Style) UnsetBold() Style { - delete(s.rules, boldKey) + s.rules.Delete(boldKey) return s } // UnsetItalic removes the italic style rule, if set. func (s Style) UnsetItalic() Style { - delete(s.rules, italicKey) + s.rules.Delete(italicKey) return s } // UnsetUnderline removes the underline style rule, if set. func (s Style) UnsetUnderline() Style { - delete(s.rules, underlineKey) + s.rules.Delete(underlineKey) return s } // UnsetStrikethrough removes the strikethrough style rule, if set. func (s Style) UnsetStrikethrough() Style { - delete(s.rules, strikethroughKey) + s.rules.Delete(strikethroughKey) return s } // UnsetReverse removes the reverse style rule, if set. func (s Style) UnsetReverse() Style { - delete(s.rules, reverseKey) + s.rules.Delete(reverseKey) return s } // UnsetBlink removes the bold style rule, if set. func (s Style) UnsetBlink() Style { - delete(s.rules, blinkKey) + s.rules.Delete(blinkKey) return s } // UnsetFaint removes the faint style rule, if set. func (s Style) UnsetFaint() Style { - delete(s.rules, faintKey) + s.rules.Delete(faintKey) return s } // UnsetForeground removes the foreground style rule, if set. func (s Style) UnsetForeground() Style { - delete(s.rules, foregroundKey) + s.rules.Delete(foregroundKey) return s } // UnsetBackground removes the background style rule, if set. func (s Style) UnsetBackground() Style { - delete(s.rules, backgroundKey) + s.rules.Delete(backgroundKey) return s } // UnsetWidth removes the width style rule, if set. func (s Style) UnsetWidth() Style { - delete(s.rules, widthKey) + s.rules.Delete(widthKey) return s } // UnsetHeight removes the height style rule, if set. func (s Style) UnsetHeight() Style { - delete(s.rules, heightKey) + s.rules.Delete(heightKey) return s } // UnsetAlign removes the horizontal and vertical text alignment style rule, if set. func (s Style) UnsetAlign() Style { - delete(s.rules, alignHorizontalKey) - delete(s.rules, alignVerticalKey) + s.rules.Delete(alignHorizontalKey) + s.rules.Delete(alignVerticalKey) return s } // UnsetAlignHorizontal removes the horizontal text alignment style rule, if set. func (s Style) UnsetAlignHorizontal() Style { - delete(s.rules, alignHorizontalKey) + s.rules.Delete(alignHorizontalKey) return s } // UnsetAlignVertical removes the vertical text alignment style rule, if set. func (s Style) UnsetAlignVertical() Style { - delete(s.rules, alignVerticalKey) + s.rules.Delete(alignVerticalKey) return s } // UnsetPadding removes all padding style rules. func (s Style) UnsetPadding() Style { - delete(s.rules, paddingLeftKey) - delete(s.rules, paddingRightKey) - delete(s.rules, paddingTopKey) - delete(s.rules, paddingBottomKey) + s.rules.Delete(paddingLeftKey) + s.rules.Delete(paddingRightKey) + s.rules.Delete(paddingTopKey) + s.rules.Delete(paddingBottomKey) return s } // UnsetPaddingLeft removes the left padding style rule, if set. func (s Style) UnsetPaddingLeft() Style { - delete(s.rules, paddingLeftKey) + s.rules.Delete(paddingLeftKey) return s } // UnsetPaddingRight removes the right padding style rule, if set. func (s Style) UnsetPaddingRight() Style { - delete(s.rules, paddingRightKey) + s.rules.Delete(paddingRightKey) return s } // UnsetPaddingTop removes the top padding style rule, if set. func (s Style) UnsetPaddingTop() Style { - delete(s.rules, paddingTopKey) + s.rules.Delete(paddingTopKey) return s } // UnsetPaddingBottom removes the bottom style rule, if set. func (s Style) UnsetPaddingBottom() Style { - delete(s.rules, paddingBottomKey) + s.rules.Delete(paddingBottomKey) return s } // UnsetColorWhitespace removes the rule for coloring padding, if set. func (s Style) UnsetColorWhitespace() Style { - delete(s.rules, colorWhitespaceKey) + s.rules.Delete(colorWhitespaceKey) return s } // UnsetMargins removes all margin style rules. func (s Style) UnsetMargins() Style { - delete(s.rules, marginLeftKey) - delete(s.rules, marginRightKey) - delete(s.rules, marginTopKey) - delete(s.rules, marginBottomKey) + s.rules.Delete(marginLeftKey) + s.rules.Delete(marginRightKey) + s.rules.Delete(marginTopKey) + s.rules.Delete(marginBottomKey) return s } // UnsetMarginLeft removes the left margin style rule, if set. func (s Style) UnsetMarginLeft() Style { - delete(s.rules, marginLeftKey) + s.rules.Delete(marginLeftKey) return s } // UnsetMarginRight removes the right margin style rule, if set. func (s Style) UnsetMarginRight() Style { - delete(s.rules, marginRightKey) + s.rules.Delete(marginRightKey) return s } // UnsetMarginTop removes the top margin style rule, if set. func (s Style) UnsetMarginTop() Style { - delete(s.rules, marginTopKey) + s.rules.Delete(marginTopKey) return s } // UnsetMarginBottom removes the bottom margin style rule, if set. func (s Style) UnsetMarginBottom() Style { - delete(s.rules, marginBottomKey) + s.rules.Delete(marginBottomKey) return s } @@ -161,141 +161,141 @@ func (s Style) UnsetMarginBottom() Style { // margin's background color can be set from the background color of another // style during inheritance. func (s Style) UnsetMarginBackground() Style { - delete(s.rules, marginBackgroundKey) + s.rules.Delete(marginBackgroundKey) return s } // UnsetBorderStyle removes the border style rule, if set. func (s Style) UnsetBorderStyle() Style { - delete(s.rules, borderStyleKey) + s.rules.Delete(borderStyleKey) return s } // UnsetBorderTop removes the border top style rule, if set. func (s Style) UnsetBorderTop() Style { - delete(s.rules, borderTopKey) + s.rules.Delete(borderTopKey) return s } // UnsetBorderRight removes the border right style rule, if set. func (s Style) UnsetBorderRight() Style { - delete(s.rules, borderRightKey) + s.rules.Delete(borderRightKey) return s } // UnsetBorderBottom removes the border bottom style rule, if set. func (s Style) UnsetBorderBottom() Style { - delete(s.rules, borderBottomKey) + s.rules.Delete(borderBottomKey) return s } // UnsetBorderLeft removes the border left style rule, if set. func (s Style) UnsetBorderLeft() Style { - delete(s.rules, borderLeftKey) + s.rules.Delete(borderLeftKey) return s } // UnsetBorderForeground removes all border foreground color styles, if set. func (s Style) UnsetBorderForeground() Style { - delete(s.rules, borderTopForegroundKey) - delete(s.rules, borderRightForegroundKey) - delete(s.rules, borderBottomForegroundKey) - delete(s.rules, borderLeftForegroundKey) + s.rules.Delete(borderTopForegroundKey) + s.rules.Delete(borderRightForegroundKey) + s.rules.Delete(borderBottomForegroundKey) + s.rules.Delete(borderLeftForegroundKey) return s } // UnsetBorderTopForeground removes the top border foreground color rule, // if set. func (s Style) UnsetBorderTopForeground() Style { - delete(s.rules, borderTopForegroundKey) + s.rules.Delete(borderTopForegroundKey) return s } // UnsetBorderRightForeground removes the right border foreground color rule, // if set. func (s Style) UnsetBorderRightForeground() Style { - delete(s.rules, borderRightForegroundKey) + s.rules.Delete(borderRightForegroundKey) return s } // UnsetBorderBottomForeground removes the bottom border foreground color // rule, if set. func (s Style) UnsetBorderBottomForeground() Style { - delete(s.rules, borderBottomForegroundKey) + s.rules.Delete(borderBottomForegroundKey) return s } // UnsetBorderLeftForeground removes the left border foreground color rule, // if set. func (s Style) UnsetBorderLeftForeground() Style { - delete(s.rules, borderLeftForegroundKey) + s.rules.Delete(borderLeftForegroundKey) return s } // UnsetBorderBackground removes all border background color styles, if // set. func (s Style) UnsetBorderBackground() Style { - delete(s.rules, borderTopBackgroundKey) - delete(s.rules, borderRightBackgroundKey) - delete(s.rules, borderBottomBackgroundKey) - delete(s.rules, borderLeftBackgroundKey) + s.rules.Delete(borderTopBackgroundKey) + s.rules.Delete(borderRightBackgroundKey) + s.rules.Delete(borderBottomBackgroundKey) + s.rules.Delete(borderLeftBackgroundKey) return s } // UnsetBorderTopBackgroundColor removes the top border background color rule, // if set. func (s Style) UnsetBorderTopBackgroundColor() Style { - delete(s.rules, borderTopBackgroundKey) + s.rules.Delete(borderTopBackgroundKey) return s } // UnsetBorderRightBackground removes the right border background color // rule, if set. func (s Style) UnsetBorderRightBackground() Style { - delete(s.rules, borderRightBackgroundKey) + s.rules.Delete(borderRightBackgroundKey) return s } // UnsetBorderBottomBackground removes the bottom border background color // rule, if set. func (s Style) UnsetBorderBottomBackground() Style { - delete(s.rules, borderBottomBackgroundKey) + s.rules.Delete(borderBottomBackgroundKey) return s } // UnsetBorderLeftBackground removes the left border color rule, if set. func (s Style) UnsetBorderLeftBackground() Style { - delete(s.rules, borderLeftBackgroundKey) + s.rules.Delete(borderLeftBackgroundKey) return s } // UnsetInline removes the inline style rule, if set. func (s Style) UnsetInline() Style { - delete(s.rules, inlineKey) + s.rules.Delete(inlineKey) return s } // UnsetMaxWidth removes the max width style rule, if set. func (s Style) UnsetMaxWidth() Style { - delete(s.rules, maxWidthKey) + s.rules.Delete(maxWidthKey) return s } // UnsetMaxHeight removes the max height style rule, if set. func (s Style) UnsetMaxHeight() Style { - delete(s.rules, maxHeightKey) + s.rules.Delete(maxHeightKey) return s } // UnsetUnderlineSpaces removes the value set by UnderlineSpaces. func (s Style) UnsetUnderlineSpaces() Style { - delete(s.rules, underlineSpacesKey) + s.rules.Delete(underlineSpacesKey) return s } // UnsetStrikethroughSpaces removes the value set by StrikethroughSpaces. func (s Style) UnsetStrikethroughSpaces() Style { - delete(s.rules, strikethroughSpacesKey) + s.rules.Delete(strikethroughSpacesKey) return s }