refactor: Implement smart line matching for scroll position preservation
This commit is contained in:
parent
bc1c07ba29
commit
a985eacd0e
67
gtm
67
gtm
|
|
@ -18,6 +18,44 @@ def get_file_at_commit(commit_hash, filename):
|
|||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
return result.stdout.splitlines()
|
||||
|
||||
def find_best_matching_line(reference_line, file_lines, max_lines=None):
|
||||
"""Find the best matching line in file_lines that matches reference_line.
|
||||
Returns the line index or None if no good match is found."""
|
||||
if not reference_line or not file_lines:
|
||||
return None
|
||||
|
||||
# First try exact match
|
||||
for i, line in enumerate(file_lines):
|
||||
if line == reference_line:
|
||||
return i
|
||||
|
||||
# If no exact match, try to find the most similar line
|
||||
# Only search through a reasonable number of lines for performance
|
||||
search_lines = file_lines[:max_lines] if max_lines else file_lines
|
||||
|
||||
best_match = None
|
||||
best_score = 0
|
||||
|
||||
for i, line in enumerate(search_lines):
|
||||
# Simple similarity score: count of common characters
|
||||
score = sum(1 for a, b in zip(reference_line, line) if a == b)
|
||||
|
||||
# Adjust score based on length difference
|
||||
length_diff = abs(len(reference_line) - len(line))
|
||||
adjusted_score = score - (length_diff * 0.5)
|
||||
|
||||
if adjusted_score > best_score:
|
||||
best_score = adjusted_score
|
||||
best_match = i
|
||||
|
||||
# Only return a match if it's reasonably good
|
||||
# (at least 60% of the shorter string length)
|
||||
min_length = min(len(reference_line), 1) # Avoid division by zero
|
||||
if best_score > (min_length * 0.6):
|
||||
return best_match
|
||||
|
||||
return None
|
||||
|
||||
def get_diff_info(current_commit, prev_commit, filename):
|
||||
"""Get diff information between two commits for a file"""
|
||||
if not prev_commit:
|
||||
|
|
@ -129,10 +167,15 @@ def main(stdscr, filename, show_whole_diff=False, show_additions=False, show_del
|
|||
|
||||
# Calculate current scroll position as percentage before changing commits
|
||||
scroll_percentage = 0
|
||||
reference_line = None
|
||||
if len(file_lines) > 0:
|
||||
max_scroll = max(0, len(file_lines) - (height - 1))
|
||||
if max_scroll > 0:
|
||||
scroll_percentage = scroll_offset / max_scroll
|
||||
|
||||
# Store the content of the top visible line as reference
|
||||
if scroll_offset < len(file_lines):
|
||||
reference_line = file_lines[scroll_offset]
|
||||
|
||||
# Only fetch file content when commit changes
|
||||
if (key in [curses.KEY_DOWN, curses.KEY_UP, ord('j'), ord('k'),
|
||||
|
|
@ -148,12 +191,26 @@ def main(stdscr, filename, show_whole_diff=False, show_additions=False, show_del
|
|||
if show_whole_diff or show_additions or show_deletions:
|
||||
added_lines, deleted_lines = get_diff_info(commit_hash, prev_commit_hash, filename)
|
||||
|
||||
# Apply the saved scroll percentage to the new file
|
||||
max_scroll = max(0, len(file_lines) - (height - 1))
|
||||
if max_scroll > 0:
|
||||
scroll_offset = int(scroll_percentage * max_scroll)
|
||||
# Try to find the same line in the new file version
|
||||
if reference_line:
|
||||
# Limit search to first 1000 lines for performance
|
||||
matching_line_idx = find_best_matching_line(reference_line, file_lines, 1000)
|
||||
if matching_line_idx is not None:
|
||||
scroll_offset = matching_line_idx
|
||||
else:
|
||||
# Fall back to percentage-based scrolling
|
||||
max_scroll = max(0, len(file_lines) - (height - 1))
|
||||
if max_scroll > 0:
|
||||
scroll_offset = int(scroll_percentage * max_scroll)
|
||||
else:
|
||||
scroll_offset = 0
|
||||
else:
|
||||
scroll_offset = 0
|
||||
# Fall back to percentage-based scrolling
|
||||
max_scroll = max(0, len(file_lines) - (height - 1))
|
||||
if max_scroll > 0:
|
||||
scroll_offset = int(scroll_percentage * max_scroll)
|
||||
else:
|
||||
scroll_offset = 0
|
||||
|
||||
# Recalculate max_scroll and ensure scroll_offset is within bounds
|
||||
max_scroll = max(0, len(file_lines) - (height - 1))
|
||||
|
|
|
|||
Loading…
Reference in New Issue