66 tea "github.com/charmbracelet/bubbletea"
77 "github.com/charmbracelet/lipgloss"
88 ltree "github.com/charmbracelet/lipgloss/tree"
9+ "github.com/charmbracelet/x/ansi"
910
11+ "github.com/charmbracelet/bubbles/help"
1012 "github.com/charmbracelet/bubbles/key"
1113)
1214
@@ -16,6 +18,7 @@ type Styles struct {
1618 SelectedNode lipgloss.Style
1719 ItemStyle lipgloss.Style
1820 SelectionCursor lipgloss.Style
21+ HelpStyle lipgloss.Style
1922}
2023
2124// DefaultStyles returns a set of default style definitions for this tree
@@ -27,6 +30,7 @@ func DefaultStyles() (s Styles) {
2730 Bold (true )
2831 s .SelectionCursor = lipgloss .NewStyle ().Foreground (lipgloss .Color ("9" ))
2932 s .ItemStyle = lipgloss .NewStyle ()
33+ s .HelpStyle = lipgloss .NewStyle ().Padding (1 , 0 , 0 , 2 )
3034
3135 return s
3236}
@@ -36,32 +40,68 @@ type KeyMap struct {
3640 Down key.Binding
3741 Up key.Binding
3842 Toggle key.Binding
39- Quit key.Binding
43+
44+ // Help toggle keybindings.
45+ ShowFullHelp key.Binding
46+ CloseFullHelp key.Binding
47+
48+ Quit key.Binding
4049}
4150
4251// DefaultKeyMap is the default set of key bindings for navigating and acting
4352// upon the tree.
4453var DefaultKeyMap = KeyMap {
45- Down : key .NewBinding (key .WithKeys ("down" , "j" , "ctrl+n" ), key .WithHelp ("down" , "next line" )),
46- Up : key .NewBinding (key .WithKeys ("up" , "k" , "ctrl+p" ), key .WithHelp ("up" , "previous line" )),
47- Toggle : key .NewBinding (key .WithKeys ("enter" ), key .WithHelp ("enter" , "toggle" )),
48- Quit : key .NewBinding (key .WithKeys ("q" , "ctrl+c" ), key .WithHelp ("q" , "quit" )),
54+ Down : key .NewBinding (
55+ key .WithKeys ("down" , "j" , "ctrl+n" ),
56+ key .WithHelp ("down" , "next line" ),
57+ ),
58+ Up : key .NewBinding (
59+ key .WithKeys ("up" , "k" , "ctrl+p" ),
60+ key .WithHelp ("up" , "previous line" ),
61+ ),
62+ Toggle : key .NewBinding (
63+ key .WithKeys ("enter" ),
64+ key .WithHelp ("enter" , "toggle" ),
65+ ),
66+
67+ // Toggle help.
68+ ShowFullHelp : key .NewBinding (
69+ key .WithKeys ("?" ),
70+ key .WithHelp ("?" , "more" ),
71+ ),
72+ CloseFullHelp : key .NewBinding (
73+ key .WithKeys ("?" ),
74+ key .WithHelp ("?" , "close help" ),
75+ ),
76+
77+ Quit : key .NewBinding (
78+ key .WithKeys ("q" , "ctrl+c" ),
79+ key .WithHelp ("q" , "quit" ),
80+ ),
4981}
5082
5183// Model is the Bubble Tea model for this tree element.
5284type Model struct {
53- root * Item
85+ showHelp bool
86+ // OpenCharacter is the character used to represent an open node.
87+ OpenCharacter string
88+ // ClosedCharacter is the character used to represent a closed node.
89+ ClosedCharacter string
5490 // KeyMap encodes the keybindings recognized by the widget.
5591 KeyMap KeyMap
56-
5792 // Styles sets the styling for the tree
5893 Styles Styles
94+ Help help.Model
5995
60- // OpenCharacter is the character used to represent an open node.
61- OpenCharacter string
96+ // Additional key mappings for the short and full help views. This allows
97+ // you to add additional key mappings to the help menu without
98+ // re-implementing the help component. Of course, you can also disable the
99+ // list's help component and implement a new one if you need more
100+ // flexibility.
101+ AdditionalShortHelpKeys func () []key.Binding
102+ AdditionalFullHelpKeys func () []key.Binding
62103
63- // ClosedCharacter is the character used to represent a closed node.
64- ClosedCharacter string
104+ root * Item
65105
66106 // yOffset is the vertical offset of the selected node.
67107 yOffset int
@@ -210,10 +250,12 @@ func Root(root any) *Item {
210250func New (t * Item ) Model {
211251 m := Model {
212252 root : t ,
253+ showHelp : true ,
213254 KeyMap : DefaultKeyMap ,
214255 Styles : DefaultStyles (),
215256 OpenCharacter : "▼" ,
216257 ClosedCharacter : "▶" ,
258+ Help : help .New (),
217259 }
218260 m .setAttributes ()
219261 m .updateStyles ()
@@ -246,6 +288,10 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
246288 m .yOffset = node .yOffset
247289 case key .Matches (msg , m .KeyMap .Quit ):
248290 return m , tea .Quit
291+ case key .Matches (msg , m .KeyMap .ShowFullHelp ):
292+ fallthrough
293+ case key .Matches (msg , m .KeyMap .CloseFullHelp ):
294+ m .Help .ShowAll = ! m .Help .ShowAll
249295 }
250296 }
251297
@@ -256,7 +302,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
256302
257303// View renders the component.
258304func (m Model ) View () string {
259- s := fmt .Sprintf ("y=%d \n " , m .yOffset )
305+ s := fmt .Sprintf ("y=%2d current=%s \n " , m .yOffset , ansi . Strip ( m . ItemAtCurrentOffset (). Value ()) )
260306
261307 // TODO: remove
262308 debug := printDebugInfo (m .root )
@@ -277,7 +323,53 @@ func (m Model) View() string {
277323 cursor ,
278324 m .root .String (),
279325 )
280- return lipgloss .JoinVertical (lipgloss .Left , s , t )
326+
327+ var help string
328+ if m .showHelp {
329+ help = m .helpView ()
330+ }
331+
332+ return lipgloss .JoinVertical (lipgloss .Left , s , t , help )
333+ }
334+
335+ // ShortHelp returns bindings to show in the abbreviated help view. It's part
336+ // of the help.KeyMap interface.
337+ func (m Model ) ShortHelp () []key.Binding {
338+ kb := []key.Binding {
339+ m .KeyMap .Up ,
340+ m .KeyMap .Down ,
341+ m .KeyMap .Toggle ,
342+ m .KeyMap .Quit ,
343+ }
344+
345+ if m .AdditionalShortHelpKeys != nil {
346+ kb = append (kb , m .AdditionalShortHelpKeys ()... )
347+ }
348+
349+ return kb
350+ }
351+
352+ // FullHelp returns bindings to show the full help view. It's part of the
353+ // help.KeyMap interface.
354+ func (m Model ) FullHelp () [][]key.Binding {
355+ kb := [][]key.Binding {
356+ {
357+ m .KeyMap .Up ,
358+ m .KeyMap .Down ,
359+ m .KeyMap .Toggle ,
360+ m .KeyMap .Quit ,
361+ },
362+ }
363+
364+ if m .AdditionalFullHelpKeys != nil {
365+ kb = append (kb , m .AdditionalFullHelpKeys ())
366+ }
367+
368+ return kb
369+ }
370+
371+ func (m Model ) helpView () string {
372+ return m .Styles .HelpStyle .Render (m .Help .View (m ))
281373}
282374
283375// FlatItems returns all items in the tree as a flat list.
0 commit comments