src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/builtin_fn_styled.go (about) 1 package eval 2 3 import ( 4 "errors" 5 "fmt" 6 7 "src.elv.sh/pkg/eval/vals" 8 "src.elv.sh/pkg/parse" 9 "src.elv.sh/pkg/ui" 10 "src.elv.sh/pkg/ui/styledown" 11 ) 12 13 var errStyledSegmentArgType = errors.New("argument to styled-segment must be a string or a styled segment") 14 15 func init() { 16 addBuiltinFns(map[string]any{ 17 "styled-segment": styledSegment, 18 "styled": styled, 19 "render-styledown": styledown.Render, 20 }) 21 } 22 23 // Turns a string or ui.Segment into a new ui.Segment with the attributes 24 // from the supplied options applied to it. If the input is already a Segment its 25 // attributes are copied and modified. 26 func styledSegment(options RawOptions, input any) (*ui.Segment, error) { 27 var text string 28 var style ui.Style 29 30 switch input := input.(type) { 31 case string: 32 text = input 33 case *ui.Segment: 34 text = input.Text 35 style = input.Style 36 default: 37 return nil, errStyledSegmentArgType 38 } 39 40 if err := style.MergeFromOptions(options); err != nil { 41 return nil, err 42 } 43 44 return &ui.Segment{ 45 Text: text, 46 Style: style, 47 }, nil 48 } 49 50 func styled(fm *Frame, input any, stylings ...any) (ui.Text, error) { 51 var text ui.Text 52 53 switch input := input.(type) { 54 case string: 55 text = ui.T(input) 56 case *ui.Segment: 57 text = ui.TextFromSegment(input) 58 case ui.Text: 59 text = input.Clone() 60 default: 61 return nil, fmt.Errorf("expected string, styled segment or styled text; got %s", vals.Kind(input)) 62 } 63 64 for _, styling := range stylings { 65 switch styling := styling.(type) { 66 case string: 67 parsedStyling := ui.ParseStyling(styling) 68 if parsedStyling == nil { 69 return nil, fmt.Errorf("%s is not a valid style transformer", parse.Quote(styling)) 70 } 71 text = ui.StyleText(text, parsedStyling) 72 case Callable: 73 for i, seg := range text { 74 vs, err := fm.CaptureOutput(func(fm *Frame) error { 75 return styling.Call(fm, []any{seg}, NoOpts) 76 }) 77 if err != nil { 78 return nil, err 79 } 80 81 if n := len(vs); n != 1 { 82 return nil, fmt.Errorf("styling function must return a single segment; got %d values", n) 83 } else if styledSegment, ok := vs[0].(*ui.Segment); !ok { 84 return nil, fmt.Errorf("styling function must return a segment; got %s", vals.Kind(vs[0])) 85 } else { 86 text[i] = styledSegment 87 } 88 } 89 90 default: 91 return nil, fmt.Errorf("need string or callable; got %s", vals.Kind(styling)) 92 } 93 } 94 95 return text, nil 96 }