Source code for simvx.core.ui.command_line

"""CommandLine: a single-line text field that remembers the commands entered into it."""

from __future__ import annotations

from ..decorators import on_gui_input
from ..descriptors import Property
from ..input.controls import Key
from .widgets import TextEdit

__all__ = ["CommandLine"]


[docs] class CommandLine(TextEdit): """A single-line command entry with history, the input line of a console or a REPL. Enter submits the line through ``text_submitted``, empty or not, ends the edit session as :class:`TextEdit` does (``editing_finished`` when the line changed), records a non-empty line in :attr:`history` and clears the field for the next command. Up walks back through earlier commands and Down forward again, ending on the line that was being typed when Up was first pressed. Both repeat while held, and the line keeps them even at either end of the history, so an arrow typed into it never moves focus or reaches a game. Example:: line = CommandLine(placeholder="Enter command...") line.text_submitted.connect(run_command) """ max_history = Property(100, range=(1, 10000), hint="How many commands Up and Down can recall") def __init__(self, text: str = "", placeholder: str = "", **kwargs): super().__init__(text, placeholder, **kwargs) self._history: list[str] = [] # Where Up and Down have walked to in the history; -1 is the line being typed. self._recall = -1 self._draft = ""
[docs] @property def history(self) -> tuple[str, ...]: """The commands entered, oldest first: at most ``max_history`` of them.""" return tuple(self._history)
@on_gui_input(Key.ENTER) def _submit(self, event) -> bool: command = self.text if command: self._history.append(command) del self._history[: -self.max_history] self._recall = -1 self._draft = "" self.text_submitted.emit(command) self._commit() self._show("") self._snapshot_committed() return True @on_gui_input(Key.UP, repeat=True) def _older(self, event) -> bool: if self._history: if self._recall == -1: self._draft = self.text self._recall = len(self._history) - 1 elif self._recall > 0: self._recall -= 1 self._show(self._history[self._recall]) return True @on_gui_input(Key.DOWN, repeat=True) def _newer(self, event) -> bool: if self._recall != -1: if self._recall < len(self._history) - 1: self._recall += 1 self._show(self._history[self._recall]) else: self._recall = -1 self._show(self._draft) return True def _show(self, text: str) -> None: """Put *text* in the field with the caret at its end.""" if text != self.text: self.text = text self.text_changed.emit(text) self.cursor_pos = len(text) self.queue_redraw()