okami.mom/glamour
git clone https://git.nkp.pet/okami.mom/glamour
4046973
main
1package ansi 2 3import ( 4"bytes" 5"fmt" 6"io" 7"strings" 8"text/template" 9 10"charm.land/lipgloss/v2" 11"github.com/charmbracelet/x/ansi" 12"golang.org/x/text/cases" 13"golang.org/x/text/language" 14) 15 16// BaseElement renders a styled primitive element. 17type BaseElement struct { 18Token string 19Prefix string 20Suffix string 21Style StylePrimitive 22// Verbatim writes Token as it is, without removing markdown escapes. 23Verbatim bool 24} 25 26func formatToken (format string ,token string ) (string ,error ) { 27var b bytes.Buffer 28 29v := make (map [string ]interface {}) 30v ["text" ]= token 31 32tmpl ,err := template .New (format ).Funcs (TemplateFuncMap ).Parse (format ) 33if err != nil { 34return "" ,fmt .Errorf ("glamour: error parsing template: %w" ,err ) 35 } 36 37err = tmpl .Execute (& b ,v ) 38return b .String (),err 39} 40 41func renderText (w io.Writer ,rules StylePrimitive ,s string ) (int ,error ) {//nolint:unparam 42if len (s )== 0 { 43return 0 ,nil 44 } 45 46// XXX: We're using [ansi.Style] instead of [lipgloss.Style] because 47// Lip Gloss has a weird bug where it adds spaces when rendering joined 48// strings. Needs further investigation. 49style := ansi.Style {} 50if rules .Upper != nil && * rules .Upper { 51s = cases .Upper (language .English ).String (s ) 52 } 53if rules .Lower != nil && * rules .Lower { 54s = cases .Lower (language .English ).String (s ) 55 } 56if rules .Title != nil && * rules .Title { 57s = cases .Title (language .English ).String (s ) 58 } 59if rules .Color != nil { 60style = style .ForegroundColor (lipgloss .Color (* rules .Color )) 61 } 62if rules .BackgroundColor != nil { 63style = style .BackgroundColor (lipgloss .Color (* rules .BackgroundColor )) 64 } 65if rules .Underline != nil && * rules .Underline { 66style = style .Underline (true ) 67 } 68if rules .Bold != nil && * rules .Bold { 69style = style .Bold () 70 } 71if rules .Italic != nil && * rules .Italic { 72style = style .Italic (true ) 73 } 74if rules .CrossedOut != nil && * rules .CrossedOut { 75style = style .Strikethrough (true ) 76 } 77if rules .Inverse != nil && * rules .Inverse { 78style = style .Reverse (true ) 79 } 80if rules .Blink != nil && * rules .Blink { 81style = style .Blink (true ) 82 } 83 84n ,err := io .WriteString (w ,style .Styled (s )) 85if err != nil { 86return n ,fmt .Errorf ("glamour: error writing to writer: %w" ,err ) 87 } 88 89return n ,nil 90} 91 92// StyleOverrideRender renders a BaseElement with an overridden style. 93func (e * BaseElement )StyleOverrideRender (w io.Writer ,ctx RenderContext ,style StylePrimitive )error { 94bs := ctx .blockStack 95st1 := cascadeStylePrimitives (bs .Current ().Style .StylePrimitive ,style ) 96st2 := cascadeStylePrimitives (bs .With (e .Style ),style ) 97 98return e .doRender (w ,st1 ,st2 ) 99} 100 101// Render renders a BaseElement. 102func (e * BaseElement )Render (w io.Writer ,ctx RenderContext )error { 103bs := ctx .blockStack 104st1 := bs .Current ().Style .StylePrimitive 105st2 := bs .With (e .Style ) 106return e .doRender (w ,st1 ,st2 ) 107} 108 109func (e * BaseElement )doRender (w io.Writer ,st1 ,st2 StylePrimitive )error { 110_ ,_ = renderText (w ,st1 ,e .Prefix ) 111defer func () { 112_ ,_ = renderText (w ,st1 ,e .Suffix ) 113 }() 114 115// render unstyled prefix/suffix 116_ ,_ = renderText (w ,st1 ,st2 .BlockPrefix ) 117defer func () { 118_ ,_ = renderText (w ,st1 ,st2 .BlockSuffix ) 119 }() 120 121// render styled prefix/suffix 122_ ,_ = renderText (w ,st2 ,st2 .Prefix ) 123defer func () { 124_ ,_ = renderText (w ,st2 ,st2 .Suffix ) 125 }() 126 127s := e .Token 128if len (st2 .Format )> 0 { 129var err error 130s ,err = formatToken (st2 .Format ,s ) 131if err != nil { 132return err 133 } 134 } 135if ! e .Verbatim { 136s = escapeReplacer .Replace (s ) 137 } 138_ ,_ = renderText (w ,st2 ,s ) 139return nil 140} 141 142// https://www.markdownguide.org/basic-syntax/#characters-you-can-escape 143var escapeReplacer = strings .NewReplacer ( 144"\\\\" ,"\\" , 145"\\`" ,"`" , 146"\\*" ,"*" , 147"\\_" ,"_" , 148"\\{" ,"{" , 149"\\}" ,"}" , 150"\\[" ,"[" , 151"\\]" ,"]" , 152"\\<" ,"<" , 153"\\>" ,">" , 154"\\(" ,"(" , 155"\\)" ,")" , 156"\\#" ,"#" , 157"\\+" ,"+" , 158"\\-" ,"-" , 159"\\." ,"." , 160"\\!" ,"!" , 161"\\|" ,"|" , 162)