internal/tui/keys/keys.go

// Package keys centralises the bubbletea key-binding table so that
// help/keys_test can enumerate and test them without reaching into
// internal/tui.
//
// mercemay.top/src/httptap/
package keys

import (
	"github.com/charmbracelet/bubbles/key"
	tea "github.com/charmbracelet/bubbletea"
)

// Map groups every keybinding exposed by the app.
type Map struct {
	Up           key.Binding
	Down         key.Binding
	PageUp       key.Binding
	PageDown     key.Binding
	Top          key.Binding
	Bottom       key.Binding
	Quit         key.Binding
	Help         key.Binding
	ToggleFilter key.Binding
	FocusList    key.Binding
	FocusDetail  key.Binding
	Export       key.Binding
	Copy         key.Binding
}

// Default returns the stock keybindings.
func Default() Map {
	return Map{
		Up:           key.NewBinding(key.WithKeys("up", "k"), key.WithHelp("↑/k", "up")),
		Down:         key.NewBinding(key.WithKeys("down", "j"), key.WithHelp("↓/j", "down")),
		PageUp:       key.NewBinding(key.WithKeys("pgup", "b"), key.WithHelp("pgup/b", "page up")),
		PageDown:     key.NewBinding(key.WithKeys("pgdown", "f", " "), key.WithHelp("pgdn/space", "page down")),
		Top:          key.NewBinding(key.WithKeys("g", "home"), key.WithHelp("g", "top")),
		Bottom:       key.NewBinding(key.WithKeys("G", "end"), key.WithHelp("G", "bottom")),
		Quit:         key.NewBinding(key.WithKeys("q", "ctrl+c"), key.WithHelp("q", "quit")),
		Help:         key.NewBinding(key.WithKeys("?"), key.WithHelp("?", "help")),
		ToggleFilter: key.NewBinding(key.WithKeys("/"), key.WithHelp("/", "filter")),
		FocusList:    key.NewBinding(key.WithKeys("esc"), key.WithHelp("esc", "focus list")),
		FocusDetail:  key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "focus detail")),
		Export:       key.NewBinding(key.WithKeys("e"), key.WithHelp("e", "export")),
		Copy:         key.NewBinding(key.WithKeys("y"), key.WithHelp("y", "copy")),
	}
}

// Matches is a thin wrapper over key.Matches that also tolerates the
// common case where the caller passes a single binding instead of a slice.
func (m Map) Matches(msg tea.KeyMsg, b key.Binding) bool {
	return key.Matches(msg, b)
}

// All returns every binding in iteration order. Used by the help view
// and keys_test for coverage checks.
func (m Map) All() []key.Binding {
	return []key.Binding{
		m.Up, m.Down, m.PageUp, m.PageDown, m.Top, m.Bottom,
		m.Quit, m.Help, m.ToggleFilter, m.FocusList, m.FocusDetail,
		m.Export, m.Copy,
	}
}