From 4dacaa265d649fffd85da4f616aa622762656946 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Wed, 2 Sep 2026 22:59:16 -0700 Subject: [PATCH] refactor(hermes_cli): sessions_cmd_browse _clip helper, hoisted invariants --- hermes_cli/sessions_cmd_browse.py | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/hermes_cli/sessions_cmd_browse.py b/hermes_cli/sessions_cmd_browse.py index af092177df..688d39dc42 100644 --- a/hermes_cli/sessions_cmd_browse.py +++ b/hermes_cli/sessions_cmd_browse.py @@ -28,6 +28,10 @@ def _label(s: dict) -> str: return (s.get("title") or "").strip() or (s.get("preview") or "").strip() or s["id"] +def _clip(text: str, n: int) -> str: + return text if len(text) <= n else text[: n - 3] + "..." + + def _msgs_str(s: dict) -> str: msgs = s.get("message_count") return str(msgs) if isinstance(msgs, int) else "-" @@ -72,8 +76,7 @@ class _CursesBrowser: self.filtered = list(sessions) def _pair(self, n, fallback=0): - c = self.curses - return c.color_pair(n) if c.has_colors() else fallback + return self.curses.color_pair(n) if self.curses.has_colors() else fallback def _status_attr(self, status): pair = {"complete": 1, "interrupted": 2, "error": 5, "empty": 4}.get(status or "") @@ -113,16 +116,15 @@ class _CursesBrowser: self.scroll = self.cursor elif self.cursor >= self.scroll + visible_rows: self.scroll = self.cursor - visible_rows + 1 + tag_x = 3 + max(20, (max_x - 3) - _FIXED_COLS) + 2 for draw_i, i in enumerate(range(self.scroll, min(len(filtered), self.scroll + visible_rows))): y = draw_i + 3 if y >= max_y - 1: break - s = filtered[i] - selected = i == self.cursor + s, selected = filtered[i], i == self.cursor row = (" → " if selected else " ") + _format_row(s, max_x - 3) try: stdscr.addnstr(y, 0, row, max_x - 1, c.A_BOLD | self._pair(1) if selected else c.A_NORMAL) - tag_x = 3 + max(20, (max_x - 3) - _FIXED_COLS) + 2 if not selected and tag_x + 5 < max_x - 1: # recolor the status tag in place status = s.get("_status") stdscr.addnstr(y, tag_x, f"{_session_status_tag(status):<5}", 5, self._status_attr(status)) @@ -130,10 +132,8 @@ class _CursesBrowser: pass footer_attr = self._pair(4, c.A_DIM) if self.confirm_delete is not None: - label = _label(self.confirm_delete) - if len(label) > 40: - label = label[:37] + "..." - footer, footer_attr = f" Delete session '{label}'? [y/N]", c.A_BOLD | self._pair(5) + footer = f" Delete session '{_clip(_label(self.confirm_delete), 40)}'? [y/N]" + footer_attr = c.A_BOLD | self._pair(5) elif self.flash: footer = f" {self.flash}" self.flash = "" @@ -193,9 +193,8 @@ class _CursesBrowser: c.start_color() c.use_default_colors() # 1 selected, 2 header, 3 search, 4 dim, 5 error/delete - for n, color in enumerate( - (c.COLOR_GREEN, c.COLOR_YELLOW, c.COLOR_CYAN, 8 if c.COLORS > 8 else c.COLOR_WHITE, c.COLOR_RED), 1 - ): + palette = (c.COLOR_GREEN, c.COLOR_YELLOW, c.COLOR_CYAN, 8 if c.COLORS > 8 else c.COLOR_WHITE, c.COLOR_RED) + for n, color in enumerate(palette, 1): c.init_pair(n, color, -1) while True: stdscr.clear() @@ -218,13 +217,9 @@ def _fallback_picker(sessions: list) -> Optional[str]: """Numbered list (Windows without curses, etc.). Same columns, no delete.""" print("\n Browse sessions (enter number to resume, q to cancel)\n") for i, s in enumerate(sessions): - label = _label(s) - if len(label) > 50: - label = label[:47] + "..." print( - f" {i + 1:>3}. {label:<50} {_session_status_tag(s.get('_status')):<5} " - f"{_msgs_str(s):>5} {_relative_time(s.get('last_active')):<10} " - f"{s.get('source', '')[:6]}" + f" {i + 1:>3}. {_clip(_label(s), 50):<50} {_session_status_tag(s.get('_status')):<5} " + f"{_msgs_str(s):>5} {_relative_time(s.get('last_active')):<10} {s.get('source', '')[:6]}" ) while True: try: