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}