align.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package lipgloss
  2. import (
  3. "strings"
  4. "github.com/charmbracelet/x/ansi"
  5. "github.com/muesli/termenv"
  6. )
  7. // Perform text alignment. If the string is multi-lined, we also make all lines
  8. // the same width by padding them with spaces. If a termenv style is passed,
  9. // use that to style the spaces added.
  10. func alignTextHorizontal(str string, pos Position, width int, style *termenv.Style) string {
  11. lines, widestLine := getLines(str)
  12. var b strings.Builder
  13. for i, l := range lines {
  14. lineWidth := ansi.StringWidth(l)
  15. shortAmount := widestLine - lineWidth // difference from the widest line
  16. shortAmount += max(0, width-(shortAmount+lineWidth)) // difference from the total width, if set
  17. if shortAmount > 0 {
  18. switch pos { //nolint:exhaustive
  19. case Right:
  20. s := strings.Repeat(" ", shortAmount)
  21. if style != nil {
  22. s = style.Styled(s)
  23. }
  24. l = s + l
  25. case Center:
  26. // Note: remainder goes on the right.
  27. left := shortAmount / 2 //nolint:gomnd
  28. right := left + shortAmount%2 //nolint:gomnd
  29. leftSpaces := strings.Repeat(" ", left)
  30. rightSpaces := strings.Repeat(" ", right)
  31. if style != nil {
  32. leftSpaces = style.Styled(leftSpaces)
  33. rightSpaces = style.Styled(rightSpaces)
  34. }
  35. l = leftSpaces + l + rightSpaces
  36. default: // Left
  37. s := strings.Repeat(" ", shortAmount)
  38. if style != nil {
  39. s = style.Styled(s)
  40. }
  41. l += s
  42. }
  43. }
  44. b.WriteString(l)
  45. if i < len(lines)-1 {
  46. b.WriteRune('\n')
  47. }
  48. }
  49. return b.String()
  50. }
  51. func alignTextVertical(str string, pos Position, height int, _ *termenv.Style) string {
  52. strHeight := strings.Count(str, "\n") + 1
  53. if height < strHeight {
  54. return str
  55. }
  56. switch pos {
  57. case Top:
  58. return str + strings.Repeat("\n", height-strHeight)
  59. case Center:
  60. topPadding, bottomPadding := (height-strHeight)/2, (height-strHeight)/2 //nolint:gomnd
  61. if strHeight+topPadding+bottomPadding > height {
  62. topPadding--
  63. } else if strHeight+topPadding+bottomPadding < height {
  64. bottomPadding++
  65. }
  66. return strings.Repeat("\n", topPadding) + str + strings.Repeat("\n", bottomPadding)
  67. case Bottom:
  68. return strings.Repeat("\n", height-strHeight) + str
  69. }
  70. return str
  71. }