diff --git a/internal/commands/key.go b/internal/commands/key.go index 6d8468d..0862fc6 100644 --- a/internal/commands/key.go +++ b/internal/commands/key.go @@ -168,9 +168,18 @@ var ViewportKeyMap = ViewportKeyMapT{ ), } +// viewportKeys is bubbles' viewport key map without "f", which the article +// view binds to favourite: left in, "f" would favourite and page down. +func viewportKeys() viewport.KeyMap { + k := viewport.DefaultKeyMap() + k.PageDown.SetKeys("pgdown", " ") + k.PageDown.SetHelp("pgdn/space", "page down") + return k +} + // This show *all* keybinds, as bubbles/viewport doesn't provide a help function func (k ViewportKeyMapT) FullHelp() [][]key.Binding { - v := viewport.DefaultKeyMap() + v := viewportKeys() return [][]key.Binding{ {v.Up, v.Down, v.HalfPageUp, v.HalfPageDown}, {k.GotoStart, k.GotoEnd, v.PageUp, v.PageDown}, @@ -181,7 +190,7 @@ func (k ViewportKeyMapT) FullHelp() [][]key.Binding { // This show *all* keybinds, as bubbles/viewport doesn't provide a help function func (k ViewportKeyMapT) ShortHelp() []key.Binding { - v := viewport.DefaultKeyMap() + v := viewportKeys() return []key.Binding{ k.Next, k.Prev, v.Down, v.Up, k.Escape, k.ShowFullHelp, } diff --git a/internal/commands/tui.go b/internal/commands/tui.go index 19036b1..47938fc 100644 --- a/internal/commands/tui.go +++ b/internal/commands/tui.go @@ -264,6 +264,7 @@ func Render(items []list.Item, cmds *Commands, errors []string, cfg *config.Conf ListKeyMap.SetOverrides(&l) vp := viewport.New(78, height) + vp.KeyMap = viewportKeys() m := model{ cfg: cfg, diff --git a/internal/commands/viewport_test.go b/internal/commands/viewport_test.go new file mode 100644 index 0000000..2c07933 --- /dev/null +++ b/internal/commands/viewport_test.go @@ -0,0 +1,77 @@ +package commands + +import ( + "strings" + "testing" + + "github.com/charmbracelet/bubbles/help" + "github.com/charmbracelet/bubbles/list" + "github.com/charmbracelet/bubbles/viewport" + tea "github.com/charmbracelet/bubbletea" + + "github.com/guyfedwards/nom/v2/internal/config" + "github.com/guyfedwards/nom/v2/internal/store" +) + +// articleModel returns a model showing one long article, as the list's +// Open leaves it. +func articleModel(t *testing.T) (model, store.Store, int) { + t.Helper() + + s, err := store.NewInMemorySQLiteStore() + if err != nil { + t.Fatal(err) + } + if err := s.UpsertItem(&store.Item{Title: "article", FeedURL: "https://example.com/feed", Link: "https://example.com/a", GUID: "a"}); err != nil { + t.Fatal(err) + } + items, err := s.GetAllItems("") + if err != nil || len(items) != 1 { + t.Fatalf("GetAllItems: %v, %d items", err, len(items)) + } + id := items[0].ID + + cfg := &config.Config{} + vp := viewport.New(78, 10) + vp.KeyMap = viewportKeys() + vp.SetContent(strings.Repeat("line\n", 100)) + + m := model{ + selectedArticle: &id, + cfg: cfg, + commands: New(cfg, s), + list: list.New(nil, list.NewDefaultDelegate(), 20, 10), + help: help.New(), + viewport: vp, + } + return m, s, id +} + +func TestFavouriteInArticleDoesNotPageDown(t *testing.T) { + m, s, id := articleModel(t) + + next, _ := updateViewport(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'f'}}, m) + m = next.(model) + + if m.viewport.YOffset != 0 { + t.Errorf("f scrolled the article to line %d, want it to stay at the top", m.viewport.YOffset) + } + item, err := s.GetItemByID(id) + if err != nil { + t.Fatal(err) + } + if !item.Favourite { + t.Error("f did not favourite the article") + } +} + +func TestSpaceStillPagesDownInArticle(t *testing.T) { + m, _, _ := articleModel(t) + + next, _ := updateViewport(tea.KeyMsg{Type: tea.KeySpace, Runes: []rune{' '}}, m) + m = next.(model) + + if m.viewport.YOffset == 0 { + t.Error("space did not page down") + } +}