From 352edde49296ee0118d5d430c13e75a4b0eeea91 Mon Sep 17 00:00:00 2001 From: "n loewen (aider)" Date: Sat, 7 Jun 2025 23:48:25 +0100 Subject: [PATCH] feat: Add sidebar toggle with "s" key press --- gtm2.py | 105 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 35 deletions(-) diff --git a/gtm2.py b/gtm2.py index 4357737..c2d71ce 100755 --- a/gtm2.py +++ b/gtm2.py @@ -102,6 +102,7 @@ class AppState: self.show_additions = show_add self.show_deletions = show_del self.enable_mouse = mouse + self.show_sidebar = True self.commits = get_commits(filename) self.file_lines = [] @@ -136,6 +137,12 @@ class AppState: curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION) else: curses.mousemask(0) + + def toggle_sidebar(self): + self.show_sidebar = not self.show_sidebar + # When hiding sidebar, focus should be on right pane + if not self.show_sidebar: + self.focus = "right" def move_commit_selection(self, delta): new_idx = self.selected_commit_idx + delta @@ -203,6 +210,9 @@ class AppState: # --- Rendering Functions (View) --- def draw_left_pane(stdscr, state): + if not state.show_sidebar: + return + if state.selected_commit_idx < state.left_scroll_offset: state.left_scroll_offset = state.selected_commit_idx elif state.selected_commit_idx >= state.left_scroll_offset + state.height - 2: @@ -218,7 +228,9 @@ def draw_left_pane(stdscr, state): stdscr.attroff(curses.A_REVERSE) def draw_right_pane(stdscr, state): - right_width = state.width - state.divider_col - 3 + # If sidebar is hidden, right pane starts at column 0 + right_start = 0 if not state.show_sidebar else state.divider_col + 2 + right_width = state.width - right_start - 1 max_scroll = max(0, len(state.file_lines) - (state.height - 2)) state.right_scroll_offset = min(state.right_scroll_offset, max_scroll) @@ -257,22 +269,25 @@ def draw_right_pane(stdscr, state): content = line_info['content'] if line_type == 'added': - stdscr.addstr(display_row, state.divider_col + 2, "+ ", curses.color_pair(3)) - stdscr.addnstr(display_row, state.divider_col + 4, content, right_width - 2, curses.color_pair(3)) + stdscr.addstr(display_row, right_start, "+ ", curses.color_pair(3)) + stdscr.addnstr(display_row, right_start + 2, content, right_width - 2, curses.color_pair(3)) elif line_type == 'deleted': - stdscr.addstr(display_row, state.divider_col + 2, "- ", curses.color_pair(4)) - stdscr.addnstr(display_row, state.divider_col + 4, content, right_width - 2, curses.color_pair(4)) + stdscr.addstr(display_row, right_start, "- ", curses.color_pair(4)) + stdscr.addnstr(display_row, right_start + 2, content, right_width - 2, curses.color_pair(4)) else: if state.show_whole_diff or state.show_additions or state.show_deletions: - stdscr.addstr(display_row, state.divider_col + 2, " ") - stdscr.addnstr(display_row, state.divider_col + 4, content, right_width - 2) + stdscr.addstr(display_row, right_start, " ") + stdscr.addnstr(display_row, right_start + 2, content, right_width - 2) else: # No diff mode, so don't add the margin padding - stdscr.addnstr(display_row, state.divider_col + 2, content, right_width) + stdscr.addnstr(display_row, right_start, content, right_width) display_row += 1 def draw_divider(stdscr, state): + if not state.show_sidebar: + return + divider_char = "║" if state.dragging_divider else "│" for y in range(state.height - 1): # Don't draw through the commit message bar try: @@ -368,24 +383,43 @@ def draw_status_bars(stdscr, state): left_attr = curses.color_pair(1) if state.focus == "left" else curses.color_pair(2) right_attr = curses.color_pair(1) if state.focus == "right" else curses.color_pair(2) - # Fill the original status bar with spaces - for x in range(state.divider_col): + if state.show_sidebar: + # Fill the original status bar with spaces + for x in range(state.divider_col): + try: + stdscr.addch(state.height - 2, x, ' ', left_attr) + except curses.error: + pass + + # Add percentage indicators on left side of original status bar try: - stdscr.addch(state.height - 2, x, ' ', left_attr) + stdscr.addstr(state.height - 2, 1, left_status, left_attr) except curses.error: pass - for x in range(state.divider_col + 1, state.width - 1): + + # Draw divider in status bar with left and right colors try: - stdscr.addch(state.height - 2, x, ' ', right_attr) + # Use the half block character "▐" which can show both colors + # First draw with left side color + stdscr.addch(state.height - 2, state.divider_col, "▐", left_attr) except curses.error: pass + + # Fill right side of status bar + for x in range(state.divider_col + 1, state.width - 1): + try: + stdscr.addch(state.height - 2, x, ' ', right_attr) + except curses.error: + pass + else: + # When sidebar is hidden, fill the entire status bar with right pane color + for x in range(state.width - 1): + try: + stdscr.addch(state.height - 2, x, ' ', right_attr) + except curses.error: + pass - # Add percentage indicators on left and right sides of original status bar - try: - stdscr.addstr(state.height - 2, 1, left_status, left_attr) - except curses.error: - pass - + # Add right percentage indicator try: right_x = state.width - len(right_status) - 1 if right_x >= 0: @@ -393,14 +427,6 @@ def draw_status_bars(stdscr, state): except curses.error: pass - # Draw divider in status bar with left and right colors - try: - # Use the half block character "▐" which can show both colors - # First draw with left side color - stdscr.addch(state.height - 2, state.divider_col, "▐", left_attr) - except curses.error: - pass - # Draw new full-width status bar with commit message below the original status bars status_attr = curses.color_pair(5) # Color pair for commit message bar @@ -503,12 +529,15 @@ def handle_mouse_input(stdscr, state): # Handle mouse button press if bstate & curses.BUTTON1_PRESSED: - # Check if clicking near divider - if abs(mx - state.divider_col) <= 1: + # Check if clicking near divider (only if sidebar is visible) + if state.show_sidebar and abs(mx - state.divider_col) <= 1: state.dragging_divider = True else: - # Switch panes immediately on click - state.focus = "left" if mx < state.divider_col else "right" + # Switch panes immediately on click (only if sidebar is visible) + if state.show_sidebar: + state.focus = "left" if mx < state.divider_col else "right" + else: + state.focus = "right" # When sidebar is hidden, focus is always right # Also start a potential selection (in case this becomes a drag) state.is_selecting = True @@ -534,11 +563,14 @@ def handle_mouse_input(stdscr, state): if (state.click_position and abs(state.click_position[0] - mx) <= 2 and abs(state.click_position[1] - my) <= 2): - # This was a click, so switch panes - state.focus = "left" if mx < state.divider_col else "right" + # This was a click, so switch panes (only if sidebar is visible) + if state.show_sidebar: + state.focus = "left" if mx < state.divider_col else "right" + else: + state.focus = "right" # When sidebar is hidden, focus is always right # If clicking in the left pane on a commit entry, select that commit - if mx < state.divider_col and my < len(state.commits) - state.left_scroll_offset: + if state.show_sidebar and mx < state.divider_col and my < len(state.commits) - state.left_scroll_offset: new_commit_idx = my + state.left_scroll_offset if 0 <= new_commit_idx < len(state.commits): state.selected_commit_idx = new_commit_idx @@ -579,8 +611,11 @@ def handle_keyboard_input(key, state): state.should_exit = True elif key == ord('m'): state.toggle_mouse() + elif key == ord('s'): + state.toggle_sidebar() elif key in [curses.KEY_LEFT, ord('h')]: - state.focus = "left" + if state.show_sidebar: + state.focus = "left" elif key in [curses.KEY_RIGHT, ord('l')]: state.focus = "right"