Navigable Content
Navigable content is any UI surface where the cursor moves over semantic items. Lists and trees are the first adapters, but the concept also applies to future option lists, search results, pickers, and other item-oriented views.
The important distinction is still:
- an item is the semantic object the user acts on
- a row is a rendered terminal line
Navigation moves by item. If an item wraps to multiple rows, j still moves to
the next item.
Responsibilities
Section titled “Responsibilities”The current navigable layer is split like this:
ListViewModelandTreeViewModelrender pure item models into lines.ListNavigationStatestores vim-like count and pendinggstate.NavigableKeymapdefines which key names mean move/select actions.NavigableInputResolverturns keys into pureNavigationCommandvalues.NavigableKeyHandleradapts resolved commands to Textual cursor callbacks.ItemActionMessagereports semantic item actions upward.
NavigableKeyHandler is widget-layer glue. It is not domain state and it does
not execute app commands.
Default Keys
Section titled “Default Keys”The low-level NavigableKeymap supports vim-like movement with arrow-key
aliases:
- down:
j,down - up:
k,up - first:
g g - last:
G - half page down/up:
ctrl+d,ctrl+u - select:
enter,space - counts:
2j,10G, and similar
Widget defaults go through lc.presets.navigation.item(), which currently
aliases the simpler lazygit() preset and disables count prefixes. Use
lc.presets.navigation.lazy_vim() for surfaces that should accept counts.
Tree widgets also use the navigation preset for tree-specific actions:
- toggle:
e - expand:
l,right - collapse:
h,left
Apps may provide a different keymap per widget, call set_navigation(...) at
runtime, or use NavigableInputResolver directly when they want to handle item
navigation outside the built-in widgets. Counts are part of this keymap for
now; broader app-level count policies still live in the input layer.
resolve_command(...) is the preferred pure API. It returns:
PENDINGfor partial input such as a count or first-key prefixMOVEwith a delta for relative movement such as5jSET_CURSORwith an absolute item index forgg,G, or3GSELECTNONE
resolve(...) still returns the older NavigableInput projection for
compatibility.
Action Messages
Section titled “Action Messages”Navigable widgets emit typed action messages:
ItemActionMessage(action=NavigableAction.SELECT, item_id="profile")Current actions are:
SELECTTOGGLEEXPANDCOLLAPSE
ItemSelectedMessage still exists for compatibility and convenience, but
ItemActionMessage is the more general event for app/controller integration.
Current Adapters
Section titled “Current Adapters”ListViewWidget emits SELECT when the current item is selected.
TreeViewWidget emits:
SELECTfor selectionTOGGLEforeEXPANDforl,rightCOLLAPSEforh,left
Tree expand/collapse is still widget-handled because it updates the local
TreeViewModel. Apps can still listen to the action messages if those actions
also need domain-side effects.