From c1aac84743e59c86f828d5830734e24accc8c755 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 28 Apr 2022 19:12:47 -0400 Subject: [PATCH] feat: add full help toggle --- ui/components/code/code.go | 32 ++++++------ ui/components/footer/footer.go | 43 ++++++++++++---- ui/components/selector/selector.go | 9 +++- ui/components/viewport/viewport.go | 76 ++++++++++++++++++++--------- ui/keymap/keymap.go | 36 ++++++++++++++ ui/pages/repo/files.go | 70 +++++++++++++++++++++++++++ ui/pages/repo/log.go | 78 ++++++++++++++++++++---------- ui/pages/repo/refs.go | 45 ++++++++++++++++- ui/pages/repo/repo.go | 36 ++++++++++++-- ui/pages/selection/selection.go | 67 ++++++++++++++++--------- ui/ui.go | 77 ++++++++++++++++------------- 11 files changed, 433 insertions(+), 136 deletions(-) diff --git a/ui/components/code/code.go b/ui/components/code/code.go index 942e2ccf63af81896e8d1ab2aa8397812d85c6bb..bbdfe5db15e5da719170e9614bb7d01e19c0f091 100644 --- a/ui/components/code/code.go +++ b/ui/components/code/code.go @@ -16,10 +16,10 @@ import ( // Code is a code snippet. type Code struct { + *vp.Viewport common common.Common content string extension string - viewport *vp.Viewport NoContentStyle lipgloss.Style } @@ -29,7 +29,7 @@ func New(c common.Common, content, extension string) *Code { common: c, content: content, extension: extension, - viewport: vp.New(), + Viewport: vp.New(c), NoContentStyle: c.Styles.CodeNoContent.Copy(), } r.SetSize(c.Width, c.Height) @@ -39,7 +39,7 @@ func New(c common.Common, content, extension string) *Code { // SetSize implements common.Component. func (r *Code) SetSize(width, height int) { r.common.SetSize(width, height) - r.viewport.SetSize(width, height) + r.Viewport.SetSize(width, height) } // SetContent sets the content of the Code. @@ -66,7 +66,7 @@ func (r *Code) Init() tea.Cmd { for i, l := range s { s[i] = l + "\x1b[0m" } - r.viewport.Viewport.SetContent(strings.Join(s, "\n")) + r.Viewport.Model.SetContent(strings.Join(s, "\n")) return nil } @@ -78,8 +78,8 @@ func (r *Code) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Recalculate content width and line wrap. cmds = append(cmds, r.Init()) } - v, cmd := r.viewport.Update(msg) - r.viewport = v.(*vp.Viewport) + v, cmd := r.Viewport.Update(msg) + r.Viewport = v.(*vp.Viewport) if cmd != nil { cmds = append(cmds, cmd) } @@ -88,52 +88,52 @@ func (r *Code) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // View implements tea.View. func (r *Code) View() string { - return r.viewport.View() + return r.Viewport.View() } // GotoTop moves the viewport to the top of the log. func (r *Code) GotoTop() { - r.viewport.GotoTop() + r.Viewport.GotoTop() } // GotoBottom moves the viewport to the bottom of the log. func (r *Code) GotoBottom() { - r.viewport.GotoBottom() + r.Viewport.GotoBottom() } // HalfViewDown moves the viewport down by half the viewport height. func (r *Code) HalfViewDown() { - r.viewport.HalfViewDown() + r.Viewport.HalfViewDown() } // HalfViewUp moves the viewport up by half the viewport height. func (r *Code) HalfViewUp() { - r.viewport.HalfViewUp() + r.Viewport.HalfViewUp() } // ViewUp moves the viewport up by a page. func (r *Code) ViewUp() []string { - return r.viewport.ViewUp() + return r.Viewport.ViewUp() } // ViewDown moves the viewport down by a page. func (r *Code) ViewDown() []string { - return r.viewport.ViewDown() + return r.Viewport.ViewDown() } // LineUp moves the viewport up by the given number of lines. func (r *Code) LineUp(n int) []string { - return r.viewport.LineUp(n) + return r.Viewport.LineUp(n) } // LineDown moves the viewport down by the given number of lines. func (r *Code) LineDown(n int) []string { - return r.viewport.LineDown(n) + return r.Viewport.LineDown(n) } // ScrollPercent returns the viewport's scroll percentage. func (r *Code) ScrollPercent() float64 { - return r.viewport.ScrollPercent() + return r.Viewport.ScrollPercent() } func styleConfig() gansi.StyleConfig { diff --git a/ui/components/footer/footer.go b/ui/components/footer/footer.go index 43015a88fba7e73b157e9ede6f357da5e21d3b3f..05b66919cbabd1ee6018c22370aa17118c9817bb 100644 --- a/ui/components/footer/footer.go +++ b/ui/components/footer/footer.go @@ -1,7 +1,10 @@ package footer import ( + "strings" + "github.com/charmbracelet/bubbles/help" + "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/soft-serve/ui/common" ) @@ -25,13 +28,14 @@ func New(c common.Common, keymap help.KeyMap) *Footer { help: h, keymap: keymap, } + f.SetSize(c.Width, c.Height) return f } // SetSize implements common.Component. func (f *Footer) SetSize(width, height int) { - f.common.Width = width - f.common.Height = height + f.common.SetSize(width, height) + f.help.Width = width } // Init implements tea.Model. @@ -41,13 +45,6 @@ func (f *Footer) Init() tea.Cmd { // Update implements tea.Model. func (f *Footer) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { - case tea.KeyMsg: - switch msg.String() { - case "?": - f.help.ShowAll = !f.help.ShowAll - } - } return f, nil } @@ -57,5 +54,31 @@ func (f *Footer) View() string { return "" } s := f.common.Styles.Footer.Copy().Width(f.common.Width) - return s.Render(f.help.View(f.keymap)) + helpView := f.help.View(f.keymap) + return s.Render(helpView) +} + +// ShortHelp returns the short help key bindings. +func (f *Footer) ShortHelp() []key.Binding { + return f.keymap.ShortHelp() +} + +// FullHelp returns the full help key bindings. +func (f *Footer) FullHelp() [][]key.Binding { + return f.keymap.FullHelp() +} + +// ShowAll returns whether the full help is shown. +func (f *Footer) ShowAll() bool { + return f.help.ShowAll +} + +// SetShowAll sets whether the full help is shown. +func (f *Footer) SetShowAll(show bool) { + f.help.ShowAll = show +} + +// Height returns the height of the footer. +func (f *Footer) Height() int { + return len(strings.Split(f.View(), "\n")) } diff --git a/ui/components/selector/selector.go b/ui/components/selector/selector.go index 8704c5cfab6c05043129a45ef2bc34cc225f4548..ed044990e6d76473d015bb7b2c93b5352408bc02 100644 --- a/ui/components/selector/selector.go +++ b/ui/components/selector/selector.go @@ -144,9 +144,16 @@ func (s *Selector) Update(msg tea.Msg) (tea.Model, tea.Cmd) { s.Model.CursorDown() } case tea.KeyMsg: + filterState := s.Model.FilterState() switch { + case key.Matches(msg, s.common.KeyMap.Help): + if filterState == list.Filtering { + return s, tea.Batch(cmds...) + } case key.Matches(msg, s.common.KeyMap.Select): - cmds = append(cmds, s.selectCmd) + if filterState != list.Filtering { + cmds = append(cmds, s.selectCmd) + } } case list.FilterMatchesMsg: cmds = append(cmds, s.activeFilterCmd) diff --git a/ui/components/viewport/viewport.go b/ui/components/viewport/viewport.go index 59fc92b5a444e7bdd31203974cac23b67fe2cdfc..4223fa725ee93231c909c4faa0454929776230a8 100644 --- a/ui/components/viewport/viewport.go +++ b/ui/components/viewport/viewport.go @@ -1,27 +1,59 @@ package viewport import ( + "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/soft-serve/ui/common" ) // Viewport represents a viewport component. type Viewport struct { - Viewport *viewport.Model -} - -func New() *Viewport { + common common.Common + *viewport.Model +} + +// New returns a new Viewport. +func New(c common.Common) *Viewport { + vp := viewport.New(c.Width, c.Height) + vp.MouseWheelEnabled = true + vp.KeyMap = viewport.KeyMap{ + PageDown: key.NewBinding( + key.WithKeys("pgdown", " ", "f"), + key.WithHelp("f/pgdn", "page down"), + ), + PageUp: key.NewBinding( + key.WithKeys("pgup", "b"), + key.WithHelp("b/pgup", "page up"), + ), + HalfPageUp: key.NewBinding( + key.WithKeys("u", "ctrl+u"), + key.WithHelp("ctrl+u/u", "half page up"), + ), + HalfPageDown: key.NewBinding( + key.WithKeys("d", "ctrl+d"), + key.WithHelp("ctrl+d/d", "half page down"), + ), + Up: key.NewBinding( + key.WithKeys("up", "k"), + key.WithHelp("↑/k", "up"), + ), + Down: key.NewBinding( + key.WithKeys("down", "j"), + key.WithHelp("↓/j", "down"), + ), + } return &Viewport{ - Viewport: &viewport.Model{ - MouseWheelEnabled: true, - }, + common: c, + Model: &vp, } } // SetSize implements common.Component. func (v *Viewport) SetSize(width, height int) { - v.Viewport.Width = width - v.Viewport.Height = height + v.common.SetSize(width, height) + v.Model.Width = width + v.Model.Height = height } // Init implements tea.Model. @@ -31,62 +63,62 @@ func (v *Viewport) Init() tea.Cmd { // Update implements tea.Model. func (v *Viewport) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - vp, cmd := v.Viewport.Update(msg) - v.Viewport = &vp + vp, cmd := v.Model.Update(msg) + v.Model = &vp return v, cmd } // View implements tea.Model. func (v *Viewport) View() string { - return v.Viewport.View() + return v.Model.View() } // SetContent sets the viewport's content. func (v *Viewport) SetContent(content string) { - v.Viewport.SetContent(content) + v.Model.SetContent(content) } // GotoTop moves the viewport to the top of the log. func (v *Viewport) GotoTop() { - v.Viewport.GotoTop() + v.Model.GotoTop() } // GotoBottom moves the viewport to the bottom of the log. func (v *Viewport) GotoBottom() { - v.Viewport.GotoBottom() + v.Model.GotoBottom() } // HalfViewDown moves the viewport down by half the viewport height. func (v *Viewport) HalfViewDown() { - v.Viewport.HalfViewDown() + v.Model.HalfViewDown() } // HalfViewUp moves the viewport up by half the viewport height. func (v *Viewport) HalfViewUp() { - v.Viewport.HalfViewUp() + v.Model.HalfViewUp() } // ViewUp moves the viewport up by a page. func (v *Viewport) ViewUp() []string { - return v.Viewport.ViewUp() + return v.Model.ViewUp() } // ViewDown moves the viewport down by a page. func (v *Viewport) ViewDown() []string { - return v.Viewport.ViewDown() + return v.Model.ViewDown() } // LineUp moves the viewport up by the given number of lines. func (v *Viewport) LineUp(n int) []string { - return v.Viewport.LineUp(n) + return v.Model.LineUp(n) } // LineDown moves the viewport down by the given number of lines. func (v *Viewport) LineDown(n int) []string { - return v.Viewport.LineDown(n) + return v.Model.LineDown(n) } // ScrollPercent returns the viewport's scroll percentage. func (v *Viewport) ScrollPercent() float64 { - return v.Viewport.ScrollPercent() + return v.Model.ScrollPercent() } diff --git a/ui/keymap/keymap.go b/ui/keymap/keymap.go index ceeb81eaf079d34232430098a52f114526500922..d3e8a79a1b224def359ca2205ea8e49e2454e473 100644 --- a/ui/keymap/keymap.go +++ b/ui/keymap/keymap.go @@ -15,6 +15,10 @@ type KeyMap struct { Back key.Binding PrevPage key.Binding NextPage key.Binding + Help key.Binding + + SelectItem key.Binding + BackItem key.Binding } // DefaultKeyMap returns the default key map. @@ -152,5 +156,37 @@ func DefaultKeyMap() *KeyMap { ), ) + km.Help = key.NewBinding( + key.WithKeys( + "?", + ), + key.WithHelp( + "?", + "toggle help", + ), + ) + + km.SelectItem = key.NewBinding( + key.WithKeys( + "l", + "right", + ), + key.WithHelp( + "→", + "select", + ), + ) + + km.BackItem = key.NewBinding( + key.WithKeys( + "h", + "left", + ), + key.WithHelp( + "←", + "back", + ), + ) + return km } diff --git a/ui/pages/repo/files.go b/ui/pages/repo/files.go index b5222848ef6c1ad85c51fabe6ba2ae174aeb153e..4e501b0e7c61ab76cc5cbdffc6b8fd3743582d9d 100644 --- a/ui/pages/repo/files.go +++ b/ui/pages/repo/files.go @@ -6,6 +6,7 @@ import ( "log" "path/filepath" + "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" ggit "github.com/charmbracelet/soft-serve/git" "github.com/charmbracelet/soft-serve/ui/common" @@ -80,6 +81,75 @@ func (f *Files) SetSize(width, height int) { f.code.SetSize(width, height) } +// ShortHelp implements help.KeyMap. +func (f *Files) ShortHelp() []key.Binding { + k := f.selector.KeyMap + switch f.activeView { + case filesViewFiles: + return []key.Binding{ + f.common.KeyMap.SelectItem, + f.common.KeyMap.BackItem, + k.CursorUp, + k.CursorDown, + } + case filesViewContent: + return []key.Binding{ + f.common.KeyMap.UpDown, + f.common.KeyMap.BackItem, + } + default: + return []key.Binding{} + } +} + +// FullHelp implements help.KeyMap. +func (f *Files) FullHelp() [][]key.Binding { + b := make([][]key.Binding, 0) + switch f.activeView { + case filesViewFiles: + k := f.selector.KeyMap + b = append(b, []key.Binding{ + f.common.KeyMap.SelectItem, + f.common.KeyMap.BackItem, + }) + b = append(b, [][]key.Binding{ + {}, + { + k.CursorUp, + k.CursorDown, + }, + { + k.NextPage, + k.PrevPage, + }, + { + k.GoToStart, + k.GoToEnd, + }, + }...) + case filesViewContent: + k := f.code.KeyMap + b = append(b, []key.Binding{ + f.common.KeyMap.BackItem, + }) + b = append(b, [][]key.Binding{ + { + k.PageDown, + k.PageUp, + }, + { + k.HalfPageDown, + k.HalfPageUp, + }, + { + k.Down, + k.Up, + }, + }...) + } + return b +} + // Init implements tea.Model. func (f *Files) Init() tea.Cmd { f.path = "" diff --git a/ui/pages/repo/log.go b/ui/pages/repo/log.go index 20cedda7af85d6b9b2efda869edd08eba3b7d4cf..db87084c3d6a4b667dadfa13b37e11caac1248f0 100644 --- a/ui/pages/repo/log.go +++ b/ui/pages/repo/log.go @@ -57,7 +57,7 @@ type Log struct { func NewLog(common common.Common) *Log { l := &Log{ common: common, - vp: viewport.New(), + vp: viewport.New(common), activeView: logViewCommits, } selector := selector.New(common, []selector.IdentifiableItem{}, LogItemDelegate{common.Styles}) @@ -81,43 +81,68 @@ func (l *Log) SetSize(width, height int) { l.vp.SetSize(width, height) } -// ShortHelp implements key.KeyMap. +// ShortHelp implements help.KeyMap. func (l *Log) ShortHelp() []key.Binding { switch l.activeView { case logViewCommits: return []key.Binding{ - key.NewBinding( - key.WithKeys( - "l", - "right", - ), - key.WithHelp( - "→", - "select", - ), - ), + l.common.KeyMap.SelectItem, } case logViewDiff: return []key.Binding{ l.common.KeyMap.UpDown, - key.NewBinding( - key.WithKeys( - "h", - "left", - ), - key.WithHelp( - "←", - "back", - ), - ), + l.common.KeyMap.BackItem, } default: return []key.Binding{} } } -func (l Log) FullHelp() [][]key.Binding { - return [][]key.Binding{} +// FullHelp implements help.KeyMap. +func (l *Log) FullHelp() [][]key.Binding { + k := l.selector.KeyMap + b := make([][]key.Binding, 0) + switch l.activeView { + case logViewCommits: + b = append(b, []key.Binding{ + l.common.KeyMap.SelectItem, + l.common.KeyMap.BackItem, + }) + b = append(b, [][]key.Binding{ + { + k.CursorUp, + k.CursorDown, + }, + { + k.NextPage, + k.PrevPage, + }, + { + k.GoToStart, + k.GoToEnd, + }, + }...) + case logViewDiff: + k := l.vp.KeyMap + b = append(b, []key.Binding{ + l.common.KeyMap.BackItem, + }) + b = append(b, [][]key.Binding{ + { + k.PageDown, + k.PageUp, + }, + { + k.HalfPageDown, + k.HalfPageUp, + }, + { + k.Down, + k.Up, + }, + }...) + } + return b } // Init implements tea.Model. @@ -147,7 +172,10 @@ func (l *Log) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds = append(cmds, l.selector.SetItems(msg)) l.selector.SetPage(l.nextPage) l.SetSize(l.common.Width, l.common.Height) - l.activeCommit = l.selector.SelectedItem().(LogItem).Commit + i := l.selector.SelectedItem() + if i != nil { + l.activeCommit = i.(LogItem).Commit + } case tea.KeyMsg, tea.MouseMsg: switch l.activeView { case logViewCommits: diff --git a/ui/pages/repo/refs.go b/ui/pages/repo/refs.go index df5b000f39c727313c57188fe88402c2c125efc0..28392d0f19df38ecde166b4ad714cd2c8c03d837 100644 --- a/ui/pages/repo/refs.go +++ b/ui/pages/repo/refs.go @@ -4,6 +4,7 @@ import ( "sort" "strings" + "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" ggit "github.com/charmbracelet/soft-serve/git" "github.com/charmbracelet/soft-serve/ui/common" @@ -12,11 +13,13 @@ import ( "github.com/charmbracelet/soft-serve/ui/git" ) +// RefItemsMsg is a message that contains a list of RefItem. type RefItemsMsg struct { prefix string items []selector.IdentifiableItem } +// Refs is a component that displays a list of references. type Refs struct { common common.Common selector *selector.Selector @@ -26,6 +29,7 @@ type Refs struct { refPrefix string } +// NewRefs creates a new Refs component. func NewRefs(common common.Common, refPrefix string) *Refs { r := &Refs{ common: common, @@ -43,15 +47,48 @@ func NewRefs(common common.Common, refPrefix string) *Refs { return r } +// SetSize implements common.Component. func (r *Refs) SetSize(width, height int) { r.common.SetSize(width, height) r.selector.SetSize(width, height) } +// ShortHelp implements help.KeyMap. +func (r *Refs) ShortHelp() []key.Binding { + k := r.selector.KeyMap + return []key.Binding{ + r.common.KeyMap.SelectItem, + k.CursorUp, + k.CursorDown, + } +} + +// FullHelp implements help.KeyMap. +func (r *Refs) FullHelp() [][]key.Binding { + k := r.selector.KeyMap + return [][]key.Binding{ + {r.common.KeyMap.SelectItem}, + { + k.CursorUp, + k.CursorDown, + }, + { + k.NextPage, + k.PrevPage, + }, + { + k.GoToStart, + k.GoToEnd, + }, + } +} + +// Init implements tea.Model. func (r *Refs) Init() tea.Cmd { return r.updateItemsCmd } +// Update implements tea.Model. func (r *Refs) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds := make([]tea.Cmd, 0) switch msg := msg.(type) { @@ -64,7 +101,10 @@ func (r *Refs) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds = append(cmds, r.Init()) case RefItemsMsg: cmds = append(cmds, r.selector.SetItems(msg.items)) - r.activeRef = r.selector.SelectedItem().(RefItem).Reference + i := r.selector.SelectedItem() + if i != nil { + r.activeRef = i.(RefItem).Reference + } case selector.ActiveMsg: switch sel := msg.IdentifiableItem.(type) { case RefItem: @@ -93,10 +133,12 @@ func (r *Refs) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return r, tea.Batch(cmds...) } +// View implements tea.Model. func (r *Refs) View() string { return r.selector.View() } +// StausBarValue implements statusbar.StatusBar. func (r *Refs) StatusBarValue() string { if r.activeRef == nil { return "" @@ -104,6 +146,7 @@ func (r *Refs) StatusBarValue() string { return r.activeRef.Name().String() } +// StatusBarInfo implements statusbar.StatusBar. func (r *Refs) StatusBarInfo() string { return "" } diff --git a/ui/pages/repo/repo.go b/ui/pages/repo/repo.go index deddb798e597607600f98ece1b795714df8556fb..4a92841404e141b387be2ad269b7ae897ac1c235 100644 --- a/ui/pages/repo/repo.go +++ b/ui/pages/repo/repo.go @@ -92,19 +92,24 @@ func (r *Repo) SetSize(width, height int) { } } -// ShortHelp implements help.KeyMap. -func (r *Repo) ShortHelp() []key.Binding { +func (r *Repo) commonHelp() []key.Binding { b := make([]key.Binding, 0) + back := r.common.KeyMap.Back + back.SetHelp("esc", "back to menu") tab := r.common.KeyMap.Section tab.SetHelp("tab", "switch tab") - back := r.common.KeyMap.Back - back.SetHelp("esc", "repos") b = append(b, back) b = append(b, tab) + return b +} + +// ShortHelp implements help.KeyMap. +func (r *Repo) ShortHelp() []key.Binding { + b := r.commonHelp() switch r.activeTab { case readmeTab: b = append(b, r.common.KeyMap.UpDown) - case commitsTab: + default: b = append(b, r.boxes[commitsTab].(help.KeyMap).ShortHelp()...) } return b @@ -113,6 +118,27 @@ func (r *Repo) ShortHelp() []key.Binding { // FullHelp implements help.KeyMap. func (r *Repo) FullHelp() [][]key.Binding { b := make([][]key.Binding, 0) + b = append(b, r.commonHelp()) + switch r.activeTab { + case readmeTab: + k := r.boxes[readmeTab].(*code.Code).KeyMap + b = append(b, [][]key.Binding{ + { + k.PageDown, + k.PageUp, + }, + { + k.HalfPageDown, + k.HalfPageUp, + }, + { + k.Down, + k.Up, + }, + }...) + default: + b = append(b, r.boxes[r.activeTab].(help.KeyMap).FullHelp()...) + } return b } diff --git a/ui/pages/selection/selection.go b/ui/pages/selection/selection.go index 0cb4986918b4502aad8402f159d11ca44e95ebf7..66fc5c2e4689f175c2bd904c47f4a112f5bf96c4 100644 --- a/ui/pages/selection/selection.go +++ b/ui/pages/selection/selection.go @@ -62,7 +62,7 @@ func (s *Selection) SetSize(width, height int) { // +1 to get wrapping to work. // This is needed because the readme box width has to be -1 from the // readme style in order for wrapping to not break. - 2 + 1 hm := s.common.Styles.ReadmeBox.GetVerticalFrameSize() s.readme.SetSize(width-wm, height-hm) s.selector.SetSize(sw, height) @@ -87,30 +87,51 @@ func (s *Selection) ShortHelp() []key.Binding { } // FullHelp implements help.KeyMap. -// TODO implement full help on ? func (s *Selection) FullHelp() [][]key.Binding { - k := s.selector.KeyMap - return [][]key.Binding{ - { - k.CursorUp, - k.CursorDown, - k.NextPage, - k.PrevPage, - k.GoToStart, - k.GoToEnd, - }, - { - k.Filter, - k.ClearFilter, - k.CancelWhileFiltering, - k.AcceptWhileFiltering, - k.ShowFullHelp, - k.CloseFullHelp, - }, - // Ignore the following keys: - // k.Quit, - // k.ForceQuit, + switch s.activeBox { + case readmeBox: + k := s.readme.KeyMap + return [][]key.Binding{ + { + k.PageDown, + k.PageUp, + }, + { + k.HalfPageDown, + k.HalfPageUp, + }, + { + k.Down, + k.Up, + }, + } + case selectorBox: + k := s.selector.KeyMap + return [][]key.Binding{ + { + s.common.KeyMap.Select, + }, + { + k.CursorUp, + k.CursorDown, + }, + { + k.NextPage, + k.PrevPage, + }, + { + k.GoToStart, + k.GoToEnd, + }, + { + k.Filter, + k.ClearFilter, + k.CancelWhileFiltering, + k.AcceptWhileFiltering, + }, + } } + return [][]key.Binding{} } // Init implements tea.Model. diff --git a/ui/ui.go b/ui/ui.go index b84eeb223b22da136ea6150790011db28e13f32f..4ace7c6b5dd18543bcf54ddc1e07d08dfac8881c 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -2,7 +2,6 @@ package ui import ( "log" - "strings" "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" @@ -57,7 +56,7 @@ func (ui *UI) getMargins() (wm, hm int) { wm = ui.common.Styles.App.GetHorizontalFrameSize() hm = ui.common.Styles.App.GetVerticalFrameSize() + ui.common.Styles.Header.GetHeight() + - ui.common.Styles.Footer.GetHeight() + ui.footer.Height() return } @@ -70,7 +69,10 @@ func (ui *UI) ShortHelp() []key.Binding { case loadedState: b = append(b, ui.pages[ui.activePage].ShortHelp()...) } - b = append(b, ui.common.KeyMap.Quit) + b = append(b, + ui.common.KeyMap.Quit, + ui.common.KeyMap.Help, + ) return b } @@ -83,7 +85,10 @@ func (ui *UI) FullHelp() [][]key.Binding { case loadedState: b = append(b, ui.pages[ui.activePage].FullHelp()...) } - b = append(b, []key.Binding{ui.common.KeyMap.Quit}) + b = append(b, []key.Binding{ + ui.common.KeyMap.Quit, + ui.common.KeyMap.Help, + }) return b } @@ -114,7 +119,6 @@ func (ui *UI) Init() tea.Cmd { } // Update implements tea.Model. -// TODO show full help. func (ui *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { log.Printf("msg: %T", msg) cmds := make([]tea.Cmd, 0) @@ -128,15 +132,20 @@ func (ui *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds = append(cmds, cmd) } } - case tea.KeyMsg: - switch { - case key.Matches(msg, ui.common.KeyMap.Back) && ui.error != nil: - ui.error = nil - ui.state = loadedState - case key.Matches(msg, ui.common.KeyMap.Quit): - return ui, tea.Quit - case ui.activePage == 1 && key.Matches(msg, ui.common.KeyMap.Back): - ui.activePage = 0 + case tea.KeyMsg, tea.MouseMsg: + switch msg := msg.(type) { + case tea.KeyMsg: + switch { + case key.Matches(msg, ui.common.KeyMap.Back) && ui.error != nil: + ui.error = nil + ui.state = loadedState + case key.Matches(msg, ui.common.KeyMap.Help): + ui.footer.SetShowAll(!ui.footer.ShowAll()) + case key.Matches(msg, ui.common.KeyMap.Quit): + return ui, tea.Quit + case ui.activePage == 1 && key.Matches(msg, ui.common.KeyMap.Back): + ui.activePage = 0 + } } case common.ErrorMsg: ui.error = msg @@ -168,43 +177,45 @@ func (ui *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds = append(cmds, cmd) } } + // This fixes determining the height margin of the footer. + ui.SetSize(ui.common.Width, ui.common.Height) return ui, tea.Batch(cmds...) } // View implements tea.Model. func (ui *UI) View() string { - s := strings.Builder{} + var view string + footer := ui.footer.View() + style := ui.common.Styles.App.Copy() switch ui.state { case startState: - s.WriteString("Loading...") + view = "Loading..." case errorState: err := ui.common.Styles.ErrorTitle.Render("Bummer") err += ui.common.Styles.ErrorBody.Render(ui.error.Error()) - view := ui.common.Styles.ErrorBody.Copy(). + view = ui.common.Styles.ErrorBody.Copy(). Width(ui.common.Width - - ui.common.Styles.App.GetHorizontalFrameSize() - + style.GetWidth() - + style.GetHorizontalFrameSize() - ui.common.Styles.ErrorBody.GetHorizontalFrameSize()). Height(ui.common.Height - - ui.common.Styles.App.GetVerticalFrameSize() - + style.GetHeight() - + style.GetVerticalFrameSize() - ui.common.Styles.Header.GetVerticalFrameSize() - 2). Render(err) - s.WriteString(lipgloss.JoinVertical( - lipgloss.Bottom, - ui.header.View(), - view, - ui.footer.View(), - )) case loadedState: - s.WriteString(lipgloss.JoinVertical( - lipgloss.Bottom, - ui.header.View(), - ui.pages[ui.activePage].View(), - ui.footer.View(), - )) + view = ui.pages[ui.activePage].View() default: - s.WriteString("Unknown state :/ this is a bug!") + view = "Unknown state :/ this is a bug!" } - return ui.common.Styles.App.Render(s.String()) + return style.Render( + lipgloss.JoinVertical( + lipgloss.Bottom, + ui.header.View(), + view, + footer, + ), + ) } func (ui *UI) setRepoCmd(rn string) tea.Cmd {