diff --git a/src/claudedo/console.py b/src/claudedo/console.py index e13d155..2a70987 100644 --- a/src/claudedo/console.py +++ b/src/claudedo/console.py @@ -18,6 +18,7 @@ _COLORS = { "red": "\033[31m", "yellow": "\033[33m", "cyan": "\033[36m", + "blue": "\033[34m", "dim": "\033[2m", "bold": "\033[1m", } @@ -45,6 +46,11 @@ class Console: return text return f"{_COLORS[color]}{text}{RESET}" + def paint(self, text: str, color: str | None) -> str: + """public colorizer for pre-coloring a fragment of a message (e.g. a command + word) before passing it to emit() with color=None""" + return self._paint(text, color) + def emit(self, prefix: str, message: str, color: str | None = None) -> None: """print one line: ``HH:MM:SS [prefix] message`` (message optionally colored)""" line = f"{self._stamp()} {self._paint(f'[{prefix}]', 'dim')} {self._paint(message, color)}" diff --git a/src/claudedo/daemon.py b/src/claudedo/daemon.py index 0475c84..8450156 100644 --- a/src/claudedo/daemon.py +++ b/src/claudedo/daemon.py @@ -178,27 +178,30 @@ class Daemon: self._console.emit(VOICE, f'heard "{transcript}" -> {self._describe(action)} {self._timing()}', "green") + def blue(s): + return self._console.paint(s, "blue") if action.name == "mode": new_mode = str(action.arg) if new_mode != self.mode: self.mode = new_mode - self._console.emit(SYSTEM, f"mode -> {new_mode}", "cyan") + self._console.emit(SYSTEM, f"{blue('mode')} -> {new_mode}") self._refresh_state() return if action.name == "set": session = target.set_target(str(action.arg)) self._pending.pop(session, None) - self._console.emit(SYSTEM, f"set sticky -> {session}", "cyan") + self._console.emit(SYSTEM, f"{blue('set sticky')} -> {session}") self._refresh_state() return if action.name == "unset": target.unset_target() - self._console.emit(SYSTEM, "unset (cleared)", "cyan") + self._console.emit(SYSTEM, f"{blue('unset')} (cleared)") self._refresh_state() return if action.name == "list": sessions = target.list_sessions() - self._console.emit(SYSTEM, "list -> " + (", ".join(sessions) if sessions else "(none running)")) + self._console.emit(SYSTEM, f"{blue('list')} -> " + + (", ".join(sessions) if sessions else "(none running)")) return if action.name == "commands": for usage, desc in grammar.command_menu(): @@ -244,13 +247,11 @@ class Daemon: self._console.emit(session, f"{reason} -> space x{n}", "green") return if name == "backspace": - have = self._pending.get(session, 0) - n = min(int(action.arg), have) + n = int(action.arg) if n: - inject.perform(session, grammar.Action("backspace", n)) - self._pending[session] = have - n - self._console.emit(session, f"{reason} -> backspace x{n}" - + ("" if n == int(action.arg) else " (capped at boundary)"), "green") + inject.perform(session, action) + self._pending[session] = max(0, self._pending.get(session, 0) - n) + self._console.emit(session, f"{reason} -> backspace x{n}", "green") return if name == "erase": n = self._pending.get(session, 0)