mirror of
https://github.com/charmbracelet/lipgloss.git
synced 2024-11-23 14:26:29 +03:00
feat: VerticalAlign
Add VerticalAlign, UnsetVerticalAlign, etc...
This commit is contained in:
parent
0ee74a5a90
commit
9852bb3017
25
align.go
25
align.go
@ -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
41
align_test.go
Normal 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
26
get.go
@ -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
16
set.go
@ -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
|
||||
}
|
||||
|
||||
|
17
style.go
17
style.go
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
17
unset.go
17
unset.go
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user