keymap

package
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 30, 2026 License: AGPL-3.0 Imports: 2 Imported by: 0

Documentation

Overview

Package keymap is the keymap as data, not as code. One table yields the runtime dispatch, the generated help screen, and the collision test. Build spec section 4.6 requires this: a switch statement cannot generate its own help, and the two drift.

This package lives under internal/uikit, so it must not import bubbletea. It deals in key strings, which is what bubbletea's Key.String() produces; the view layer does the conversion.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Binding

type Binding struct {
	ID      ID
	Context Context
	Keys    []string
	Help    string
	// Short is the one-word label the compact footer hint uses. A binding
	// without one never appears in a hint; the full Help text is unchanged.
	Short string
	// Hidden keeps a binding out of the generated help without removing
	// it from dispatch. Use it for alternate spellings of a key, never
	// to hide a binding a user must know about.
	Hidden bool
}

Binding is one row of the table.

func Default

func Default() []Binding

Default returns the shipped keymap.

Reserved keys are deliberately absent; see docs/design/ux-rules.md section 1. Notably Ctrl-S is XOFF and freezes the terminal, so the design's Ctrl-S reasoning toggle moved to Ctrl-R. Ctrl-M is byte-identical to Enter and is never bound. Ctrl-W is readline's word-rubout and is "close tab" in many emulators, so collapse-all moved off it too.

type Context

type Context string

Context is the surface a binding applies to. A key may mean different things in different contexts, and the same key may appear once per context without collision.

const (
	// ContextGlobal applies everywhere, in every screen and dialog.
	ContextGlobal Context = "global"
	// ContextComposer applies while the composer holds focus and no
	// completion menu is open.
	ContextComposer Context = "composer"
	// ContextCompletion applies while the completion menu is open. It is
	// separate from ContextComposer because the menu must claim Enter,
	// Esc and the arrows before the composer or the app see them.
	ContextCompletion Context = "completion"
	// ContextTranscript applies while a transcript block holds focus.
	ContextTranscript Context = "transcript"
	// ContextApproval applies while an approval prompt is pending.
	ContextApproval Context = "approval"
	// ContextDialog applies inside a modal dialog.
	ContextDialog Context = "dialog"
	// ContextPager applies inside the full-screen pager.
	ContextPager Context = "pager"
	// ContextFiles applies while the files panel's list holds focus.
	ContextFiles Context = "files"
	// ContextSettings applies inside the full-screen settings modal. It
	// does not cascade from ContextGlobal - like ContextPager, the
	// settings screen is a self-contained modal that consults only its
	// own context.
	ContextSettings Context = "settings"
)

type HelpRow

type HelpRow struct {
	Context Context
	Keys    string
	Help    string
}

HelpRow is one generated help line.

type ID

type ID string

ID names an action. The view layer switches on ID, never on a key string, so a rebind changes this table and nothing else.

