refactor: Convert AppState to pure dataclass with functional state management
This commit is contained in:
parent
9406908d2f
commit
ddb1119bb5
322
gtm
322
gtm
|
|
@ -5,6 +5,8 @@ import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
|
from dataclasses import dataclass, field, replace
|
||||||
|
from typing import List, Optional, Tuple
|
||||||
|
|
||||||
VERSION = "2025-06-07.3"
|
VERSION = "2025-06-07.3"
|
||||||
|
|
||||||
|
|
@ -91,121 +93,129 @@ def get_diff_info(current_commit, prev_commit, filename):
|
||||||
i += 1
|
i += 1
|
||||||
return added_lines, deleted_lines
|
return added_lines, deleted_lines
|
||||||
|
|
||||||
# --- Application State Class ---
|
@dataclass
|
||||||
|
|
||||||
class AppState:
|
class AppState:
|
||||||
def __init__(self, filename, width, height, show_diff, show_add, show_del, mouse):
|
filename: str
|
||||||
self.filename = filename
|
width: int
|
||||||
self.width = width
|
height: int
|
||||||
self.height = height
|
show_whole_diff: bool
|
||||||
self.show_whole_diff = show_diff
|
show_additions: bool
|
||||||
self.show_additions = show_add
|
show_deletions: bool
|
||||||
self.show_deletions = show_del
|
enable_mouse: bool
|
||||||
self.enable_mouse = mouse
|
|
||||||
self.show_sidebar = True
|
|
||||||
|
|
||||||
self.commits = get_commits(filename)
|
show_sidebar: bool = True
|
||||||
self.file_lines = []
|
commits: List[str] = field(default_factory=list)
|
||||||
self.added_lines = []
|
file_lines: List[str] = field(default_factory=list)
|
||||||
self.deleted_lines = []
|
added_lines: List[Tuple[int, str]] = field(default_factory=list)
|
||||||
|
deleted_lines: List[Tuple[int, str]] = field(default_factory=list)
|
||||||
|
|
||||||
self.focus = "left"
|
focus: str = "left"
|
||||||
self.divider_col = 40
|
divider_col: int = 40
|
||||||
|
|
||||||
self.selected_commit_idx = 0
|
selected_commit_idx: int = 0
|
||||||
self.left_scroll_offset = 0
|
left_scroll_offset: int = 0
|
||||||
self.right_scroll_offset = 0
|
right_scroll_offset: int = 0
|
||||||
|
|
||||||
self.dragging_divider = False
|
dragging_divider: bool = False
|
||||||
self.should_exit = False
|
should_exit: bool = False
|
||||||
|
|
||||||
self.is_selecting = False
|
is_selecting: bool = False
|
||||||
self.selection_start_coord = None
|
selection_start_coord: Optional[Tuple[int, int]] = None
|
||||||
self.selection_end_coord = None
|
selection_end_coord: Optional[Tuple[int, int]] = None
|
||||||
self.click_position = None # Store click position to detect clicks vs. drags
|
click_position: Optional[Tuple[int, int]] = None
|
||||||
self.last_bstate = 0
|
last_bstate: int = 0
|
||||||
self.mouse_x = -1
|
mouse_x: int = -1
|
||||||
self.mouse_y = -1
|
mouse_y: int = -1
|
||||||
|
|
||||||
def update_dimensions(self, height, width):
|
# --- Actions (Controller) ---
|
||||||
self.height = height
|
|
||||||
self.width = width
|
|
||||||
|
|
||||||
def toggle_mouse(self):
|
def load_commit_content(state: AppState) -> AppState:
|
||||||
self.enable_mouse = not self.enable_mouse
|
if not state.commits:
|
||||||
if self.enable_mouse:
|
return state
|
||||||
curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION)
|
|
||||||
|
reference_line = None
|
||||||
|
scroll_percentage = 0
|
||||||
|
if len(state.file_lines) > 0:
|
||||||
|
max_scroll_old = max(0, len(state.file_lines) - (state.height - 1))
|
||||||
|
if max_scroll_old > 0:
|
||||||
|
scroll_percentage = state.right_scroll_offset / max_scroll_old
|
||||||
|
if state.right_scroll_offset < len(state.file_lines):
|
||||||
|
reference_line = state.file_lines[state.right_scroll_offset]
|
||||||
|
|
||||||
|
commit_hash = state.commits[state.selected_commit_idx].split()[0]
|
||||||
|
file_lines = get_file_at_commit(commit_hash, state.filename)
|
||||||
|
|
||||||
|
prev_commit_hash = None
|
||||||
|
if state.selected_commit_idx < len(state.commits) - 1:
|
||||||
|
prev_commit_hash = state.commits[state.selected_commit_idx + 1].split()[0]
|
||||||
|
|
||||||
|
if state.show_whole_diff or state.show_additions or state.show_deletions:
|
||||||
|
added_lines, deleted_lines = get_diff_info(commit_hash, prev_commit_hash, state.filename)
|
||||||
|
else:
|
||||||
|
added_lines, deleted_lines = [], []
|
||||||
|
|
||||||
|
max_scroll_new = max(0, len(file_lines) - (state.height - 1))
|
||||||
|
right_scroll_offset = state.right_scroll_offset
|
||||||
|
if reference_line:
|
||||||
|
matching_line_idx = find_best_matching_line(reference_line, file_lines, 1000)
|
||||||
|
if matching_line_idx is not None:
|
||||||
|
right_scroll_offset = matching_line_idx
|
||||||
else:
|
else:
|
||||||
curses.mousemask(0)
|
right_scroll_offset = int(scroll_percentage * max_scroll_new)
|
||||||
|
else:
|
||||||
|
right_scroll_offset = int(scroll_percentage * max_scroll_new)
|
||||||
|
|
||||||
def toggle_sidebar(self):
|
right_scroll_offset = max(0, min(right_scroll_offset, max_scroll_new))
|
||||||
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):
|
return replace(state,
|
||||||
new_idx = self.selected_commit_idx + delta
|
file_lines=file_lines,
|
||||||
if 0 <= new_idx < len(self.commits):
|
added_lines=added_lines,
|
||||||
self.selected_commit_idx = new_idx
|
deleted_lines=deleted_lines,
|
||||||
self.load_commit_content()
|
right_scroll_offset=right_scroll_offset
|
||||||
|
)
|
||||||
|
|
||||||
def page_commit_selection(self, direction):
|
def update_dimensions(state: AppState, height: int, width: int) -> AppState:
|
||||||
page_size = self.height - 1
|
return replace(state, height=height, width=width)
|
||||||
delta = page_size * direction
|
|
||||||
self.move_commit_selection(delta)
|
|
||||||
|
|
||||||
def scroll_right_pane(self, delta):
|
def toggle_mouse(state: AppState) -> AppState:
|
||||||
max_scroll = max(0, len(self.file_lines) - (self.height - 1))
|
return replace(state, enable_mouse=not state.enable_mouse)
|
||||||
new_offset = self.right_scroll_offset + delta
|
|
||||||
self.right_scroll_offset = max(0, min(new_offset, max_scroll))
|
|
||||||
|
|
||||||
def page_right_pane(self, direction):
|
def toggle_sidebar(state: AppState) -> AppState:
|
||||||
page_size = self.height - 1
|
new_show_sidebar = not state.show_sidebar
|
||||||
delta = page_size * direction
|
new_focus = state.focus
|
||||||
self.scroll_right_pane(delta)
|
if not new_show_sidebar:
|
||||||
|
new_focus = "right"
|
||||||
|
return replace(state, show_sidebar=new_show_sidebar, focus=new_focus)
|
||||||
|
|
||||||
def update_divider(self, mx):
|
def move_commit_selection(state: AppState, delta: int) -> AppState:
|
||||||
min_col = 10
|
new_idx = state.selected_commit_idx + delta
|
||||||
max_col = self.width - 20
|
if 0 <= new_idx < len(state.commits):
|
||||||
self.divider_col = max(min_col, min(mx, max_col))
|
new_state = replace(state, selected_commit_idx=new_idx)
|
||||||
|
return load_commit_content(new_state)
|
||||||
|
return state
|
||||||
|
|
||||||
def load_commit_content(self):
|
def page_commit_selection(state: AppState, direction: int) -> AppState:
|
||||||
if not self.commits:
|
page_size = state.height - 1
|
||||||
return
|
delta = page_size * direction
|
||||||
|
return move_commit_selection(state, delta)
|
||||||
|
|
||||||
reference_line = None
|
def scroll_right_pane(state: AppState, delta: int) -> AppState:
|
||||||
scroll_percentage = 0
|
max_scroll = max(0, len(state.file_lines) - (state.height - 1))
|
||||||
if len(self.file_lines) > 0:
|
new_offset = state.right_scroll_offset + delta
|
||||||
max_scroll_old = max(0, len(self.file_lines) - (self.height - 1))
|
new_offset = max(0, min(new_offset, max_scroll))
|
||||||
if max_scroll_old > 0:
|
return replace(state, right_scroll_offset=new_offset)
|
||||||
scroll_percentage = self.right_scroll_offset / max_scroll_old
|
|
||||||
if self.right_scroll_offset < len(self.file_lines):
|
|
||||||
reference_line = self.file_lines[self.right_scroll_offset]
|
|
||||||
|
|
||||||
commit_hash = self.commits[self.selected_commit_idx].split()[0]
|
def page_right_pane(state: AppState, direction: int) -> AppState:
|
||||||
self.file_lines = get_file_at_commit(commit_hash, self.filename)
|
page_size = state.height - 1
|
||||||
|
delta = page_size * direction
|
||||||
|
return scroll_right_pane(state, delta)
|
||||||
|
|
||||||
prev_commit_hash = None
|
def update_divider(state: AppState, mx: int) -> AppState:
|
||||||
if self.selected_commit_idx < len(self.commits) - 1:
|
min_col = 10
|
||||||
prev_commit_hash = self.commits[self.selected_commit_idx + 1].split()[0]
|
max_col = state.width - 20
|
||||||
|
new_divider_col = max(min_col, min(mx, max_col))
|
||||||
|
return replace(state, divider_col=new_divider_col)
|
||||||
|
|
||||||
if self.show_whole_diff or self.show_additions or self.show_deletions:
|
|
||||||
self.added_lines, self.deleted_lines = get_diff_info(commit_hash, prev_commit_hash, self.filename)
|
|
||||||
else:
|
|
||||||
self.added_lines, self.deleted_lines = [], []
|
|
||||||
|
|
||||||
max_scroll_new = max(0, len(self.file_lines) - (self.height - 1))
|
|
||||||
if reference_line:
|
|
||||||
matching_line_idx = find_best_matching_line(reference_line, self.file_lines, 1000)
|
|
||||||
if matching_line_idx is not None:
|
|
||||||
self.right_scroll_offset = matching_line_idx
|
|
||||||
else:
|
|
||||||
self.right_scroll_offset = int(scroll_percentage * max_scroll_new)
|
|
||||||
else:
|
|
||||||
self.right_scroll_offset = int(scroll_percentage * max_scroll_new)
|
|
||||||
|
|
||||||
self.right_scroll_offset = max(0, min(self.right_scroll_offset, max_scroll_new))
|
|
||||||
|
|
||||||
# --- Rendering Functions (View) ---
|
# --- Rendering Functions (View) ---
|
||||||
|
|
||||||
|
|
@ -507,42 +517,32 @@ def copy_selection_to_clipboard(stdscr, state):
|
||||||
except (FileNotFoundError, subprocess.CalledProcessError):
|
except (FileNotFoundError, subprocess.CalledProcessError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def handle_mouse_input(stdscr, state):
|
def handle_mouse_input(stdscr, state: AppState) -> AppState:
|
||||||
try:
|
try:
|
||||||
_, mx, my, _, bstate = curses.getmouse()
|
_, mx, my, _, bstate = curses.getmouse()
|
||||||
state.last_bstate = bstate
|
state = replace(state, last_bstate=bstate, mouse_x=mx, mouse_y=my)
|
||||||
state.mouse_x, state.mouse_y = mx, my
|
|
||||||
|
|
||||||
# Handle mouse button press
|
# Handle mouse button press
|
||||||
if bstate & curses.BUTTON1_PRESSED:
|
if bstate & curses.BUTTON1_PRESSED:
|
||||||
# Check if clicking near divider (only if sidebar is visible)
|
|
||||||
if state.show_sidebar and abs(mx - state.divider_col) <= 1:
|
if state.show_sidebar and abs(mx - state.divider_col) <= 1:
|
||||||
state.dragging_divider = True
|
return replace(state, dragging_divider=True)
|
||||||
else:
|
else:
|
||||||
# Switch panes immediately on click (only if sidebar is visible)
|
focus = "right"
|
||||||
if state.show_sidebar:
|
if state.show_sidebar:
|
||||||
state.focus = "left" if mx < state.divider_col else "right"
|
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)
|
return replace(state,
|
||||||
state.is_selecting = True
|
focus=focus,
|
||||||
state.selection_start_coord = (mx, my)
|
is_selecting=True,
|
||||||
state.selection_end_coord = (mx, my)
|
selection_start_coord=(mx, my),
|
||||||
state.click_position = (mx, my)
|
selection_end_coord=(mx, my),
|
||||||
|
click_position=(mx, my))
|
||||||
# Redraw immediately to show selection highlight and focus change
|
|
||||||
draw_ui(stdscr, state)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Handle mouse button release
|
# Handle mouse button release
|
||||||
if bstate & curses.BUTTON1_RELEASED:
|
if bstate & curses.BUTTON1_RELEASED:
|
||||||
# End of divider drag
|
|
||||||
if state.dragging_divider:
|
if state.dragging_divider:
|
||||||
state.dragging_divider = False
|
return replace(state, dragging_divider=False)
|
||||||
return
|
|
||||||
|
|
||||||
# End of selection
|
|
||||||
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)
|
||||||
# or very close to the same position (within 1-2 pixels)
|
# or very close to the same position (within 1-2 pixels)
|
||||||
|
|
@ -550,80 +550,77 @@ def handle_mouse_input(stdscr, state):
|
||||||
abs(state.click_position[0] - mx) <= 2 and
|
abs(state.click_position[0] - mx) <= 2 and
|
||||||
abs(state.click_position[1] - my) <= 2):
|
abs(state.click_position[1] - my) <= 2):
|
||||||
# This was a click, so switch panes (only if sidebar is visible)
|
# This was a click, so switch panes (only if sidebar is visible)
|
||||||
|
focus = "right"
|
||||||
if state.show_sidebar:
|
if state.show_sidebar:
|
||||||
state.focus = "left" if mx < state.divider_col else "right"
|
focus = "left" if mx < state.divider_col else "right"
|
||||||
else:
|
|
||||||
state.focus = "right" # When sidebar is hidden, focus is always right
|
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(state.height - 1, 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):
|
||||||
state.selected_commit_idx = new_commit_idx
|
new_state = replace(new_state, selected_commit_idx=new_commit_idx)
|
||||||
state.load_commit_content()
|
new_state = load_commit_content(new_state)
|
||||||
|
|
||||||
|
# Reset selection state
|
||||||
|
return replace(new_state, is_selecting=False, selection_start_coord=None, selection_end_coord=None, click_position=None)
|
||||||
|
|
||||||
elif state.selection_start_coord and state.selection_end_coord:
|
elif state.selection_start_coord and state.selection_end_coord:
|
||||||
# This was a drag selection, copy the text
|
# This was a drag selection, copy the text
|
||||||
copy_selection_to_clipboard(stdscr, state)
|
copy_selection_to_clipboard(stdscr, state)
|
||||||
|
|
||||||
# Reset selection state
|
# Reset selection state
|
||||||
state.is_selecting = False
|
return replace(state, is_selecting=False, selection_start_coord=None, selection_end_coord=None, click_position=None)
|
||||||
state.selection_start_coord = None
|
|
||||||
state.selection_end_coord = None
|
|
||||||
state.click_position = None
|
|
||||||
return
|
|
||||||
|
|
||||||
# Handle mouse movement during drag operations
|
# Handle mouse movement during drag operations
|
||||||
if state.dragging_divider:
|
if state.dragging_divider:
|
||||||
# Update divider position during drag
|
return update_divider(state, mx)
|
||||||
state.update_divider(mx)
|
|
||||||
elif state.is_selecting:
|
elif state.is_selecting:
|
||||||
# Update selection end coordinates during drag
|
return replace(state, selection_end_coord=(mx, my))
|
||||||
state.selection_end_coord = (mx, my)
|
|
||||||
# Redraw immediately to show selection highlight during drag
|
|
||||||
draw_ui(stdscr, state)
|
|
||||||
|
|
||||||
except curses.error:
|
except curses.error:
|
||||||
pass
|
pass
|
||||||
|
return state
|
||||||
|
|
||||||
def handle_keyboard_input(key, state):
|
def handle_keyboard_input(key, state: AppState) -> AppState:
|
||||||
if key in [ord('q')]:
|
if key in [ord('q')]:
|
||||||
state.should_exit = True
|
return replace(state, should_exit=True)
|
||||||
elif key == 27: # Escape key
|
elif key == 27: # Escape key
|
||||||
if state.is_selecting:
|
if state.is_selecting:
|
||||||
state.is_selecting = False
|
return replace(state, is_selecting=False, selection_start_coord=None, selection_end_coord=None)
|
||||||
state.selection_start_coord = None
|
|
||||||
state.selection_end_coord = None
|
|
||||||
else:
|
else:
|
||||||
state.should_exit = True
|
return replace(state, should_exit=True)
|
||||||
elif key == ord('m'):
|
elif key == ord('m'):
|
||||||
state.toggle_mouse()
|
return toggle_mouse(state)
|
||||||
elif key == ord('s'):
|
elif key == ord('s'):
|
||||||
state.toggle_sidebar()
|
return toggle_sidebar(state)
|
||||||
elif key in [curses.KEY_LEFT, ord('h')]:
|
elif key in [curses.KEY_LEFT, ord('h')]:
|
||||||
if state.show_sidebar:
|
if state.show_sidebar:
|
||||||
state.focus = "left"
|
return replace(state, focus="left")
|
||||||
elif key in [curses.KEY_RIGHT, ord('l')]:
|
elif key in [curses.KEY_RIGHT, ord('l')]:
|
||||||
state.focus = "right"
|
return replace(state, focus="right")
|
||||||
|
|
||||||
elif state.focus == "left":
|
elif state.focus == "left":
|
||||||
if key in [curses.KEY_DOWN, ord('j')]:
|
if key in [curses.KEY_DOWN, ord('j')]:
|
||||||
state.move_commit_selection(1)
|
return move_commit_selection(state, 1)
|
||||||
elif key in [curses.KEY_UP, ord('k')]:
|
elif key in [curses.KEY_UP, ord('k')]:
|
||||||
state.move_commit_selection(-1)
|
return move_commit_selection(state, -1)
|
||||||
elif key in [curses.KEY_NPAGE, ord(' ')]:
|
elif key in [curses.KEY_NPAGE, ord(' ')]:
|
||||||
state.page_commit_selection(1)
|
return page_commit_selection(state, 1)
|
||||||
elif key in [curses.KEY_PPAGE, 8, 127, curses.KEY_SR]:
|
elif key in [curses.KEY_PPAGE, 8, 127, curses.KEY_SR]:
|
||||||
state.page_commit_selection(-1)
|
return page_commit_selection(state, -1)
|
||||||
|
|
||||||
elif state.focus == "right":
|
elif state.focus == "right":
|
||||||
if key in [curses.KEY_DOWN, ord('j')]:
|
if key in [curses.KEY_DOWN, ord('j')]:
|
||||||
state.scroll_right_pane(1)
|
return scroll_right_pane(state, 1)
|
||||||
elif key in [curses.KEY_UP, ord('k')]:
|
elif key in [curses.KEY_UP, ord('k')]:
|
||||||
state.scroll_right_pane(-1)
|
return scroll_right_pane(state, -1)
|
||||||
elif key in [curses.KEY_NPAGE, ord(' ')]:
|
elif key in [curses.KEY_NPAGE, ord(' ')]:
|
||||||
state.page_right_pane(1)
|
return page_right_pane(state, 1)
|
||||||
elif key in [curses.KEY_PPAGE, 8, 127, curses.KEY_SR]:
|
elif key in [curses.KEY_PPAGE, 8, 127, curses.KEY_SR]:
|
||||||
state.page_right_pane(-1)
|
return page_right_pane(state, -1)
|
||||||
|
return state
|
||||||
|
|
||||||
# --- Main Application ---
|
# --- Main Application ---
|
||||||
|
|
||||||
|
|
@ -644,7 +641,12 @@ def main(stdscr, filename, show_diff, show_add, show_del, mouse):
|
||||||
curses.init_pair(4, curses.COLOR_RED, -1)
|
curses.init_pair(4, curses.COLOR_RED, -1)
|
||||||
|
|
||||||
height, width = stdscr.getmaxyx()
|
height, width = stdscr.getmaxyx()
|
||||||
state = AppState(filename, width, height, show_diff, show_add, show_del, mouse)
|
state = AppState(
|
||||||
|
filename=filename, width=width, height=height,
|
||||||
|
show_whole_diff=show_diff, show_additions=show_add,
|
||||||
|
show_deletions=show_del, enable_mouse=mouse,
|
||||||
|
commits=get_commits(filename)
|
||||||
|
)
|
||||||
|
|
||||||
if state.enable_mouse:
|
if state.enable_mouse:
|
||||||
curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION)
|
curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION)
|
||||||
|
|
@ -656,7 +658,7 @@ def main(stdscr, filename, show_diff, show_add, show_del, mouse):
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
state.load_commit_content()
|
state = load_commit_content(state)
|
||||||
|
|
||||||
# Initial draw before the main loop starts
|
# Initial draw before the main loop starts
|
||||||
draw_ui(stdscr, state)
|
draw_ui(stdscr, state)
|
||||||
|
|
@ -665,16 +667,24 @@ def main(stdscr, filename, show_diff, show_add, show_del, mouse):
|
||||||
try:
|
try:
|
||||||
key = stdscr.getch()
|
key = stdscr.getch()
|
||||||
|
|
||||||
|
old_mouse_enabled = state.enable_mouse
|
||||||
|
|
||||||
# Process input and update the application state
|
# Process input and update the application state
|
||||||
if key == -1: # No input available (timeout)
|
if key == -1: # No input available (timeout)
|
||||||
pass # Just redraw the UI and continue
|
pass # Just redraw the UI and continue
|
||||||
elif key == curses.KEY_RESIZE:
|
elif key == curses.KEY_RESIZE:
|
||||||
h, w = stdscr.getmaxyx()
|
h, w = stdscr.getmaxyx()
|
||||||
state.update_dimensions(h, w)
|
state = update_dimensions(state, h, w)
|
||||||
elif state.enable_mouse and key == curses.KEY_MOUSE:
|
elif state.enable_mouse and key == curses.KEY_MOUSE:
|
||||||
handle_mouse_input(stdscr, state)
|
state = handle_mouse_input(stdscr, state)
|
||||||
else:
|
else:
|
||||||
handle_keyboard_input(key, state)
|
state = handle_keyboard_input(key, state)
|
||||||
|
|
||||||
|
if old_mouse_enabled != state.enable_mouse:
|
||||||
|
if state.enable_mouse:
|
||||||
|
curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION)
|
||||||
|
else:
|
||||||
|
curses.mousemask(0)
|
||||||
|
|
||||||
# After every action, redraw the UI to reflect changes immediately.
|
# After every action, redraw the UI to reflect changes immediately.
|
||||||
# This is crucial for real-time feedback during mouse drags.
|
# This is crucial for real-time feedback during mouse drags.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue