okami.mom/glamour
git clone https://git.nkp.pet/okami.mom/glamour
c293649
main
1package ansi 2 3import ( 4"bytes" 5"fmt" 6"io" 7 8"charm.land/lipgloss/v2" 9"charm.land/lipgloss/v2/table" 10 astext"github.com/yuin/goldmark/extension/ast" 11) 12 13// A TableElement is used to render tables. 14type TableElement struct { 15lipgloss * table.Table 16table * astext.Table 17header []string 18row []string 19source []byte 20 21tableImages []tableLink 22tableLinks []tableLink 23} 24 25// A TableRowElement is used to render a single row in a table. 26type TableRowElement struct {} 27 28// A TableHeadElement is used to render a table's head element. 29type TableHeadElement struct {} 30 31// A TableCellElement is used to render a single cell in a row. 32type TableCellElement struct { 33Children []ElementRenderer 34Head bool 35} 36 37// Render renders a TableElement. 38func (e * TableElement )Render (w io.Writer ,ctx RenderContext )error { 39bs := ctx .blockStack 40 41var indentation uint 42var margin uint 43rules := ctx .options .Styles .Table 44if rules .Indent != nil { 45indentation = * rules .Indent 46 } 47if rules .Margin != nil { 48margin = * rules .Margin 49 } 50 51iw := NewIndentWriter (w ,int (indentation + margin ),func (_ io.Writer ) { 52_ ,_ = renderText (w ,bs .Current ().Style .StylePrimitive ," " ) 53 }) 54defer iw .Close ()//nolint:errcheck 55 56style := bs .With (rules .StylePrimitive ) 57 58_ ,_ = renderText (iw ,bs .Current ().Style .StylePrimitive ,rules .BlockPrefix ) 59_ ,_ = renderText (iw ,style ,rules .Prefix ) 60width := int (ctx .blockStack .Width (ctx )) 61 62wrap := true 63if ctx .options .TableWrap != nil { 64wrap = * ctx .options .TableWrap 65 } 66ctx .table .lipgloss = table .New ().Width (width ).Wrap (wrap ) 67 68if err := e .collectLinksAndImages (ctx );err != nil { 69return err 70 } 71 72return nil 73} 74 75func (e * TableElement )setStyles (ctx RenderContext ) { 76docRules := ctx .options .Styles .Document 77if docRules .BackgroundColor != nil { 78baseStyle := lipgloss .NewStyle ().Background (lipgloss .Color (* docRules .BackgroundColor )) 79ctx .table .lipgloss .BaseStyle (baseStyle ) 80 } 81 82ctx .table .lipgloss = ctx .table .lipgloss .StyleFunc (func (_ ,col int ) lipgloss.Style { 83st := lipgloss .NewStyle ().Inline (false ) 84// Default Styles 85st = st .Margin (0 ,1 ) 86 87// Override with custom styles 88if m := ctx .options .Styles .Table .Margin ;m != nil { 89st = st .Padding (0 ,int (* m )) 90 } 91switch e .table .Alignments [col ] { 92case astext .AlignLeft : 93st = st .Align (lipgloss .Left ).PaddingRight (0 ) 94case astext .AlignCenter : 95st = st .Align (lipgloss .Center ) 96case astext .AlignRight : 97st = st .Align (lipgloss .Right ).PaddingLeft (0 ) 98case astext .AlignNone : 99// do nothing 100 } 101 102return st 103 }) 104} 105 106func (e * TableElement )setBorders (ctx RenderContext ) { 107rules := ctx .options .Styles .Table 108border := lipgloss .NormalBorder () 109 110if rules .RowSeparator != nil && rules .ColumnSeparator != nil { 111border = lipgloss.Border { 112Top :* rules .RowSeparator , 113Bottom :* rules .RowSeparator , 114Left :* rules .ColumnSeparator , 115Right :* rules .ColumnSeparator , 116Middle :* rules .CenterSeparator , 117 } 118 } 119ctx .table .lipgloss .Border (border ) 120ctx .table .lipgloss .BorderTop (false ) 121ctx .table .lipgloss .BorderLeft (false ) 122ctx .table .lipgloss .BorderRight (false ) 123ctx .table .lipgloss .BorderBottom (false ) 124} 125 126// Finish finishes rendering a TableElement. 127func (e * TableElement )Finish (_ io.Writer ,ctx RenderContext )error { 128defer func () { 129ctx .table .lipgloss = nil 130ctx .table .tableImages = nil 131ctx .table .tableLinks = nil 132 }() 133 134rules := ctx .options .Styles .Table 135 136e .setStyles (ctx ) 137e .setBorders (ctx ) 138 139ow := ctx .blockStack .Current ().Block 140if _ ,err := ow .WriteString (ctx .table .lipgloss .String ());err != nil { 141return fmt .Errorf ("glamour: error writing to buffer: %w" ,err ) 142 } 143 144_ ,_ = renderText (ow ,ctx .blockStack .With (rules .StylePrimitive ),rules .Suffix ) 145_ ,_ = renderText (ow ,ctx .blockStack .Current ().Style .StylePrimitive ,rules .BlockSuffix ) 146 147e .printTableLinks (ctx ) 148 149ctx .table .lipgloss = nil 150return nil 151} 152 153// Finish finishes rendering a TableRowElement. 154func (e * TableRowElement )Finish (_ io.Writer ,ctx RenderContext )error { 155if ctx .table .lipgloss == nil { 156return nil 157 } 158 159ctx .table .lipgloss .Row (ctx .table .row ... ) 160ctx .table .row = []string {} 161return nil 162} 163 164// Finish finishes rendering a TableHeadElement. 165func (e * TableHeadElement )Finish (_ io.Writer ,ctx RenderContext )error { 166if ctx .table .lipgloss == nil { 167return nil 168 } 169 170ctx .table .lipgloss .Headers (ctx .table .header ... ) 171ctx .table .header = []string {} 172return nil 173} 174 175// Render renders a TableCellElement. 176func (e * TableCellElement )Render (_ io.Writer ,ctx RenderContext )error { 177var b bytes.Buffer 178style := ctx .options .Styles .Table .StylePrimitive 179for _ ,child := range e .Children { 180if r ,ok := child .(StyleOverriderElementRenderer );ok { 181if err := r .StyleOverrideRender (& b ,ctx ,style );err != nil { 182return fmt .Errorf ("glamour: error rendering with style: %w" ,err ) 183 } 184 }else { 185var bb bytes.Buffer 186if err := child .Render (& bb ,ctx );err != nil { 187return fmt .Errorf ("glamour: error rendering: %w" ,err ) 188 } 189el := & BaseElement { 190Token :bb .String (), 191Style :style , 192 } 193if err := el .Render (& b ,ctx );err != nil { 194return err 195 } 196 } 197 } 198 199if e .Head { 200ctx .table .header = append (ctx .table .header ,b .String ()) 201 }else { 202ctx .table .row = append (ctx .table .row ,b .String ()) 203 } 204 205return nil 206}