feat: VerticalAlign

Add VerticalAlign, UnsetVerticalAlign, etc...
This commit is contained in:
Maas Lalani 2022-08-30 16:59:06 -04:00
parent 0ee74a5a90
commit 9852bb3017
6 changed files with 125 additions and 17 deletions

View File

@ -10,7 +10,7 @@ import (
// Perform text alignment. If the string is multi-lined, we also make all lines
// the same width by padding them with spaces. If a termenv style is passed,
// use that to style the spaces added.
func alignText(str string, pos Position, width int, style *termenv.Style) string {
func alignTextHorizontal(str string, pos Position, width int, style *termenv.Style) string {
lines, widestLine := getLines(str)
var b strings.Builder
@ -57,3 +57,26 @@ func alignText(str string, pos Position, width int, style *termenv.Style) string
return b.String()
}
func alignTextVertical(str string, pos Position, height int, _ *termenv.Style) string {
strHeight := strings.Count(str, "\n") + 1
if height < strHeight {
return str
}
switch pos {
case Top:
return str + strings.Repeat("\n", height-strHeight)
case Center:
var topPadding, bottomPadding = (height - strHeight) / 2, (height - strHeight) / 2
if strHeight+topPadding+bottomPadding > height {
topPadding--
} else if strHeight+topPadding+bottomPadding < height {
bottomPadding++
}
return strings.Repeat("\n", topPadding) + str + strings.Repeat("\n", bottomPadding)
case Bottom:
return strings.Repeat("\n", height-strHeight) + str
}
return str
}

41
align_test.go Normal file
View File

@ -0,0 +1,41 @@
package lipgloss
import "testing"
func TestAlignTextVertical(t *testing.T) {
tests := []struct {
str string
pos Position
height int
want string
}{
{str: "Foo", pos: Top, height: 2, want: "Foo\n"},
{str: "Foo", pos: Center, height: 5, want: "\n\nFoo\n\n"},
{str: "Foo", pos: Bottom, height: 5, want: "\n\n\n\nFoo"},
{str: "Foo\nBar", pos: Bottom, height: 5, want: "\n\n\nFoo\nBar"},
{str: "Foo\nBar", pos: Center, height: 5, want: "\nFoo\nBar\n\n"},
{str: "Foo\nBar", pos: Top, height: 5, want: "Foo\nBar\n\n\n"},
{str: "Foo\nBar\nBaz", pos: Bottom, height: 5, want: "\n\nFoo\nBar\nBaz"},
{str: "Foo\nBar\nBaz", pos: Center, height: 5, want: "\nFoo\nBar\nBaz\n"},
{str: "Foo\nBar\nBaz", pos: Bottom, height: 3, want: "Foo\nBar\nBaz"},
{str: "Foo\nBar\nBaz", pos: Center, height: 3, want: "Foo\nBar\nBaz"},
{str: "Foo\nBar\nBaz", pos: Top, height: 3, want: "Foo\nBar\nBaz"},
{str: "Foo\n\n\n\nBar", pos: Bottom, height: 5, want: "Foo\n\n\n\nBar"},
{str: "Foo\n\n\n\nBar", pos: Center, height: 5, want: "Foo\n\n\n\nBar"},
{str: "Foo\n\n\n\nBar", pos: Top, height: 5, want: "Foo\n\n\n\nBar"},
{str: "Foo\nBar\nBaz", pos: Center, height: 9, want: "\n\n\nFoo\nBar\nBaz\n\n\n"},
{str: "Foo\nBar\nBaz", pos: Center, height: 10, want: "\n\n\nFoo\nBar\nBaz\n\n\n\n"},
}
for _, test := range tests {
got := alignTextVertical(test.str, test.pos, test.height, nil)
if got != test.want {
t.Errorf("alignTextVertical(%q, %v, %d) = %q, want %q", test.str, test.pos, test.height, got, test.want)
}
}
}

26
get.go
View File

@ -71,16 +71,36 @@ func (s Style) GetHeight() int {
return s.getAsInt(heightKey)
}
// GetAlign returns the style's implicit alignment setting. If no alignment is
// set Position.AlignLeft is returned.
// GetAlign returns the style's implicit horizontal alignment setting.
// If no alignment is set Position.AlignLeft is returned.
func (s Style) GetAlign() Position {
v := s.getAsPosition(alignKey)
v := s.getAsPosition(alignHorizontalKey)
if v == Position(0) {
return Left
}
return v
}
// GetAlignHorizontal returns the style's implicit horizontal alignment setting.
// If no alignment is set Position.AlignLeft is returned.
func (s Style) GetAlignHorizontal() Position {
v := s.getAsPosition(alignHorizontalKey)
if v == Position(0) {
return Left
}
return v
}
// GetAlignVertical returns the style's implicit vertical alignment setting.
// If no alignment is set Position.AlignTop is returned.
func (s Style) GetAlignVertical() Position {
v := s.getAsPosition(alignVerticalKey)
if v == Position(0) {
return Top
}
return v
}
// GetPadding returns the style's top, right, bottom, and left padding values,
// in that order. 0 is returned for unset values.
func (s Style) GetPadding() (top, right, bottom, left int) {

16
set.go
View File

@ -104,9 +104,21 @@ func (s Style) Height(i int) Style {
return s
}
// Align sets a text alignment rule.
// Align sets a horizontal text alignment rule.
func (s Style) Align(p Position) Style {
s.set(alignKey, p)
s.set(alignHorizontalKey, p)
return s
}
// HorizontalAlign sets a horizontal text alignment rule.
func (s Style) AlignHorizontal(p Position) Style {
s.set(alignHorizontalKey, p)
return s
}
// VerticalAlign sets a text alignment rule.
func (s Style) AlignVertical(p Position) Style {
s.set(alignVerticalKey, p)
return s
}

View File

@ -26,7 +26,8 @@ const (
backgroundKey
widthKey
heightKey
alignKey
alignHorizontalKey
alignVerticalKey
// Padding.
paddingTopKey
@ -169,9 +170,10 @@ func (s Style) Render(str string) string {
fg = s.getAsColor(foregroundKey)
bg = s.getAsColor(backgroundKey)
width = s.getAsInt(widthKey)
height = s.getAsInt(heightKey)
align = s.getAsPosition(alignKey)
width = s.getAsInt(widthKey)
height = s.getAsInt(heightKey)
horizontalAlign = s.getAsPosition(alignHorizontalKey)
verticalAlign = s.getAsPosition(alignVerticalKey)
topPadding = s.getAsInt(paddingTopKey)
rightPadding = s.getAsInt(paddingRightKey)
@ -327,10 +329,7 @@ func (s Style) Render(str string) string {
// Height
if height > 0 {
h := strings.Count(str, "\n") + 1
if height > h {
str += strings.Repeat("\n", height-h)
}
str = alignTextVertical(str, verticalAlign, height, nil)
}
// Set alignment. This will also pad short lines with spaces so that all
@ -344,7 +343,7 @@ func (s Style) Render(str string) string {
if colorWhitespace || styleWhitespace {
st = &teWhitespace
}
str = alignText(str, align, width, st)
str = alignTextHorizontal(str, horizontalAlign, width, st)
}
}

View File

@ -66,9 +66,22 @@ func (s Style) UnsetHeight() Style {
return s
}
// UnsetAlign removes the text alignment style rule, if set.
// UnsetAlign removes the horizontal and vertical text alignment style rule, if set.
func (s Style) UnsetAlign() Style {
delete(s.rules, alignKey)
delete(s.rules, alignHorizontalKey)
delete(s.rules, alignVerticalKey)
return s
}
// UnsetAlignHorizontal removes the horizontal text alignment style rule, if set.
func (s Style) UnsetAlignHorizontal() Style {
delete(s.rules, alignHorizontalKey)
return s
}
// UnsetAlignHorizontal removes the vertical text alignment style rule, if set.
func (s Style) UnsetAlignVertical() Style {
delete(s.rules, alignVerticalKey)
return s
}