Files
nib-v1/internal/tui/help.go
lerko 2684eb1d24
CI / test (pull_request) Successful in 2m18s
feat(tui): add link picker and navigation history
Press [ in detail view to open link picker showing all [[links]]
in the current entry. Enter follows a link, resolving by title
then body substring. Navigation history stack enables esc to pop
back through followed links before returning to list.

Adds Store.ResolveLink() for non-transactional link resolution
from the TUI layer.
2026-05-21 14:03:09 -04:00

120 lines
3.0 KiB
Go

package tui
import "strings"
func renderHelp(width, height int) string {
sections := []struct {
title string
binds [][2]string
}{
{"Focus", [][2]string{
{"tab", "toggle capture ↔ list"},
{"esc", "back / clear filter / to capture"},
{"a", "focus capture bar"},
{"h", "focus tag rail (from list)"},
{"l", "focus detail (split view)"},
{"ctrl+b", "toggle tag rail"},
}},
{"Capture Bar", [][2]string{
{"enter", "submit (or browse if empty)"},
{"?…", "search (type ?query)"},
{"#…", "tag (autocomplete with tab)"},
{"-", "todo prefix"},
{"@", "event prefix"},
{"!", "reminder prefix"},
}},
{"Query Operators", [][2]string{
{"?text", "substring search"},
{"?#tag1 #tag2", "filter by tags (AND)"},
{"?@today @week", "date filter (@yesterday @month)"},
{"?<7d >30d", "newer/older than N days"},
{"?^snippet", "card type filter"},
}},
{"Navigation", [][2]string{
{"j/k ↑/↓", "move cursor"},
{"g/G home/end", "top / bottom"},
{"pgup/pgdn", "page up / down"},
{"enter", "view detail"},
}},
{"Views", [][2]string{
{"1", "stream view"},
{"2", "cards view"},
{"s", "cycle sort (cards)"},
{"i", "cycle intent (cards)"},
{"T", "cycle theme"},
}},
{"Actions", [][2]string{
{"d", "delete (with confirm)"},
{"x", "toggle todo completion"},
{"!", "toggle pin"},
{"#", "filter by tag"},
{"m", "absorb (merge into target)"},
{"p", "promote to card"},
{"S", "stumble (resurface stale entries)"},
}},
{"Detail View", [][2]string{
{"p", "promote to card"},
{"D", "demote to fluid"},
{"c", "copy to clipboard"},
{"e", "edit in $EDITOR"},
{"!", "toggle pin"},
{"r", "run checklist"},
{"f", "fill template"},
{"[", "follow [[link]]"},
{"esc", "back (pops link history)"},
}},
{"Stumble", [][2]string{
{"n / →", "skip to next"},
{"d", "dismiss (soft delete)"},
{"!", "pin"},
{"p", "promote to card"},
{"m", "absorb"},
{"esc", "exit"},
}},
{"Run Mode", [][2]string{
{"j/k", "move between steps"},
{"space", "toggle step"},
{"r", "reset all steps"},
{"esc", "save + exit"},
}},
{"Fill Mode", [][2]string{
{"tab", "next slot"},
{"shift+tab", "prev slot"},
{"enter", "copy resolved"},
{"esc", "cancel"},
}},
{"Split View", [][2]string{
{"l", "focus detail pane"},
{"h", "focus list pane"},
{"esc", "close detail / back"},
}},
{"Global", [][2]string{
{"?", "toggle help"},
{"q / ctrl+c", "quit"},
}},
}
var b strings.Builder
b.WriteString(detailHeaderStyle.Render("keybindings"))
b.WriteString("\n\n")
for _, s := range sections {
b.WriteString(titleStyle.Render(s.title))
b.WriteString("\n")
for _, bind := range s.binds {
key := helpKeyStyle.Render(bind[0])
desc := helpDescStyle.Render(bind[1])
b.WriteString(" " + key + " " + desc + "\n")
}
b.WriteString("\n")
}
b.WriteString(helpStyle.Render("press ? or esc to close"))
lines := strings.Split(b.String(), "\n")
if len(lines) > height {
lines = lines[:height]
}
return strings.Join(lines, "\n")
}