whitespace.go

 1package lipgloss
 2
 3import (
 4	"strings"
 5
 6	"github.com/charmbracelet/x/ansi"
 7)
 8
 9// whitespace is a whitespace renderer.
10type whitespace struct {
11	chars string
12	style Style
13}
14
15// newWhitespace creates a new whitespace renderer.
16func newWhitespace(opts ...WhitespaceOption) *whitespace {
17	w := &whitespace{}
18	for _, opt := range opts {
19		opt(w)
20	}
21	return w
22}
23
24// Render whitespaces.
25func (w whitespace) render(width int) string {
26	if w.chars == "" {
27		w.chars = " "
28	}
29
30	r := []rune(w.chars)
31	j := 0
32	b := strings.Builder{}
33
34	// Cycle through runes and print them into the whitespace.
35	for i := 0; i < width; {
36		b.WriteRune(r[j])
37		j++
38		if j >= len(r) {
39			j = 0
40		}
41		i += ansi.StringWidth(string(r[j]))
42	}
43
44	// Fill any extra gaps white spaces. This might be necessary if any runes
45	// are more than one cell wide, which could leave a one-rune gap.
46	short := width - ansi.StringWidth(b.String())
47	if short > 0 {
48		b.WriteString(strings.Repeat(" ", short))
49	}
50
51	return w.style.Render(b.String())
52}
53
54// WhitespaceOption sets a styling rule for rendering whitespace.
55type WhitespaceOption func(*whitespace)
56
57// WithWhitespaceStyle sets the style for the whitespace.
58func WithWhitespaceStyle(s Style) WhitespaceOption {
59	return func(w *whitespace) {
60		w.style = s
61	}
62}
63
64// WithWhitespaceChars sets the characters to be rendered in the whitespace.
65func WithWhitespaceChars(s string) WhitespaceOption {
66	return func(w *whitespace) {
67		w.chars = s
68	}
69}