summaryrefslogtreecommitdiff
path: root/internal/tui/reader_test.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-07-29 13:45:19 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-07-29 13:45:19 +0200
commit6964ee56de01f9769a39ba480dc787339b642f7a (patch)
treece20ba33e56a414e96e81a3d9d438c373534027e /internal/tui/reader_test.go
parent8ab0502569264478697bf3dbd060eadb82459647 (diff)
downloadlectio-6964ee56de01f9769a39ba480dc787339b642f7a.tar.gz
lectio-6964ee56de01f9769a39ba480dc787339b642f7a.zip
tui(reader): filter bookmarks by tag, and show tags in the list
Bookmarks stored tags but the list neither showed them nor let you use them. Now each row shows "Ref — note #tag1 #tag2", and `/` opens a live tag filter (case-insensitive substring over a bookmark's tags): type to narrow, Enter keeps the filter while j/k navigate the filtered list, Esc clears it. Navigation, open and delete all act on the visible (filtered) list. Reuses the store's existing tag data; help keybar (en/pl) updated; test covers filter/keys.
Diffstat (limited to 'internal/tui/reader_test.go')
-rw-r--r--internal/tui/reader_test.go49
1 files changed, 49 insertions, 0 deletions
diff --git a/internal/tui/reader_test.go b/internal/tui/reader_test.go
index 7bce759..da8d4d4 100644
--- a/internal/tui/reader_test.go
+++ b/internal/tui/reader_test.go
@@ -49,6 +49,55 @@ func win(m ReaderModel, w, h int) ReaderModel {
return nm.(ReaderModel)
}
+func TestReaderBookmarkTagFilter(t *testing.T) {
+ m := enReader(t)
+ m.marks = []bookmarks.Bookmark{
+ {ID: "1", Book: "John", Chapter: 3, Verse: 16, Tags: []string{"faith"}},
+ {ID: "2", Book: "Psalms", Chapter: 23, Verse: 1, Tags: []string{"work", "prayer"}},
+ {ID: "3", Book: "Matthew", Chapter: 5, Verse: 3, Tags: []string{"prayer"}},
+ }
+ m.mode = modeBookmarks
+
+ if got := len(m.visMarks()); got != 3 {
+ t.Fatalf("unfiltered visible = %d, want 3", got)
+ }
+
+ // "/" enters filter input; typing narrows to the two 'prayer' bookmarks.
+ m = key(m, runes("/"))
+ if !m.markFiltering {
+ t.Fatal(`"/" did not enter filter input`)
+ }
+ for _, c := range []string{"p", "r", "a", "y"} {
+ m = key(m, runes(c))
+ }
+ if got := len(m.visMarks()); got != 2 {
+ t.Fatalf(`filter "pray" visible = %d, want 2 (Psalms, Matthew)`, got)
+ }
+
+ // Enter keeps the filter and leaves input mode.
+ m = key(m, tea.KeyMsg{Type: tea.KeyEnter})
+ if m.markFiltering || m.markFilter != "pray" {
+ t.Fatalf("after enter: filtering=%v filter=%q", m.markFiltering, m.markFilter)
+ }
+
+ // Case-insensitive substring: "WORK" matches the 'work' tag (1 bookmark).
+ m.markFilter = "WORK"
+ if got := len(m.visMarks()); got != 1 {
+ t.Fatalf(`filter "WORK" visible = %d, want 1`, got)
+ }
+
+ // Esc clears an active filter, back to all.
+ m.markFilter = "work"
+ m.markFiltering = false
+ m = key(m, tea.KeyMsg{Type: tea.KeyEsc})
+ if m.markFilter != "" {
+ t.Fatalf("esc did not clear filter, got %q", m.markFilter)
+ }
+ if got := len(m.visMarks()); got != 3 {
+ t.Fatalf("after clearing filter, visible = %d, want 3", got)
+ }
+}
+
func TestReaderInit(t *testing.T) {
m := enReader(t)
if m.mode != modePick {