github.com/charmbracelet/glamour@v0.7.0/ansi/heading.go (about)

     1  package ansi
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  
     7  	"github.com/muesli/reflow/indent"
     8  	"github.com/muesli/reflow/wordwrap"
     9  )
    10  
    11  // A HeadingElement is used to render headings.
    12  type HeadingElement struct {
    13  	Level int
    14  	First bool
    15  }
    16  
    17  const (
    18  	h1 = iota + 1
    19  	h2
    20  	h3
    21  	h4
    22  	h5
    23  	h6
    24  )
    25  
    26  func (e *HeadingElement) Render(w io.Writer, ctx RenderContext) error {
    27  	bs := ctx.blockStack
    28  	rules := ctx.options.Styles.Heading
    29  
    30  	switch e.Level {
    31  	case h1:
    32  		rules = cascadeStyles(rules, ctx.options.Styles.H1)
    33  	case h2:
    34  		rules = cascadeStyles(rules, ctx.options.Styles.H2)
    35  	case h3:
    36  		rules = cascadeStyles(rules, ctx.options.Styles.H3)
    37  	case h4:
    38  		rules = cascadeStyles(rules, ctx.options.Styles.H4)
    39  	case h5:
    40  		rules = cascadeStyles(rules, ctx.options.Styles.H5)
    41  	case h6:
    42  		rules = cascadeStyles(rules, ctx.options.Styles.H6)
    43  	}
    44  
    45  	if !e.First {
    46  		renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, "\n")
    47  	}
    48  
    49  	be := BlockElement{
    50  		Block: &bytes.Buffer{},
    51  		Style: cascadeStyle(bs.Current().Style, rules, false),
    52  	}
    53  	bs.Push(be)
    54  
    55  	renderText(w, ctx.options.ColorProfile, bs.Parent().Style.StylePrimitive, rules.BlockPrefix)
    56  	renderText(bs.Current().Block, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, rules.Prefix)
    57  	return nil
    58  }
    59  
    60  func (e *HeadingElement) Finish(w io.Writer, ctx RenderContext) error {
    61  	bs := ctx.blockStack
    62  	rules := bs.Current().Style
    63  
    64  	var indentation uint
    65  	var margin uint
    66  	if rules.Indent != nil {
    67  		indentation = *rules.Indent
    68  	}
    69  	if rules.Margin != nil {
    70  		margin = *rules.Margin
    71  	}
    72  
    73  	iw := indent.NewWriterPipe(w, indentation+margin, func(wr io.Writer) {
    74  		renderText(w, ctx.options.ColorProfile, bs.Parent().Style.StylePrimitive, " ")
    75  	})
    76  
    77  	flow := wordwrap.NewWriter(int(bs.Width(ctx) - indentation - margin*2))
    78  	_, err := flow.Write(bs.Current().Block.Bytes())
    79  	if err != nil {
    80  		return err
    81  	}
    82  	flow.Close()
    83  
    84  	_, err = iw.Write(flow.Bytes())
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, rules.Suffix)
    90  	renderText(w, ctx.options.ColorProfile, bs.Parent().Style.StylePrimitive, rules.BlockSuffix)
    91  
    92  	bs.Current().Block.Reset()
    93  	bs.Pop()
    94  	return nil
    95  }