const (
	IDCancel        ID = "cancel"
	IDQuit          ID = "quit"
	IDSend          ID = "send"
	IDNewline       ID = "newline"
	IDClearLine     ID = "clear-line"
	IDHelp          ID = "help"
	IDThemeDialog   ID = "theme-dialog"
	IDFocusNext     ID = "focus-next"
	IDFocusPrev     ID = "focus-prev"
	IDToggleBlock   ID = "toggle-block"
	IDExpandAll     ID = "expand-all"
	IDCollapseAll   ID = "collapse-all"
	IDCopyBlock     ID = "copy-block"
	IDScrollUp      ID = "scroll-up"
	IDScrollDown    ID = "scroll-down"
	IDScrollTop     ID = "scroll-top"
	IDScrollBottom  ID = "scroll-bottom"
	IDOpenPager     ID = "open-pager"
	IDToggleReason  ID = "toggle-reasoning"
	IDApproveOnce   ID = "approve-once"
	IDApproveAlways ID = "approve-always"
	IDDenyOnce      ID = "deny-once"
	IDDenyAlways    ID = "deny-always"
	IDAcceptPrefix  ID = "accept-prefix"
	IDMenuNext      ID = "menu-next"
	IDMenuPrev      ID = "menu-prev"
	IDMenuAccept    ID = "menu-accept"
	IDMenuDismiss   ID = "menu-dismiss"
	IDDialogUp      ID = "dialog-up"
	IDDialogDown    ID = "dialog-down"
	IDDialogAccept  ID = "dialog-accept"
	IDDialogCancel  ID = "dialog-cancel"

	// Transcript mode (the pager). One ID per less-compatible action, so
	// the help screen names every key the pager answers to
	// (docs/design/cockpit-research.md rule 6.2).
	IDSearchStart    ID = "search-start"
	IDSearchNext     ID = "search-next"
	IDSearchPrev     ID = "search-prev"
	IDPagerRowUp     ID = "pager-row-up"
	IDPagerRowDown   ID = "pager-row-down"
	IDPagerTop       ID = "pager-top"
	IDPagerBottom    ID = "pager-bottom"
	IDPagerPromptUp  ID = "pager-prompt-up"
	IDPagerPromptDn  ID = "pager-prompt-down"
	IDPagerHalfUp    ID = "pager-half-up"
	IDPagerHalfDown  ID = "pager-half-down"
	IDPagerFullUp    ID = "pager-full-up"
	IDPagerFullDown  ID = "pager-full-down"
	IDLeavePager     ID = "leave-pager"
	IDDumpScrollback ID = "dump-scrollback"
	IDEditTranscript ID = "edit-transcript"

	// Files panel (the touched-files pane beside the conversation).
	IDPanelToggle    ID = "panel-toggle"
	IDFileToggleView ID = "file-toggle-view"
	IDFileOpen       ID = "file-open"

	// Universal Command Palette (Ctrl+P / Ctrl+X).
	IDPalette ID = "command-palette"

	// Queue manager overlay (Ctrl+Up).
	IDQueueDialog ID = "queue-dialog"

	// Settings screen. IDSettingsDialog is the global key that opens it
	// (f2, not ctrl+g - see its binding below for why); the rest are
	// ContextSettings-scoped.
	IDSettingsDialog    ID = "settings-dialog"
	IDSettingsUp        ID = "settings-up"
	IDSettingsDown      ID = "settings-down"
	IDSettingsPaneLeft  ID = "settings-pane-left"
	IDSettingsPaneRight ID = "settings-pane-right"
	IDSettingsSelect    ID = "settings-select"
	IDSettingsNew       ID = "settings-new"
	IDSettingsDelete    ID = "settings-delete"
	IDSettingsDefault   ID = "settings-default"
	// IDSettingsProjectDefault and IDSettingsClearOverride are Models-only:
	// a provider's default_model can be
	// set independently at Global and Project scope (internal/config.
	// LoadProviderDefaultOverrides), so "set as default" (d, whichever
	// scope the focused row IS) is not enough to also let a Global row
	// create a project override, or a Project row's override be
	// cleared back to the Global value. Harmless no-op on every other
	// section, the same tolerance IDSettingsTrigger already has.
	IDSettingsProjectDefault ID = "settings-project-default"
	IDSettingsClearOverride  ID = "settings-clear-override"
	IDSettingsToggle         ID = "settings-toggle"
	IDSettingsTrigger        ID = "settings-trigger"
	IDSettingsFilter         ID = "settings-filter"
	IDSettingsReveal         ID = "settings-reveal"
	IDSettingsBack           ID = "settings-back"
	IDSettingsHelp           ID = "settings-help"

	// Blackboard & agent messaging center.
	IDBlackboardDialog ID = "blackboard-dialog"

	// Force-send: interrupt the current turn (composer) or force-send
	// the selected queued message (dialog).
	IDForceSend ID = "force-send"
)

Action identifiers.

type Map

type Map struct {
	// contains filtered or unexported fields
}

Map indexes bindings for dispatch and help generation.

func New

func New(bindings []Binding) *Map

New indexes the given bindings.

func (*Map) Collisions

func (m *Map) Collisions() []string

Collisions reports keys bound to more than one ID within a context. A collision is a defect: the later binding silently wins at runtime.

func (*Map) Help

func (m *Map) Help() []HelpRow

Help generates the help screen from the table. It is the only help source, so adding a binding updates the help with no second edit.

func (*Map) Hint

func (m *Map) Hint(ids ...ID) string

Hint renders a compact one-line key hint ("? help ctrl+o transcript") from the same table that feeds Help, so the persistent footer hint and the help screen cannot drift. Each named ID uses its first key and its Short label; an ID with no Short label is skipped, and an unknown ID is skipped rather than reported: hints are chrome, not dispatch.

func (*Map) Match

func (m *Map) Match(ctx Context, key string) (ID, bool)

Match resolves a key string within one context.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL