Files
Autoparts-DB/console/core/navigation.py
consultoria-as ceacab789b feat(console): add core framework - keybindings, navigation, screen base
Add the three core modules that all screens depend on:
- keybindings.py: Key constants (curses codes) and KeyBindings registry
- navigation.py: Stack-based screen navigation with breadcrumbs
- screens.py: Screen base class with on_enter/on_key/render lifecycle

Includes 31 tests covering all public APIs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 01:38:02 +00:00

61 lines
2.0 KiB
Python

"""
Screen-stack navigation for the console UI.
Navigation maintains a stack of ``(screen_name, context, label)`` entries.
Screens push onto the stack when the user drills into a sub-view and pop
when they press Escape / Backspace to go back.
"""
class Navigation:
"""A simple stack-based navigator.
Each entry is a tuple ``(screen_name, context, label)`` where
*screen_name* identifies which screen to display, *context* carries
any data the screen needs, and *label* is the human-readable text
shown in the breadcrumb trail.
"""
def __init__(self):
self._stack: list[tuple[str, object, str]] = []
def push(self, screen_name: str, context=None, label: str | None = None) -> None:
"""Push a new screen onto the stack.
If *label* is ``None`` the *screen_name* is used as fallback in
the breadcrumb.
"""
self._stack.append((screen_name, context, label if label is not None else screen_name))
def pop(self) -> tuple[str, object] | None:
"""Remove and return the top entry as ``(screen_name, context)``.
Returns ``None`` if the stack is empty.
"""
if not self._stack:
return None
screen_name, context, _label = self._stack.pop()
return (screen_name, context)
def current(self) -> tuple[str, object] | None:
"""Return the top entry as ``(screen_name, context)`` without removing it.
Returns ``None`` if the stack is empty.
"""
if not self._stack:
return None
screen_name, context, _label = self._stack[-1]
return (screen_name, context)
def breadcrumb(self) -> list[str]:
"""Return the list of labels from bottom to top of the stack."""
return [label for _name, _ctx, label in self._stack]
def clear(self) -> None:
"""Remove all entries from the stack."""
self._stack.clear()
def depth(self) -> int:
"""Return the number of entries on the stack."""
return len(self._stack)