whitespace.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package lipgloss
  2. import (
  3. "strings"
  4. "github.com/muesli/reflow/ansi"
  5. "github.com/muesli/termenv"
  6. )
  7. // whitespace is a whitespace renderer.
  8. type whitespace struct {
  9. re *Renderer
  10. style termenv.Style
  11. chars string
  12. }
  13. // newWhitespace creates a new whitespace renderer. The order of the options
  14. // matters, it you'r using WithWhitespaceRenderer, make sure it comes first as
  15. // other options might depend on it.
  16. func newWhitespace(r *Renderer, opts ...WhitespaceOption) *whitespace {
  17. w := &whitespace{
  18. re: r,
  19. style: r.ColorProfile().String(),
  20. }
  21. for _, opt := range opts {
  22. opt(w)
  23. }
  24. return w
  25. }
  26. // Render whitespaces.
  27. func (w whitespace) render(width int) string {
  28. if w.chars == "" {
  29. w.chars = " "
  30. }
  31. r := []rune(w.chars)
  32. j := 0
  33. b := strings.Builder{}
  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.PrintableRuneWidth(string(r[j]))
  42. }
  43. // Fill any extra gaps white spaces. This might be necessary if any runes
  44. // are more than one cell wide, which could leave a one-rune gap.
  45. short := width - ansi.PrintableRuneWidth(b.String())
  46. if short > 0 {
  47. b.WriteString(strings.Repeat(" ", short))
  48. }
  49. return w.style.Styled(b.String())
  50. }
  51. // WhitespaceOption sets a styling rule for rendering whitespace.
  52. type WhitespaceOption func(*whitespace)
  53. // WithWhitespaceForeground sets the color of the characters in the whitespace.
  54. func WithWhitespaceForeground(c TerminalColor) WhitespaceOption {
  55. return func(w *whitespace) {
  56. w.style = w.style.Foreground(c.color(w.re))
  57. }
  58. }
  59. // WithWhitespaceBackground sets the background color of the whitespace.
  60. func WithWhitespaceBackground(c TerminalColor) WhitespaceOption {
  61. return func(w *whitespace) {
  62. w.style = w.style.Background(c.color(w.re))
  63. }
  64. }
  65. // WithWhitespaceChars sets the characters to be rendered in the whitespace.
  66. func WithWhitespaceChars(s string) WhitespaceOption {
  67. return func(w *whitespace) {
  68. w.chars = s
  69. }
  70. }