1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-04-21 12:16:54 +02:00

Right-align key labels in menu

I find this makes it look a little nicer
This commit is contained in:
Jesse Duffield 2023-05-21 12:06:22 +10:00
parent 5b933762c2
commit ec3a28df43
8 changed files with 124 additions and 43 deletions

View File

@ -13,6 +13,8 @@ type ListContextTrait struct {
c *ContextCommon c *ContextCommon
list types.IList list types.IList
getDisplayStrings func(startIdx int, length int) [][]string getDisplayStrings func(startIdx int, length int) [][]string
// alignment for each column. If nil, the default is left alignment
columnAlignments []utils.Alignment
} }
func (self *ListContextTrait) IsListContext() {} func (self *ListContextTrait) IsListContext() {}
@ -52,7 +54,10 @@ func (self *ListContextTrait) HandleFocusLost(opts types.OnFocusLostOpts) error
// OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view // OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view
func (self *ListContextTrait) HandleRender() error { func (self *ListContextTrait) HandleRender() error {
self.list.RefreshSelectedIdx() self.list.RefreshSelectedIdx()
content := utils.RenderDisplayStrings(self.getDisplayStrings(0, self.list.Len())) content := utils.RenderDisplayStrings(
self.getDisplayStrings(0, self.list.Len()),
self.columnAlignments,
)
self.GetViewTrait().SetContent(content) self.GetViewTrait().SetContent(content)
self.c.Render() self.c.Render()
self.setFooter() self.setFooter()

View File

@ -5,6 +5,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/gui/keybindings" "github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo" "github.com/samber/lo"
) )
@ -37,6 +38,7 @@ func NewMenuContext(
getDisplayStrings: viewModel.GetDisplayStrings, getDisplayStrings: viewModel.GetDisplayStrings,
list: viewModel, list: viewModel,
c: c, c: c,
columnAlignments: []utils.Alignment{utils.AlignRight, utils.AlignLeft},
}, },
} }
} }

View File

@ -17,6 +17,6 @@ func (self *ViewportListContextTrait) FocusLine() {
startIdx, length := self.GetViewTrait().ViewPortYBounds() startIdx, length := self.GetViewTrait().ViewPortYBounds()
displayStrings := self.ListContextTrait.getDisplayStrings(startIdx, length) displayStrings := self.ListContextTrait.getDisplayStrings(startIdx, length)
content := utils.RenderDisplayStrings(displayStrings) content := utils.RenderDisplayStrings(displayStrings, nil)
self.GetViewTrait().SetViewPortContent(content) self.GetViewTrait().SetViewPortContent(content)
} }

View File

@ -42,7 +42,7 @@ func LongAuthor(authorName string) string {
return value return value
} }
paddedAuthorName := utils.WithPadding(authorName, 17) paddedAuthorName := utils.WithPadding(authorName, 17, utils.AlignLeft)
truncatedName := utils.TruncateWithEllipsis(paddedAuthorName, 17) truncatedName := utils.TruncateWithEllipsis(paddedAuthorName, 17)
value := AuthorStyle(authorName).Sprint(truncatedName) value := AuthorStyle(authorName).Sprint(truncatedName)
authorNameCache[authorName] = value authorNameCache[authorName] = value

View File

@ -35,7 +35,7 @@ func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool
} }
coloredName := nameTextStyle.Sprint(displayName) coloredName := nameTextStyle.Sprint(displayName)
branchStatus := utils.WithPadding(ColoredBranchStatus(b, tr), 2) branchStatus := utils.WithPadding(ColoredBranchStatus(b, tr), 2, utils.AlignLeft)
coloredName = fmt.Sprintf("%s %s", coloredName, branchStatus) coloredName = fmt.Sprintf("%s %s", coloredName, branchStatus)
recencyColor := style.FgCyan recencyColor := style.FgCyan

View File

@ -283,7 +283,7 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
s.showYouAreHereLabel, s.showYouAreHereLabel,
) )
renderedResult := utils.RenderDisplayStrings(result) renderedResult := utils.RenderDisplayStrings(result, nil)
t.Logf("\n%s", renderedResult) t.Logf("\n%s", renderedResult)
assert.EqualValues(t, s.expected, renderedResult) assert.EqualValues(t, s.expected, renderedResult)

View File

@ -8,20 +8,52 @@ import (
"github.com/samber/lo" "github.com/samber/lo"
) )
type Alignment int
const (
AlignLeft Alignment = iota
AlignRight
)
type ColumnConfig struct {
Width int
Alignment Alignment
}
// WithPadding pads a string as much as you want // WithPadding pads a string as much as you want
func WithPadding(str string, padding int) string { func WithPadding(str string, padding int, alignment Alignment) string {
uncoloredStr := Decolorise(str) uncoloredStr := Decolorise(str)
width := runewidth.StringWidth(uncoloredStr) width := runewidth.StringWidth(uncoloredStr)
if padding < width { if padding < width {
return str return str
} }
return str + strings.Repeat(" ", padding-width) space := strings.Repeat(" ", padding-width)
if alignment == AlignLeft {
return str + space
} else {
return space + str
}
} }
func RenderDisplayStrings(displayStringsArr [][]string) string { // defaults to left-aligning each column. If you want to set the alignment of
// each column, pass in a slice of Alignment values.
func RenderDisplayStrings(displayStringsArr [][]string, columnAlignments []Alignment) string {
displayStringsArr = excludeBlankColumns(displayStringsArr) displayStringsArr = excludeBlankColumns(displayStringsArr)
padWidths := getPadWidths(displayStringsArr) padWidths := getPadWidths(displayStringsArr)
output := getPaddedDisplayStrings(displayStringsArr, padWidths) columnConfigs := make([]ColumnConfig, len(padWidths))
for i, padWidth := range padWidths {
// gracefully handle when columnAlignments is shorter than padWidths
alignment := AlignLeft
if len(columnAlignments) > i {
alignment = columnAlignments[i]
}
columnConfigs[i] = ColumnConfig{
Width: padWidth,
Alignment: alignment,
}
}
output := getPaddedDisplayStrings(displayStringsArr, columnConfigs)
return output return output
} }
@ -59,23 +91,23 @@ outer:
return displayStringsArr return displayStringsArr
} }
func getPaddedDisplayStrings(stringArrays [][]string, padWidths []int) string { func getPaddedDisplayStrings(stringArrays [][]string, columnConfigs []ColumnConfig) string {
builder := strings.Builder{} builder := strings.Builder{}
for i, stringArray := range stringArrays { for i, stringArray := range stringArrays {
if len(stringArray) == 0 { if len(stringArray) == 0 {
continue continue
} }
for j, padWidth := range padWidths { for j, columnConfig := range columnConfigs {
if len(stringArray)-1 < j { if len(stringArray)-1 < j {
continue continue
} }
builder.WriteString(WithPadding(stringArray[j], padWidth)) builder.WriteString(WithPadding(stringArray[j], columnConfig.Width, columnConfig.Alignment))
builder.WriteString(" ") builder.WriteString(" ")
} }
if len(stringArray)-1 < len(padWidths) { if len(stringArray)-1 < len(columnConfigs) {
continue continue
} }
builder.WriteString(stringArray[len(padWidths)]) builder.WriteString(stringArray[len(columnConfigs)])
if i < len(stringArrays)-1 { if i < len(stringArrays)-1 {
builder.WriteString("\n") builder.WriteString("\n")

View File

@ -6,34 +6,49 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
// TestWithPadding is a function.
func TestWithPadding(t *testing.T) { func TestWithPadding(t *testing.T) {
type scenario struct { type scenario struct {
str string str string
padding int padding int
alignment Alignment
expected string expected string
} }
scenarios := []scenario{ scenarios := []scenario{
{ {
"hello world !", str: "hello world !",
1, padding: 1,
"hello world !", alignment: AlignLeft,
expected: "hello world !",
}, },
{ {
"hello world !", str: "hello world !",
14, padding: 14,
"hello world ! ", alignment: AlignLeft,
expected: "hello world ! ",
}, },
{ {
"Güçlü", str: "hello world !",
7, padding: 14,
"Güçlü ", alignment: AlignRight,
expected: " hello world !",
},
{
str: "Güçlü",
padding: 7,
alignment: AlignLeft,
expected: "Güçlü ",
},
{
str: "Güçlü",
padding: 7,
alignment: AlignRight,
expected: " Güçlü",
}, },
} }
for _, s := range scenarios { for _, s := range scenarios {
assert.EqualValues(t, s.expected, WithPadding(s.str, s.padding)) assert.EqualValues(t, s.expected, WithPadding(s.str, s.padding, s.alignment))
} }
} }
@ -145,38 +160,65 @@ func TestTruncateWithEllipsis(t *testing.T) {
func TestRenderDisplayStrings(t *testing.T) { func TestRenderDisplayStrings(t *testing.T) {
type scenario struct { type scenario struct {
input [][]string input [][]string
columnAlignments []Alignment
expected string expected string
} }
tests := []scenario{ tests := []scenario{
{ {
[][]string{{""}, {""}}, input: [][]string{{""}, {""}},
"", columnAlignments: nil,
expected: "",
}, },
{ {
[][]string{{"a"}, {""}}, input: [][]string{{"a"}, {""}},
"a\n", columnAlignments: nil,
expected: "a\n",
}, },
{ {
[][]string{{"a"}, {"b"}}, input: [][]string{{"a"}, {"b"}},
"a\nb", columnAlignments: nil,
expected: "a\nb",
}, },
{ {
[][]string{{"a", "b"}, {"c", "d"}}, input: [][]string{{"a", "b"}, {"c", "d"}},
"a b\nc d", columnAlignments: nil,
expected: "a b\nc d",
}, },
{ {
[][]string{{"a", "", "c"}, {"d", "", "f"}}, input: [][]string{{"a", "", "c"}, {"d", "", "f"}},
"a c\nd f", columnAlignments: nil,
expected: "a c\nd f",
}, },
{ {
[][]string{{"a", "", "c", ""}, {"d", "", "f", ""}}, input: [][]string{{"a", "", "c", ""}, {"d", "", "f", ""}},
"a c\nd f", columnAlignments: nil,
expected: "a c\nd f",
},
{
input: [][]string{{"abc", "", "d", ""}, {"e", "", "f", ""}},
columnAlignments: nil,
expected: "abc d\ne f",
},
{
input: [][]string{{"abc", "", "d", ""}, {"e", "", "f", ""}},
columnAlignments: []Alignment{AlignLeft, AlignLeft}, // same as nil (default)
expected: "abc d\ne f",
},
{
input: [][]string{{"abc", "", "d", ""}, {"e", "", "f", ""}},
columnAlignments: []Alignment{AlignRight, AlignLeft},
expected: "abc d\n e f",
},
{
input: [][]string{{"abc", "", "d", ""}, {"e", "", "f", ""}},
columnAlignments: []Alignment{AlignRight}, // gracefully defaults unspecified columns to left-align
expected: "abc d\n e f",
}, },
} }
for _, test := range tests { for _, test := range tests {
output := RenderDisplayStrings(test.input) output := RenderDisplayStrings(test.input, test.columnAlignments)
if !assert.EqualValues(t, output, test.expected) { if !assert.EqualValues(t, output, test.expected) {
t.Errorf("RenderDisplayStrings(%v) = %v, want %v", test.input, output, test.expected) t.Errorf("RenderDisplayStrings(%v) = %v, want %v", test.input, output, test.expected)
} }