github.com/charmbracelet/glamour@v0.7.0/ansi/baseelement.go (about) 1 package ansi 2 3 import ( 4 "bytes" 5 "io" 6 "strings" 7 "text/template" 8 9 "github.com/muesli/termenv" 10 ) 11 12 // BaseElement renders a styled primitive element. 13 type BaseElement struct { 14 Token string 15 Prefix string 16 Suffix string 17 Style StylePrimitive 18 } 19 20 func formatToken(format string, token string) (string, error) { 21 var b bytes.Buffer 22 23 v := make(map[string]interface{}) 24 v["text"] = token 25 26 tmpl, err := template.New(format).Funcs(TemplateFuncMap).Parse(format) 27 if err != nil { 28 return "", err 29 } 30 31 err = tmpl.Execute(&b, v) 32 return b.String(), err 33 } 34 35 func renderText(w io.Writer, p termenv.Profile, rules StylePrimitive, s string) { 36 if len(s) == 0 { 37 return 38 } 39 40 out := termenv.String(s) 41 42 if rules.Upper != nil && *rules.Upper { 43 out = termenv.String(strings.ToUpper(s)) 44 } 45 if rules.Lower != nil && *rules.Lower { 46 out = termenv.String(strings.ToLower(s)) 47 } 48 if rules.Title != nil && *rules.Title { 49 out = termenv.String(strings.Title(s)) 50 } 51 if rules.Color != nil { 52 out = out.Foreground(p.Color(*rules.Color)) 53 } 54 if rules.BackgroundColor != nil { 55 out = out.Background(p.Color(*rules.BackgroundColor)) 56 } 57 if rules.Underline != nil && *rules.Underline { 58 out = out.Underline() 59 } 60 if rules.Bold != nil && *rules.Bold { 61 out = out.Bold() 62 } 63 if rules.Italic != nil && *rules.Italic { 64 out = out.Italic() 65 } 66 if rules.CrossedOut != nil && *rules.CrossedOut { 67 out = out.CrossOut() 68 } 69 if rules.Overlined != nil && *rules.Overlined { 70 out = out.Overline() 71 } 72 if rules.Inverse != nil && *rules.Inverse { 73 out = out.Reverse() 74 } 75 if rules.Blink != nil && *rules.Blink { 76 out = out.Blink() 77 } 78 79 _, _ = w.Write([]byte(out.String())) 80 } 81 82 func (e *BaseElement) Render(w io.Writer, ctx RenderContext) error { 83 bs := ctx.blockStack 84 85 renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, e.Prefix) 86 defer func() { 87 renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, e.Suffix) 88 }() 89 90 rules := bs.With(e.Style) 91 // render unstyled prefix/suffix 92 renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, rules.BlockPrefix) 93 defer func() { 94 renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, rules.BlockSuffix) 95 }() 96 97 // render styled prefix/suffix 98 renderText(w, ctx.options.ColorProfile, rules, rules.Prefix) 99 defer func() { 100 renderText(w, ctx.options.ColorProfile, rules, rules.Suffix) 101 }() 102 103 s := e.Token 104 if len(rules.Format) > 0 { 105 var err error 106 s, err = formatToken(rules.Format, s) 107 if err != nil { 108 return err 109 } 110 } 111 renderText(w, ctx.options.ColorProfile, rules, s) 112 return nil 113 }