okami.mom/glamour

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

nekomimi.pettake code block text from Segments.Value and hang list items through IndentWriter052c391

main
2.0 KiB75 linesraw
1package ansi
2
3import (
4	"bytes"
5	"errors"
6	"io"
7	"strconv"
8	"strings"
9
10	"charm.land/lipgloss/v2"
11	"github.com/charmbracelet/x/ansi"
12)
13
14// An ItemElement is used to render items inside a list.
15type ItemElement struct {
16	IsOrdered   bool
17	Enumeration uint
18}
19
20// Render renders an ItemElement.
21func (e *ItemElement) Render(w io.Writer, ctx RenderContext) error {
22	var el *BaseElement
23	if e.IsOrdered {
24		el = &BaseElement{
25			Style:  ctx.options.Styles.Enumeration,
26			Prefix: strconv.FormatInt(int64(e.Enumeration), 10), //nolint:gosec
27		}
28	} else {
29		el = &BaseElement{
30			Style: ctx.options.Styles.Item,
31		}
32	}
33
34	return el.Render(w, ctx)
35}
36
37// A ListItemElement renders a list item as a block: its marker leads the
38// first row and every later row hangs under the text after it, so wrapped
39// lines, paragraphs, code and nested lists stay inside the item.
40type ListItemElement struct {
41	Marker ElementRenderer
42}
43
44func (e *ListItemElement) marker(ctx RenderContext) string {
45	var marker bytes.Buffer
46	_ = e.Marker.Render(&marker, ctx)
47	return marker.String()
48}
49
50// Render opens the item's block, indented by the marker's width.
51func (e *ListItemElement) Render(_ io.Writer, ctx RenderContext) error {
52	width := uint(ansi.StringWidth(e.marker(ctx))) //nolint:gosec
53	bs := ctx.blockStack
54	bs.Push(BlockElement{
55		Block: &bytes.Buffer{},
56		Style: cascadeStyle(bs.Current().Style, StyleBlock{Indent: &width}, false),
57	})
58	return nil
59}
60
61// Finish writes the item: the marker leads its first row and pads the rest.
62func (e *ListItemElement) Finish(w io.Writer, ctx RenderContext) error {
63	bs := ctx.blockStack
64	marker := e.marker(ctx)
65	lead, pad := marker, strings.Repeat(" ", ansi.StringWidth(marker))
66	iw := NewIndentWriter(w, 1, func(w io.Writer) {
67		_, _ = io.WriteString(w, lead)
68		lead = pad
69	})
70	body := lipgloss.Wrap(bs.Current().Block.String(), int(bs.Width(ctx)), " ,.;-+|")
71	_, err := io.WriteString(iw, strings.TrimRight(body, "\n"))
72	bs.Current().Block.Reset()
73	bs.Pop()
74	return errors.Join(err, iw.Close())
75}