feat: Add second status bar with commit details and resizable height
This commit is contained in:
parent
6c319c1570
commit
c945c89b74
217
gtm
217
gtm
|
|
@ -24,6 +24,36 @@ def get_commits(filename):
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
return result.stdout.splitlines()
|
return result.stdout.splitlines()
|
||||||
|
|
||||||
|
def get_commit_details(commit_hash):
|
||||||
|
"""Get detailed information about a specific commit."""
|
||||||
|
# Get commit author
|
||||||
|
author_cmd = ['git', 'show', '-s', '--format=%an <%ae>', commit_hash]
|
||||||
|
author_result = subprocess.run(author_cmd, capture_output=True, text=True)
|
||||||
|
author = author_result.stdout.strip()
|
||||||
|
|
||||||
|
# Get branch information
|
||||||
|
branch_cmd = ['git', 'branch', '--contains', commit_hash]
|
||||||
|
branch_result = subprocess.run(branch_cmd, capture_output=True, text=True)
|
||||||
|
branches = [b.strip() for b in branch_result.stdout.splitlines()]
|
||||||
|
|
||||||
|
# Find the current branch (marked with *)
|
||||||
|
current_branch = "detached"
|
||||||
|
for branch in branches:
|
||||||
|
if branch.startswith('*'):
|
||||||
|
current_branch = branch[1:].strip()
|
||||||
|
break
|
||||||
|
|
||||||
|
# Get full commit message
|
||||||
|
message_cmd = ['git', 'show', '-s', '--format=%B', commit_hash]
|
||||||
|
message_result = subprocess.run(message_cmd, capture_output=True, text=True)
|
||||||
|
message = message_result.stdout.strip()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'author': author,
|
||||||
|
'branch': current_branch,
|
||||||
|
'message': message
|
||||||
|
}
|
||||||
|
|
||||||
def get_file_at_commit(commit_hash, filename):
|
def get_file_at_commit(commit_hash, filename):
|
||||||
cmd = ['git', 'show', f'{commit_hash}:{filename}']
|
cmd = ['git', 'show', f'{commit_hash}:{filename}']
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
|
|
@ -148,6 +178,16 @@ class AppState:
|
||||||
# Help popup
|
# Help popup
|
||||||
show_help: bool = False
|
show_help: bool = False
|
||||||
|
|
||||||
|
# Commit details
|
||||||
|
commit_hash: str = ""
|
||||||
|
commit_message: str = ""
|
||||||
|
commit_author: str = ""
|
||||||
|
commit_branch: str = ""
|
||||||
|
|
||||||
|
# Status bar settings
|
||||||
|
status_bar_height: int = 2 # Default height for the status bar (2 lines)
|
||||||
|
dragging_status_bar: bool = False # Flag to track if user is resizing the status bar
|
||||||
|
|
||||||
# --- Actions (Controller) ---
|
# --- Actions (Controller) ---
|
||||||
|
|
||||||
def calculate_change_blocks(state: AppState) -> AppState:
|
def calculate_change_blocks(state: AppState) -> AppState:
|
||||||
|
|
@ -202,7 +242,7 @@ def load_commit_content(state: AppState) -> AppState:
|
||||||
reference_line = None
|
reference_line = None
|
||||||
scroll_percentage = 0
|
scroll_percentage = 0
|
||||||
if len(state.file_lines) > 0:
|
if len(state.file_lines) > 0:
|
||||||
max_scroll_old = max(0, len(state.file_lines) - (state.height - 1))
|
max_scroll_old = max(0, len(state.file_lines) - (state.height - state.status_bar_height))
|
||||||
if max_scroll_old > 0:
|
if max_scroll_old > 0:
|
||||||
scroll_percentage = state.right_scroll_offset / max_scroll_old
|
scroll_percentage = state.right_scroll_offset / max_scroll_old
|
||||||
if state.right_scroll_offset < len(state.file_lines):
|
if state.right_scroll_offset < len(state.file_lines):
|
||||||
|
|
@ -220,7 +260,15 @@ def load_commit_content(state: AppState) -> AppState:
|
||||||
else:
|
else:
|
||||||
added_lines, deleted_lines = [], []
|
added_lines, deleted_lines = [], []
|
||||||
|
|
||||||
max_scroll_new = max(0, len(file_lines) - (state.height - 1))
|
# Get commit details
|
||||||
|
commit_details = get_commit_details(commit_hash)
|
||||||
|
|
||||||
|
# Get commit message from the commit line
|
||||||
|
commit_line = state.commits[state.selected_commit_idx]
|
||||||
|
parts = commit_line.split(' ', 3) # Split into hash, date, time, message
|
||||||
|
short_message = parts[3] if len(parts) >= 4 else ""
|
||||||
|
|
||||||
|
max_scroll_new = max(0, len(file_lines) - (state.height - state.status_bar_height))
|
||||||
right_scroll_offset = state.right_scroll_offset
|
right_scroll_offset = state.right_scroll_offset
|
||||||
if reference_line:
|
if reference_line:
|
||||||
matching_line_idx = find_best_matching_line(reference_line, file_lines, 1000)
|
matching_line_idx = find_best_matching_line(reference_line, file_lines, 1000)
|
||||||
|
|
@ -237,7 +285,11 @@ def load_commit_content(state: AppState) -> AppState:
|
||||||
file_lines=file_lines,
|
file_lines=file_lines,
|
||||||
added_lines=added_lines,
|
added_lines=added_lines,
|
||||||
deleted_lines=deleted_lines,
|
deleted_lines=deleted_lines,
|
||||||
right_scroll_offset=right_scroll_offset
|
right_scroll_offset=right_scroll_offset,
|
||||||
|
commit_hash=commit_hash,
|
||||||
|
commit_message=commit_details['message'],
|
||||||
|
commit_author=commit_details['author'],
|
||||||
|
commit_branch=commit_details['branch']
|
||||||
)
|
)
|
||||||
|
|
||||||
# Calculate change blocks for navigation
|
# Calculate change blocks for navigation
|
||||||
|
|
@ -291,10 +343,10 @@ def draw_left_pane(stdscr, state):
|
||||||
|
|
||||||
if state.selected_commit_idx < state.left_scroll_offset:
|
if state.selected_commit_idx < state.left_scroll_offset:
|
||||||
state.left_scroll_offset = state.selected_commit_idx
|
state.left_scroll_offset = state.selected_commit_idx
|
||||||
elif state.selected_commit_idx >= state.left_scroll_offset + state.height - 1:
|
elif state.selected_commit_idx >= state.left_scroll_offset + state.height - state.status_bar_height:
|
||||||
state.left_scroll_offset = state.selected_commit_idx - (state.height - 2)
|
state.left_scroll_offset = state.selected_commit_idx - (state.height - state.status_bar_height - 1)
|
||||||
|
|
||||||
visible_commits = state.commits[state.left_scroll_offset:state.left_scroll_offset + state.height - 1]
|
visible_commits = state.commits[state.left_scroll_offset:state.left_scroll_offset + state.height - state.status_bar_height]
|
||||||
for i, line in enumerate(visible_commits):
|
for i, line in enumerate(visible_commits):
|
||||||
display_index = i + state.left_scroll_offset
|
display_index = i + state.left_scroll_offset
|
||||||
if display_index == state.selected_commit_idx:
|
if display_index == state.selected_commit_idx:
|
||||||
|
|
@ -429,10 +481,10 @@ def draw_right_pane(stdscr, state):
|
||||||
|
|
||||||
right_width = state.width - right_start - 1
|
right_width = state.width - right_start - 1
|
||||||
|
|
||||||
max_scroll = max(0, len(state.file_lines) - (state.height - 1))
|
max_scroll = max(0, len(state.file_lines) - (state.height - state.status_bar_height))
|
||||||
state.right_scroll_offset = min(state.right_scroll_offset, max_scroll)
|
state.right_scroll_offset = min(state.right_scroll_offset, max_scroll)
|
||||||
|
|
||||||
visible_lines = state.file_lines[state.right_scroll_offset:state.right_scroll_offset + state.height - 1]
|
visible_lines = state.file_lines[state.right_scroll_offset:state.right_scroll_offset + state.height - state.status_bar_height]
|
||||||
|
|
||||||
display_lines = []
|
display_lines = []
|
||||||
deleted_line_map = {}
|
deleted_line_map = {}
|
||||||
|
|
@ -591,7 +643,7 @@ def draw_divider(stdscr, state):
|
||||||
return
|
return
|
||||||
|
|
||||||
divider_char = "║" if state.dragging_divider else "│"
|
divider_char = "║" if state.dragging_divider else "│"
|
||||||
for y in range(state.height - 1): # Don't draw through the status bar
|
for y in range(state.height - state.status_bar_height): # Don't draw through the status bars
|
||||||
try:
|
try:
|
||||||
stdscr.addch(y, state.divider_col, divider_char)
|
stdscr.addch(y, state.divider_col, divider_char)
|
||||||
except curses.error:
|
except curses.error:
|
||||||
|
|
@ -755,53 +807,51 @@ def draw_help_popup(stdscr, state):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def draw_status_bars(stdscr, state):
|
def draw_status_bars(stdscr, state):
|
||||||
# We'll use height-1 for the single status bar
|
# Calculate the position of the status bars
|
||||||
visible_height = state.height - 1
|
status_bar_start = state.height - state.status_bar_height
|
||||||
|
visible_height = status_bar_start
|
||||||
|
|
||||||
# If in search mode, draw the search input field instead of the normal status bar
|
# If in search mode, draw the search input field instead of the normal status bars
|
||||||
if state.search_mode:
|
if state.search_mode:
|
||||||
# Fill the status bar with spaces
|
# Fill the top status bar with spaces
|
||||||
for x in range(state.width - 1):
|
for x in range(state.width - 1):
|
||||||
try:
|
try:
|
||||||
stdscr.addch(state.height - 1, x, ' ')
|
stdscr.addch(status_bar_start, x, ' ')
|
||||||
except curses.error:
|
except curses.error:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Draw search prompt
|
# Draw search prompt
|
||||||
search_prompt = "Search: "
|
search_prompt = "Search: "
|
||||||
try:
|
try:
|
||||||
stdscr.addstr(state.height - 1, 0, search_prompt)
|
stdscr.addstr(status_bar_start, 0, search_prompt)
|
||||||
|
|
||||||
# Draw the search query
|
# Draw the search query
|
||||||
stdscr.addstr(state.height - 1, len(search_prompt), state.search_query)
|
stdscr.addstr(status_bar_start, len(search_prompt), state.search_query)
|
||||||
|
|
||||||
# Draw cursor at the end of the query
|
# Draw cursor at the end of the query
|
||||||
try:
|
try:
|
||||||
stdscr.move(state.height - 1, len(search_prompt) + len(state.search_query))
|
stdscr.move(status_bar_start, len(search_prompt) + len(state.search_query))
|
||||||
except curses.error:
|
except curses.error:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# If we have search results, show count
|
# If we have search results, show count
|
||||||
if state.search_matches:
|
if state.search_matches:
|
||||||
match_info = f" [{state.current_match_idx + 1}/{len(state.search_matches)}]"
|
match_info = f" [{state.current_match_idx + 1}/{len(state.search_matches)}]"
|
||||||
stdscr.addstr(state.height - 1, state.width - len(match_info) - 1, match_info)
|
stdscr.addstr(status_bar_start, state.width - len(match_info) - 1, match_info)
|
||||||
|
except curses.error:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Draw a blank second status bar
|
||||||
|
for x in range(state.width - 1):
|
||||||
|
try:
|
||||||
|
stdscr.addch(state.height - 1, x, ' ', curses.A_REVERSE)
|
||||||
except curses.error:
|
except curses.error:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Normal status bar (not in search mode)
|
# --- First status bar (top) ---
|
||||||
# Get commit message for the selected commit
|
# Add indicators to status bar
|
||||||
commit_message = ""
|
|
||||||
if state.commits and state.selected_commit_idx < len(state.commits):
|
|
||||||
# Format is now: hash date time message
|
|
||||||
# We need to split on more than just the first two spaces
|
|
||||||
commit_line = state.commits[state.selected_commit_idx]
|
|
||||||
parts = commit_line.split(' ', 3) # Split into hash, date, time, message
|
|
||||||
if len(parts) >= 4:
|
|
||||||
commit_message = parts[3]
|
|
||||||
|
|
||||||
# Add indicators to commit message
|
|
||||||
wrap_indicator = "" if state.wrap_lines else "[NW] "
|
wrap_indicator = "" if state.wrap_lines else "[NW] "
|
||||||
change_indicator = ""
|
change_indicator = ""
|
||||||
if state.change_blocks and state.current_change_idx != -1:
|
if state.change_blocks and state.current_change_idx != -1:
|
||||||
|
|
@ -811,7 +861,7 @@ def draw_status_bars(stdscr, state):
|
||||||
if state.search_matches:
|
if state.search_matches:
|
||||||
search_indicator = f"[Search {state.current_match_idx + 1}/{len(state.search_matches)}] "
|
search_indicator = f"[Search {state.current_match_idx + 1}/{len(state.search_matches)}] "
|
||||||
|
|
||||||
commit_message = wrap_indicator + change_indicator + search_indicator + commit_message
|
status_indicators = wrap_indicator + change_indicator + search_indicator
|
||||||
|
|
||||||
# Status bar percentages
|
# Status bar percentages
|
||||||
if len(state.file_lines) > 0:
|
if len(state.file_lines) > 0:
|
||||||
|
|
@ -833,10 +883,10 @@ def draw_status_bars(stdscr, state):
|
||||||
# Use terminal's default colors for the status bar
|
# Use terminal's default colors for the status bar
|
||||||
status_attr = curses.A_NORMAL # Use terminal's default colors
|
status_attr = curses.A_NORMAL # Use terminal's default colors
|
||||||
|
|
||||||
# Fill the status bar with spaces using reverse video
|
# Fill the top status bar with spaces using reverse video
|
||||||
for x in range(state.width - 1):
|
for x in range(state.width - 1):
|
||||||
try:
|
try:
|
||||||
stdscr.addch(state.height - 1, x, ' ', curses.A_REVERSE)
|
stdscr.addch(status_bar_start, x, ' ', curses.A_REVERSE)
|
||||||
except curses.error:
|
except curses.error:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -846,26 +896,23 @@ def draw_status_bars(stdscr, state):
|
||||||
# Use normal video if left pane is active (since status bar is already reverse)
|
# Use normal video if left pane is active (since status bar is already reverse)
|
||||||
left_attr = status_attr if state.focus == "left" else curses.A_REVERSE
|
left_attr = status_attr if state.focus == "left" else curses.A_REVERSE
|
||||||
# Add a space before and after the percentage with the same highlighting
|
# Add a space before and after the percentage with the same highlighting
|
||||||
stdscr.addstr(state.height - 1, 0, f" {left_status} ", left_attr)
|
stdscr.addstr(status_bar_start, 0, f" {left_status} ", left_attr)
|
||||||
except curses.error:
|
except curses.error:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Add commit message in the middle
|
# Add status indicators in the middle
|
||||||
if commit_message:
|
if status_indicators:
|
||||||
# Calculate available space
|
# Calculate available space
|
||||||
left_margin = len(left_status) + 3 if state.show_sidebar else 1 # +3 for the spaces around percentage
|
left_margin = len(left_status) + 3 if state.show_sidebar else 1 # +3 for the spaces around percentage
|
||||||
right_margin = len(right_status) + 3 # +3 for the spaces around percentage
|
right_margin = len(right_status) + 3 # +3 for the spaces around percentage
|
||||||
available_width = state.width - left_margin - right_margin
|
available_width = state.width - left_margin - right_margin
|
||||||
|
|
||||||
# Truncate message if needed
|
# Truncate if needed
|
||||||
if len(commit_message) > available_width:
|
if len(status_indicators) > available_width:
|
||||||
commit_message = commit_message[:available_width-3] + "..."
|
status_indicators = status_indicators[:available_width-3] + "..."
|
||||||
|
|
||||||
# Center the message in the available space
|
|
||||||
message_x = left_margin
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
stdscr.addstr(state.height - 1, message_x, commit_message, curses.A_REVERSE)
|
stdscr.addstr(status_bar_start, left_margin, status_indicators, curses.A_REVERSE)
|
||||||
except curses.error:
|
except curses.error:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -877,7 +924,61 @@ def draw_status_bars(stdscr, state):
|
||||||
if right_x >= 0:
|
if right_x >= 0:
|
||||||
# Use normal video if right pane is active (since status bar is already reverse)
|
# Use normal video if right pane is active (since status bar is already reverse)
|
||||||
right_attr = status_attr if state.focus == "right" else curses.A_REVERSE
|
right_attr = status_attr if state.focus == "right" else curses.A_REVERSE
|
||||||
stdscr.addstr(state.height - 1, right_x, padded_right_status, right_attr)
|
stdscr.addstr(status_bar_start, right_x, padded_right_status, right_attr)
|
||||||
|
except curses.error:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# --- Second status bar (bottom) ---
|
||||||
|
# Draw the commit details in the second status bar
|
||||||
|
|
||||||
|
# Fill the bottom status bar with spaces using reverse video
|
||||||
|
for x in range(state.width - 1):
|
||||||
|
try:
|
||||||
|
stdscr.addch(state.height - 1, x, ' ', curses.A_REVERSE)
|
||||||
|
except curses.error:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Draw the commit hash and message on the left
|
||||||
|
if state.commit_hash:
|
||||||
|
commit_info = f" {state.commit_hash} "
|
||||||
|
|
||||||
|
# Calculate available space for the commit message
|
||||||
|
author_branch_info = f" {state.commit_author} [{state.commit_branch}] "
|
||||||
|
available_width = state.width - len(commit_info) - len(author_branch_info) - 1
|
||||||
|
|
||||||
|
# Get the commit message (potentially multi-line)
|
||||||
|
commit_message = state.commit_message
|
||||||
|
|
||||||
|
# For multi-line messages, we'll show as many lines as we can fit in the status bar height
|
||||||
|
message_lines = commit_message.splitlines()
|
||||||
|
if not message_lines:
|
||||||
|
message_lines = [""]
|
||||||
|
|
||||||
|
# Show the first line in the status bar
|
||||||
|
display_message = message_lines[0]
|
||||||
|
|
||||||
|
# Truncate message if needed
|
||||||
|
if len(display_message) > available_width:
|
||||||
|
display_message = display_message[:available_width-3] + "..."
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Draw the commit hash with bold
|
||||||
|
stdscr.addstr(state.height - 1, 0, commit_info, curses.A_REVERSE | curses.A_BOLD)
|
||||||
|
|
||||||
|
# Draw the commit message
|
||||||
|
stdscr.addstr(state.height - 1, len(commit_info), display_message, curses.A_REVERSE)
|
||||||
|
|
||||||
|
# Draw the author and branch on the right
|
||||||
|
right_x = state.width - len(author_branch_info)
|
||||||
|
if right_x >= 0:
|
||||||
|
stdscr.addstr(state.height - 1, right_x, author_branch_info, curses.A_REVERSE)
|
||||||
|
except curses.error:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Draw a handle for resizing the status bar
|
||||||
|
try:
|
||||||
|
handle_char = "≡" if state.dragging_status_bar else "="
|
||||||
|
stdscr.addstr(status_bar_start, state.width // 2 - 1, handle_char * 3, curses.A_REVERSE | curses.A_BOLD)
|
||||||
except curses.error:
|
except curses.error:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -1014,15 +1115,37 @@ def copy_selection_to_clipboard(stdscr, state):
|
||||||
except (FileNotFoundError, subprocess.CalledProcessError):
|
except (FileNotFoundError, subprocess.CalledProcessError):
|
||||||
pass # Silently fail if no clipboard command is available
|
pass # Silently fail if no clipboard command is available
|
||||||
|
|
||||||
|
def update_status_bar_height(state: AppState, my: int) -> AppState:
|
||||||
|
"""Update the status bar height based on mouse position."""
|
||||||
|
# Calculate the minimum and maximum allowed heights
|
||||||
|
min_height = 2 # Minimum 2 lines for the status bar
|
||||||
|
max_height = min(10, state.height // 2) # Maximum 10 lines or half the screen
|
||||||
|
|
||||||
|
# Calculate the new height based on how far the user has dragged
|
||||||
|
status_bar_start = state.height - state.status_bar_height
|
||||||
|
drag_distance = status_bar_start - my
|
||||||
|
new_height = state.status_bar_height + drag_distance
|
||||||
|
|
||||||
|
# Clamp to allowed range
|
||||||
|
new_height = max(min_height, min(new_height, max_height))
|
||||||
|
|
||||||
|
return replace(state, status_bar_height=new_height)
|
||||||
|
|
||||||
def handle_mouse_input(stdscr, state: AppState) -> AppState:
|
def handle_mouse_input(stdscr, state: AppState) -> AppState:
|
||||||
try:
|
try:
|
||||||
_, mx, my, _, bstate = curses.getmouse()
|
_, mx, my, _, bstate = curses.getmouse()
|
||||||
state = replace(state, last_bstate=bstate, mouse_x=mx, mouse_y=my)
|
state = replace(state, last_bstate=bstate, mouse_x=mx, mouse_y=my)
|
||||||
|
|
||||||
|
# Status bar position
|
||||||
|
status_bar_start = state.height - state.status_bar_height
|
||||||
|
|
||||||
# Handle mouse button press
|
# Handle mouse button press
|
||||||
if bstate & curses.BUTTON1_PRESSED:
|
if bstate & curses.BUTTON1_PRESSED:
|
||||||
if state.show_sidebar and abs(mx - state.divider_col) <= 1:
|
if state.show_sidebar and abs(mx - state.divider_col) <= 1:
|
||||||
return replace(state, dragging_divider=True)
|
return replace(state, dragging_divider=True)
|
||||||
|
elif my == status_bar_start and abs(mx - (state.width // 2)) <= 2:
|
||||||
|
# Clicked on the status bar handle
|
||||||
|
return replace(state, dragging_status_bar=True)
|
||||||
else:
|
else:
|
||||||
focus = "right"
|
focus = "right"
|
||||||
if state.show_sidebar:
|
if state.show_sidebar:
|
||||||
|
|
@ -1039,6 +1162,8 @@ def handle_mouse_input(stdscr, state: AppState) -> AppState:
|
||||||
if bstate & curses.BUTTON1_RELEASED:
|
if bstate & curses.BUTTON1_RELEASED:
|
||||||
if state.dragging_divider:
|
if state.dragging_divider:
|
||||||
return replace(state, dragging_divider=False)
|
return replace(state, dragging_divider=False)
|
||||||
|
elif state.dragging_status_bar:
|
||||||
|
return replace(state, dragging_status_bar=False)
|
||||||
|
|
||||||
if state.is_selecting:
|
if state.is_selecting:
|
||||||
# Check if this was a click (press and release at same position)
|
# Check if this was a click (press and release at same position)
|
||||||
|
|
@ -1054,7 +1179,7 @@ def handle_mouse_input(stdscr, state: AppState) -> AppState:
|
||||||
new_state = replace(state, focus=focus)
|
new_state = replace(state, focus=focus)
|
||||||
|
|
||||||
# If clicking in the left pane on a commit entry, select that commit
|
# If clicking in the left pane on a commit entry, select that commit
|
||||||
if state.show_sidebar and mx < state.divider_col and my < min(state.height - 1, len(state.commits) - state.left_scroll_offset):
|
if state.show_sidebar and mx < state.divider_col and my < min(status_bar_start, len(state.commits) - state.left_scroll_offset):
|
||||||
new_commit_idx = my + state.left_scroll_offset
|
new_commit_idx = my + state.left_scroll_offset
|
||||||
if 0 <= new_commit_idx < len(state.commits):
|
if 0 <= new_commit_idx < len(state.commits):
|
||||||
new_state = replace(new_state, selected_commit_idx=new_commit_idx)
|
new_state = replace(new_state, selected_commit_idx=new_commit_idx)
|
||||||
|
|
@ -1073,6 +1198,8 @@ def handle_mouse_input(stdscr, state: AppState) -> AppState:
|
||||||
# Handle mouse movement during drag operations
|
# Handle mouse movement during drag operations
|
||||||
if state.dragging_divider:
|
if state.dragging_divider:
|
||||||
return update_divider(state, mx)
|
return update_divider(state, mx)
|
||||||
|
elif state.dragging_status_bar:
|
||||||
|
return update_status_bar_height(state, my)
|
||||||
elif state.is_selecting:
|
elif state.is_selecting:
|
||||||
return replace(state, selection_end_coord=(mx, my))
|
return replace(state, selection_end_coord=(mx, my))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue