1package ansi
2
3import (
4 "bytes"
5 "fmt"
6 "io"
7
8 "github.com/charmbracelet/x/cellbuf"
9)
10
11// A HeadingElement is used to render headings.
12type HeadingElement struct {
13 Level int
14 First bool
15}
16
17const (
18 h1 = iota + 1
19 h2
20 h3
21 h4
22 h5
23 h6
24)
25
26// Render renders a HeadingElement.
27func (e *HeadingElement) Render(w io.Writer, ctx RenderContext) error {
28 bs := ctx.blockStack
29 rules := ctx.options.Styles.Heading
30
31 switch e.Level {
32 case h1:
33 rules = cascadeStyles(rules, ctx.options.Styles.H1)
34 case h2:
35 rules = cascadeStyles(rules, ctx.options.Styles.H2)
36 case h3:
37 rules = cascadeStyles(rules, ctx.options.Styles.H3)
38 case h4:
39 rules = cascadeStyles(rules, ctx.options.Styles.H4)
40 case h5:
41 rules = cascadeStyles(rules, ctx.options.Styles.H5)
42 case h6:
43 rules = cascadeStyles(rules, ctx.options.Styles.H6)
44 }
45
46 if !e.First {
47 _, _ = renderText(w, bs.Current().Style.StylePrimitive, "\n")
48 }
49
50 be := BlockElement{
51 Block: &bytes.Buffer{},
52 Style: cascadeStyle(bs.Current().Style, rules, false),
53 }
54 bs.Push(be)
55
56 _, _ = renderText(w, bs.Parent().Style.StylePrimitive, rules.BlockPrefix)
57 _, _ = renderText(bs.Current().Block, bs.Current().Style.StylePrimitive, rules.Prefix)
58 return nil
59}
60
61// Finish finishes rendering a HeadingElement.
62func (e *HeadingElement) Finish(w io.Writer, ctx RenderContext) error {
63 bs := ctx.blockStack
64 rules := bs.Current().Style
65 mw := NewMarginWriter(ctx, w, rules)
66
67 flow := cellbuf.Wrap(bs.Current().Block.String(), int(bs.Width(ctx)), "") //nolint: gosec
68 _, err := io.WriteString(mw, flow)
69 if err != nil {
70 return fmt.Errorf("glamour: error writing to writer: %w", err)
71 }
72
73 _, _ = renderText(w, bs.Current().Style.StylePrimitive, rules.Suffix)
74 _, _ = renderText(w, bs.Parent().Style.StylePrimitive, rules.BlockSuffix)
75
76 bs.Current().Block.Reset()
77 bs.Pop()
78 return nil
79}