feat: Add line numbers with color-coded display and toggle option

This commit is contained in:
n loewen (aider) 2025-06-08 02:20:16 +01:00
parent cfa96a436f
commit e4b65b98d1
1 changed files with 42 additions and 5 deletions

47
gtm
View File

@ -133,6 +133,9 @@ class AppState:
# Line wrapping settings
wrap_lines: bool = True
# Line numbers settings
show_line_numbers: bool = False
# Change navigation
change_blocks: List[Tuple[int, int]] = field(default_factory=list) # (start_line, end_line) of each change block
current_change_idx: int = -1 # -1 means no change is selected
@ -356,6 +359,18 @@ def jump_to_prev_change(state: AppState) -> AppState:
def draw_right_pane(stdscr, state):
# If sidebar is hidden, right pane starts at column 0
right_start = 0 if not state.show_sidebar else state.divider_col + 2
# Calculate line number width if enabled
line_num_width = 0
if state.show_line_numbers:
# Width based on the number of digits in the largest line number
max_line_num = len(state.file_lines)
line_num_width = len(str(max_line_num)) + 1 # +1 for spacing
# Adjust right pane start position and width for line numbers
if state.show_line_numbers:
right_start += line_num_width
right_width = state.width - right_start - 1
max_scroll = max(0, len(state.file_lines) - (state.height - 1))
@ -375,7 +390,8 @@ def draw_right_pane(stdscr, state):
line_num = i + state.right_scroll_offset + 1
if (state.show_whole_diff or state.show_deletions) and line_num in deleted_line_map:
for del_content in deleted_line_map[line_num]:
display_lines.append({'type': 'deleted', 'content': del_content})
# For deleted lines, use the same line number
display_lines.append({'type': 'deleted', 'content': del_content, 'line_num': line_num})
is_added = False
if state.show_whole_diff or state.show_additions:
@ -384,7 +400,7 @@ def draw_right_pane(stdscr, state):
is_added = True
break
display_lines.append({'type': 'added' if is_added else 'regular', 'content': line})
display_lines.append({'type': 'added' if is_added else 'regular', 'content': line, 'line_num': line_num})
display_row = 0
for line_info in display_lines:
@ -393,6 +409,20 @@ def draw_right_pane(stdscr, state):
line_type = line_info['type']
content = line_info['content']
line_num = line_info.get('line_num', 0)
# Draw line number if enabled
if state.show_line_numbers:
line_num_str = str(line_num).rjust(line_num_width - 1) + " "
line_num_pos = (0 if not state.show_sidebar else state.divider_col + 2)
# Use different color for line numbers
if line_type == 'added':
stdscr.addstr(display_row, line_num_pos, line_num_str, curses.color_pair(5))
elif line_type == 'deleted':
stdscr.addstr(display_row, line_num_pos, line_num_str, curses.color_pair(6))
else:
stdscr.addstr(display_row, line_num_pos, line_num_str, curses.color_pair(7))
# Determine prefix based on line type and diff mode
prefix = ""
@ -528,13 +558,14 @@ def draw_status_bars(stdscr, state):
if len(parts) >= 4:
commit_message = parts[3]
# Add wrap indicator and change position to commit message
# Add indicators to commit message
wrap_indicator = "" if state.wrap_lines else "[NW] "
line_num_indicator = "[LN] " if state.show_line_numbers else ""
change_indicator = ""
if state.change_blocks and state.current_change_idx != -1:
change_indicator = f"[Change {state.current_change_idx + 1}/{len(state.change_blocks)}] "
commit_message = wrap_indicator + change_indicator + commit_message
commit_message = wrap_indicator + line_num_indicator + change_indicator + commit_message
# Status bar percentages
if len(state.file_lines) > 0:
@ -814,6 +845,8 @@ def handle_keyboard_input(key, state: AppState) -> AppState:
return toggle_sidebar(state)
elif key == ord('w'):
return replace(state, wrap_lines=not state.wrap_lines)
elif key == ord('L'): # Capital L to toggle line numbers
return replace(state, show_line_numbers=not state.show_line_numbers)
elif key in [110, ord('n')]: # ASCII code for 'n'
if state.show_whole_diff or state.show_additions or state.show_deletions:
return jump_to_next_change(state)
@ -864,6 +897,9 @@ def main(stdscr, filename, show_diff, show_add, show_del, mouse, wrap_lines=True
curses.init_pair(2, curses.COLOR_WHITE, 0) # Inactive pane: white on black
curses.init_pair(3, curses.COLOR_GREEN, -1) # Added lines
curses.init_pair(4, curses.COLOR_RED, -1) # Deleted lines
curses.init_pair(5, curses.COLOR_GREEN, -1) # Line numbers for added lines
curses.init_pair(6, curses.COLOR_RED, -1) # Line numbers for deleted lines
curses.init_pair(7, curses.COLOR_BLUE, -1) # Regular line numbers
height, width = stdscr.getmaxyx()
state = AppState(
@ -930,6 +966,7 @@ if __name__ == "__main__":
parser.add_argument("--diff-deletions", action="store_true", help="Show deleted lines in red")
parser.add_argument("--no-mouse", action="store_true", help="Disable mouse support")
parser.add_argument("--no-wrap", action="store_true", help="Disable line wrapping")
parser.add_argument("--line-numbers", action="store_true", help="Show line numbers")
parser.add_argument("-v", "--version", action="store_true", help="Show version number")
parser.add_argument("filename", nargs="?", help="File to view history for")
@ -956,4 +993,4 @@ if __name__ == "__main__":
print(f" git commit -m 'Add {os.path.basename(filename)}'")
sys.exit(1)
curses.wrapper(main, filename, args.diff, args.diff_additions, args.diff_deletions, not args.no_mouse, not args.no_wrap)
curses.wrapper(main, filename, args.diff, args.diff_additions, args.diff_deletions, not args.no_mouse, not args.no_wrap, args.line_numbers)