Configure Navigation Keys
ListViewWidget and TreeViewWidget accept an item navigation preset. The
default is lazygit-style movement with j/k and arrow-key aliases, but without
count prefixes. Apps can provide another preset without subclassing widgets.
import lazy_cuh as lcfrom lazy_cuh.widgets import ListViewWidget
preset = lc.presets.navigation.lazygit()
yield ListViewWidget(model, navigation=preset, id="items")The preset bundles the runtime keymap and matching keybar hints:
preset.keymappreset.keybar_hintsUse lazy_vim() when a surface should accept counted movement such as 5j.
Line-number mode is separate view state; choosing a movement preset does not
toggle line numbers.
vim_preset = lc.presets.navigation.lazy_vim(include_select=True)tree.set_navigation(vim_preset)list_view.set_navigation(vim_preset)For lower-level control, pass a raw NavigableKeymap as keymap=....
from lazy_cuh.widgets import NavigableKeymap
keymap = NavigableKeymap( down=("n",), up=("p",), first_prefix=("f",), first=("f",), last=("end",), select=("o",),)This maps:
nto move downpto move upf fto jump to the first itemendto jump to the last itemoto select the current item
Listen To Actions
Section titled “Listen To Actions”Use ItemActionMessage when the app needs semantic item actions.
from lazy_cuh.widgets import ItemActionMessage, NavigableAction
def on_item_action_message(self, message: ItemActionMessage) -> None: if message.action == NavigableAction.SELECT: self.open_item(message.item_id)ItemSelectedMessage is still emitted for selection compatibility, but
ItemActionMessage is the better fit when an app wants one event shape for
select, expand, collapse, and toggle.
Key Specs And Aliases
Section titled “Key Specs And Aliases”Action bindings may use key specs for configurable leader-style keys. Resolution
and display are separate: KeyAliasMap expands a named leader token for input
handling, while KeyDisplayMap controls how the same binding appears in
keybars and help text.
import lazy_cuh as lc
actions = lc.inputs.ActionMap( ( lc.inputs.ActionBinding.from_key_spec( "<leader> h", lc.inputs.ActionId.SELECT, label="Pane left", visibility=lc.inputs.HintVisibility.COMPACT, ), ))
aliases = lc.inputs.KeyAliasMap.from_mapping({"leader": ("z",)})key_display = lc.inputs.KeyDisplayMap(aliases=aliases)spec = lc.keybar.from_actions(actions, key_display=key_display)That keybar renders Pane left: z h. Without a configured display map, the
same binding renders symbolically as Pane left: <leader> h.
When multiple keys mean the same thing, keep them on one binding with
ActionBinding.from_keys(...). That produces one help row such as
Left: h/left instead of duplicate rows for the same action.
Count Prefixes Are Scoped
Section titled “Count Prefixes Are Scoped”Count prefixes are opt-in. The framework does not reserve number keys globally.
Use VIM_NAVIGATION_KEYS only for the scopes that should treat leading digits
as counts, and use SIMPLE_KEYS where bare numbers should remain normal
bindings.
import lazy_cuh as lc
registry = lc.inputs.BindingRegistry( bindings=( lc.inputs.ScopedBinding( lc.inputs.ActionBinding.from_key("1", lc.inputs.ActionId.SELECT), context=lc.inputs.BindingContext(panel="tabs"), profile=lc.inputs.SIMPLE_KEYS, ), lc.inputs.ScopedBinding( lc.inputs.ActionBinding.from_key("j", lc.inputs.ActionId.SELECT), context=lc.inputs.BindingContext(widget="tree"), profile=lc.inputs.VIM_NAVIGATION_KEYS, ), ))diagnostics = registry.validate()With VIM_NAVIGATION_KEYS, a bare 1 binding reports a warning because it may
conflict with count input such as 10j. Leader sequences such as z 1 are
still valid because the digit is no longer a bare leading count.
Validate Binding Registries
Section titled “Validate Binding Registries”Validation is explicit. The framework does not automatically validate every
registry during app startup. Run BindingRegistry.validate() in tests, CI, or a
development-only startup check, then decide whether warnings should fail your
app.
diagnostics = registry.validate()for line in lc.inputs.format_binding_diagnostics(diagnostics): print(line)Diagnostics include duplicate bindings, global/local override conflicts, ambiguous sequence prefixes, unknown symbolic leader tokens, and bare digit bindings inside count-enabled scopes.
Use collision_policy=CollisionPolicy.WARN when duplicate/override/prefix
diagnostics should be warnings instead of errors. Use allow_override=True on a
local ScopedBinding when a local key intentionally takes over a global key.
Use CollisionPolicy.ALLOW_OVERRIDE only when that is the desired default for
the whole registry.
Keep Domain Meaning Outside Widgets
Section titled “Keep Domain Meaning Outside Widgets”The widget keymap decides how to navigate and which UI action happened. It does not decide what selecting an item means in your app. App controllers should translate item actions into commands when side effects are needed.