Skip to content

Commit ee5636d

Browse files
committed
feat(help): add styled whitespace with configurable background
Added WhitespaceStyle fields to both short and full help Styles struct, llowing customization of whitespace appearance between keys and descriptions. Previously whitespace was unstyled, now it matches the aesthetic of other elements and can be customized (e.g. with background colors for testing). - Added ShortWhitespace and FullWhitespace to Styles struct - Modified ShortHelpView to use styled whitespace between key and desc - Modified FullHelpView to use styled whitespace between key and desc - Added tests to verify whitespace styling behavior Fixes #571
1 parent 8624776 commit ee5636d

12 files changed

+137
-15
lines changed

help/help.go

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,16 @@ type Styles struct {
3131
Ellipsis lipgloss.Style
3232

3333
// Styling for the short help
34-
ShortKey lipgloss.Style
35-
ShortDesc lipgloss.Style
36-
ShortSeparator lipgloss.Style
34+
ShortKey lipgloss.Style
35+
ShortDesc lipgloss.Style
36+
ShortSeparator lipgloss.Style
37+
ShortWhitespace lipgloss.Style
3738

3839
// Styling for the full help
39-
FullKey lipgloss.Style
40-
FullDesc lipgloss.Style
41-
FullSeparator lipgloss.Style
40+
FullKey lipgloss.Style
41+
FullDesc lipgloss.Style
42+
FullSeparator lipgloss.Style
43+
FullWhitespace lipgloss.Style
4244
}
4345

4446
// Model contains the state of the help view.
@@ -78,13 +80,15 @@ func New() Model {
7880
FullSeparator: " ",
7981
Ellipsis: "…",
8082
Styles: Styles{
81-
ShortKey: keyStyle,
82-
ShortDesc: descStyle,
83-
ShortSeparator: sepStyle,
84-
Ellipsis: sepStyle,
85-
FullKey: keyStyle,
86-
FullDesc: descStyle,
87-
FullSeparator: sepStyle,
83+
ShortKey: keyStyle,
84+
ShortDesc: descStyle,
85+
ShortSeparator: sepStyle,
86+
ShortWhitespace: sepStyle,
87+
Ellipsis: sepStyle,
88+
FullKey: keyStyle,
89+
FullDesc: descStyle,
90+
FullSeparator: sepStyle,
91+
FullWhitespace: sepStyle,
8892
},
8993
}
9094
}
@@ -132,7 +136,8 @@ func (m Model) ShortHelpView(bindings []key.Binding) string {
132136

133137
// Item
134138
str := sep +
135-
m.Styles.ShortKey.Inline(true).Render(kb.Help().Key) + " " +
139+
m.Styles.ShortKey.Inline(true).Render(kb.Help().Key) +
140+
m.Styles.ShortWhitespace.Inline(true).Render(" ") +
136141
m.Styles.ShortDesc.Inline(true).Render(kb.Help().Desc)
137142
w := lipgloss.Width(str)
138143

@@ -197,7 +202,7 @@ func (m Model) FullHelpView(groups [][]key.Binding) string {
197202
col := lipgloss.JoinHorizontal(lipgloss.Top,
198203
sep,
199204
m.Styles.FullKey.Render(strings.Join(keys, "\n")),
200-
" ",
205+
m.Styles.FullWhitespace.Render(" "),
201206
m.Styles.FullDesc.Render(strings.Join(descriptions, "\n")),
202207
)
203208
w := lipgloss.Width(col)

help/help_whitespace_test.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package help
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/charmbracelet/bubbles/key"
8+
"github.com/charmbracelet/lipgloss"
9+
"github.com/charmbracelet/x/exp/golden"
10+
)
11+
12+
func TestWhitespaceStyle(t *testing.T) {
13+
m := New()
14+
m.FullSeparator = " | "
15+
16+
// Set a distinctive background color for whitespace to make it visible in tests
17+
whitespaceBg := lipgloss.Color("#FF0000")
18+
m.Styles.ShortWhitespace = m.Styles.ShortWhitespace.Background(whitespaceBg)
19+
m.Styles.FullWhitespace = m.Styles.FullWhitespace.Background(whitespaceBg)
20+
21+
// Standard keys setup
22+
k := key.WithKeys("x")
23+
kb := [][]key.Binding{
24+
{
25+
key.NewBinding(k, key.WithHelp("enter", "continue")),
26+
},
27+
{
28+
key.NewBinding(k, key.WithHelp("esc", "back")),
29+
key.NewBinding(k, key.WithHelp("?", "help")),
30+
},
31+
{
32+
key.NewBinding(k, key.WithHelp("H", "home")),
33+
key.NewBinding(k, key.WithHelp("ctrl+c", "quit")),
34+
key.NewBinding(k, key.WithHelp("ctrl+l", "log")),
35+
},
36+
}
37+
38+
// Test both views at different widths
39+
for _, w := range []int{20, 30, 40} {
40+
t.Run(fmt.Sprintf("full_help_width_%d", w), func(t *testing.T) {
41+
m.Width = w
42+
s := m.FullHelpView(kb)
43+
golden.RequireEqual(t, []byte(s))
44+
})
45+
46+
t.Run(fmt.Sprintf("short_help_width_%d", w), func(t *testing.T) {
47+
m.Width = w
48+
// Flatten the bindings for short help
49+
var shortBindings []key.Binding
50+
for _, group := range kb {
51+
shortBindings = append(shortBindings, group...)
52+
}
53+
s := m.ShortHelpView(shortBindings)
54+
golden.RequireEqual(t, []byte(s))
55+
})
56+
}
57+
58+
// Test with a disabled item and custom style
59+
for _, tc := range []struct {
60+
name string
61+
setupFn func()
62+
bindings [][]key.Binding
63+
}{
64+
{
65+
name: "disabled_item",
66+
setupFn: func() {
67+
m.Width = 40
68+
},
69+
bindings: [][]key.Binding{{
70+
key.NewBinding(k, key.WithHelp("enter", "continue")),
71+
key.NewBinding(k, key.WithHelp("ctrl+c", "quit"), key.WithDisabled()),
72+
}},
73+
},
74+
{
75+
name: "custom_style",
76+
setupFn: func() {
77+
m.Width = 40
78+
customBg := lipgloss.Color("#00FF00")
79+
m.Styles.FullWhitespace = m.Styles.FullWhitespace.Background(customBg)
80+
m.Styles.ShortWhitespace = m.Styles.ShortWhitespace.Background(customBg)
81+
},
82+
bindings: kb,
83+
},
84+
} {
85+
t.Run(tc.name+"_full", func(t *testing.T) {
86+
tc.setupFn()
87+
s := m.FullHelpView(tc.bindings)
88+
golden.RequireEqual(t, []byte(s))
89+
})
90+
91+
t.Run(tc.name+"_short", func(t *testing.T) {
92+
tc.setupFn()
93+
// Flatten the bindings for short help
94+
var shortBindings []key.Binding
95+
for _, group := range tc.bindings {
96+
shortBindings = append(shortBindings, group...)
97+
}
98+
s := m.ShortHelpView(shortBindings)
99+
golden.RequireEqual(t, []byte(s))
100+
})
101+
}
102+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
enter continue | esc back | H home
2+
? help ctrl+c quit
3+
ctrl+l log
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
enter continue • esc back • ? help …
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
enter continue
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
enter continue
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
enter continue …
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
enter continue | esc back …
2+
? help
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
enter continue | esc back | H home
2+
? help ctrl+c quit
3+
ctrl+l log
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
enter continue …
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
enter continue • esc back …
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
enter continue • esc back • ? help …

0 commit comments

Comments
 (0)