mirror of
https://github.com/charmbracelet/lipgloss.git
synced 2024-08-17 09:50:31 +03:00
feat: Style.Transform for altering strings at render time (#232)
* feat: Style.Transform for altering strings at render time * feat: add `UnsetTransform` --------- Co-authored-by: Maas Lalani <maas@lalani.dev>
This commit is contained in:
parent
59fcf6fa80
commit
d354842a40
17
get.go
17
get.go
@ -408,6 +408,12 @@ func (s Style) GetFrameSize() (x, y int) {
|
||||
return s.GetHorizontalFrameSize(), s.GetVerticalFrameSize()
|
||||
}
|
||||
|
||||
// GetTransform returns the transform set on the style. If no transform is set
|
||||
// nil is returned.
|
||||
func (s Style) GetTransform() func(string) string {
|
||||
return s.getAsTransform(transformKey)
|
||||
}
|
||||
|
||||
// Returns whether or not the given property is set.
|
||||
func (s Style) isSet(k propKey) bool {
|
||||
_, exists := s.rules[k]
|
||||
@ -469,6 +475,17 @@ func (s Style) getBorderStyle() Border {
|
||||
return noBorder
|
||||
}
|
||||
|
||||
func (s Style) getAsTransform(k propKey) func(string) string {
|
||||
v, ok := s.rules[k]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if fn, ok := v.(func(string) string); ok {
|
||||
return fn
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Split a string into lines, additionally returning the size of the widest
|
||||
// line.
|
||||
func getLines(s string) (lines []string, widest int) {
|
||||
|
12
set.go
12
set.go
@ -544,6 +544,18 @@ func (s Style) StrikethroughSpaces(v bool) Style {
|
||||
return s
|
||||
}
|
||||
|
||||
// Transform applies a given function to a string at render time, allowing for
|
||||
// the string being rendered to be manipuated.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// s := NewStyle().Transform(strings.ToUpper)
|
||||
// fmt.Println(s.Render("raow!") // "RAOW!"
|
||||
func (s Style) Transform(fn func(string) string) Style {
|
||||
s.set(transformKey, fn)
|
||||
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 {
|
||||
|
8
style.go
8
style.go
@ -73,6 +73,8 @@ const (
|
||||
tabWidthKey
|
||||
underlineSpacesKey
|
||||
strikethroughSpacesKey
|
||||
|
||||
transformKey
|
||||
)
|
||||
|
||||
// A set of properties.
|
||||
@ -225,6 +227,8 @@ func (s Style) Render(strs ...string) string {
|
||||
|
||||
// Do we need to style spaces separately?
|
||||
useSpaceStyler = underlineSpaces || strikethroughSpaces
|
||||
|
||||
transform = s.getAsTransform(transformKey)
|
||||
)
|
||||
|
||||
if len(s.rules) == 0 {
|
||||
@ -401,6 +405,10 @@ func (s Style) Render(strs ...string) string {
|
||||
str = strings.Join(lines[:min(maxHeight, len(lines))], "\n")
|
||||
}
|
||||
|
||||
if transform != nil {
|
||||
return transform(str)
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package lipgloss
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/muesli/termenv"
|
||||
@ -374,6 +375,42 @@ func TestTabConversion(t *testing.T) {
|
||||
requireEqual(t, "[\t]", s.Render("[\t]"))
|
||||
}
|
||||
|
||||
func TestStringTransform(t *testing.T) {
|
||||
for i, tc := range []struct {
|
||||
input string
|
||||
fn func(string) string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
"raow",
|
||||
strings.ToUpper,
|
||||
"RAOW",
|
||||
},
|
||||
{
|
||||
"The quick brown 狐 jumped over the lazy 犬",
|
||||
func(s string) string {
|
||||
n := 0
|
||||
rune := make([]rune, len(s))
|
||||
for _, r := range s {
|
||||
rune[n] = r
|
||||
n++
|
||||
}
|
||||
rune = rune[0:n]
|
||||
for i := 0; i < n/2; i++ {
|
||||
rune[i], rune[n-1-i] = rune[n-1-i], rune[i]
|
||||
}
|
||||
return string(rune)
|
||||
},
|
||||
"犬 yzal eht revo depmuj 狐 nworb kciuq ehT",
|
||||
},
|
||||
} {
|
||||
res := NewStyle().Transform(tc.fn).Render(tc.input)
|
||||
if res != tc.expected {
|
||||
t.Errorf("Test #%d:\nExpected: %q\nGot: %q", i+1, tc.expected, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkStyleRender(b *testing.B) {
|
||||
s := NewStyle().
|
||||
Bold(true).
|
||||
|
6
unset.go
6
unset.go
@ -305,6 +305,12 @@ func (s Style) UnsetStrikethroughSpaces() Style {
|
||||
return s
|
||||
}
|
||||
|
||||
// UnsetTransform removes the value set by Transform.
|
||||
func (s Style) UnsetTransform() Style {
|
||||
delete(s.rules, transformKey)
|
||||
return s
|
||||
}
|
||||
|
||||
// UnsetString sets the underlying string value to the empty string.
|
||||
func (s Style) UnsetString() Style {
|
||||
s.value = ""
|
||||
|
Loading…
Reference in New Issue
Block a user