okami.mom/glamour

git clone https://git.nkp.pet/okami.mom/glamour

Kieran Klukaschore: fix pre-existing lint failuresc293649

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