Skip to content

Commit

Permalink
feat: VerticalAlign
Browse files Browse the repository at this point in the history
Add VerticalAlign, UnsetVerticalAlign, etc...
  • Loading branch information
maaslalani committed Sep 6, 2022
1 parent 0ee74a5 commit 9852bb3
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 17 deletions.
25 changes: 24 additions & 1 deletion align.go
Expand Up @@ -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

Expand Down Expand Up @@ -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 changes: 41 additions & 0 deletions align_test.go
@@ -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 changes: 23 additions & 3 deletions get.go
Expand Up @@ -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) {
Expand Down
16 changes: 14 additions & 2 deletions set.go
Expand Up @@ -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
}

Expand Down
17 changes: 8 additions & 9 deletions style.go
Expand Up @@ -26,7 +26,8 @@ const (
backgroundKey
widthKey
heightKey
alignKey
alignHorizontalKey
alignVerticalKey

// Padding.
paddingTopKey
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand 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)
}
}

Expand Down
17 changes: 15 additions & 2 deletions unset.go
Expand Up @@ -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
}

Expand Down

0 comments on commit 9852bb3

Please sign in to comment.