feat: Add sidebar toggle with "s" key press

This commit is contained in:
n loewen (aider) 2025-06-07 23:48:25 +01:00
parent a73213a88b
commit 352edde492
1 changed files with 70 additions and 35 deletions

105
gtm2.py
View File

@ -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"