Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

Commit c306bca

Browse files
committed
moved the process_diff_method from gitless to gitpylib
1 parent 7bd9a55 commit c306bca

File tree

1 file changed

+81
-2
lines changed

1 file changed

+81
-2
lines changed

gitpylib/file.py

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
"""Module for dealing with Git files."""
66

77

8+
import collections
89
import os.path
10+
import re
911

1012
import common
1113

@@ -14,6 +16,12 @@
1416
FILE_NOT_FOUND = 2
1517
FILE_NOT_FOUND_AT_CP = 3
1618

19+
# Possible diff output lines.
20+
DIFF_INFO = 4 # line carrying diff info for new hunk.
21+
DIFF_SAME = 5 # line that git diff includes for context.
22+
DIFF_ADDED = 6
23+
DIFF_MINUS = 7
24+
1725

1826
def stage(fp):
1927
"""Stages the given file.
@@ -118,7 +126,7 @@ def diff(fp):
118126
fp = common.real_case(fp)
119127

120128
out, unused_err = common.safe_git_call('diff -- "%s"' % fp)
121-
return out
129+
return _process_diff_output(_strip_diff_header(out.splitlines()))
122130

123131

124132
def staged_diff(fp):
@@ -133,4 +141,75 @@ def staged_diff(fp):
133141
fp = common.real_case(fp)
134142

135143
out, unused_err = common.safe_git_call('diff --cached -- "%s"' % fp)
136-
return out
144+
return _process_diff_output(_strip_diff_header(out.splitlines()))
145+
146+
147+
# Private functions.
148+
149+
150+
def _strip_diff_header(diff_out):
151+
"""Removes the diff header lines."""
152+
first_non_header_line = 0
153+
for line in diff_out:
154+
if line.startswith('@@'):
155+
break
156+
first_non_header_line += 1
157+
return diff_out[first_non_header_line:]
158+
159+
160+
def _process_diff_output(diff_out):
161+
"""Process the git diff output.
162+
163+
Args:
164+
diff_out: a list of lines output by the git diff command.
165+
166+
Returns:
167+
a 2-tuple of:
168+
- a list of namedtuples with fields 'line', 'status', 'old_line_number'
169+
and 'new_line_number' where 'status' is one of DIFF_INFO, DIFF_SAME,
170+
DIFF_ADDED or DIFF_MINUS and 'old_line_number', 'new_line_number'
171+
correspond to the line's old line number and new line number respectively.
172+
(Note that, for example, if the line is DIFF_ADDED, then 'old_line_number'
173+
is None since that line is not present in the old file).
174+
- max_line_digits: return the maximum amount of line digits found while
175+
parsing the git diff output, this is useful for padding.
176+
"""
177+
MIN_LINE_PADDING = 8
178+
LineData = collections.namedtuple(
179+
'LineData',
180+
['line', 'status', 'old_line_number', 'new_line_number'])
181+
182+
resulting = [] # accumulates line information for formatting.
183+
max_line_digits = 0
184+
old_line_number = 1
185+
new_line_number = 1
186+
187+
for line in diff_out:
188+
# @@ -(start of old),(length of old) +(start of new),(length of new) @@
189+
new_hunk_regex = "^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@"
190+
new_hunk_info = re.search(new_hunk_regex, line)
191+
if new_hunk_info:
192+
old_line_number = int(new_hunk_info.group(1))
193+
old_diff_length = int(new_hunk_info.group(2))
194+
new_line_number = int(new_hunk_info.group(3))
195+
new_diff_length = int(new_hunk_info.group(4))
196+
resulting.append(
197+
LineData(line, DIFF_INFO, old_line_number, new_line_number))
198+
max_line_digits = max([old_line_number + old_diff_length,
199+
new_line_number + new_diff_length,
200+
max_line_digits]) # start + length of each diff.
201+
elif line.startswith(' '):
202+
resulting.append(
203+
LineData(line, DIFF_SAME, old_line_number, new_line_number))
204+
old_line_number += 1
205+
new_line_number += 1
206+
elif line.startswith('-'):
207+
resulting.append(LineData(line, DIFF_MINUS, old_line_number, None))
208+
old_line_number += 1
209+
elif line.startswith('+'):
210+
resulting.append(LineData(line, DIFF_ADDED, None, new_line_number))
211+
new_line_number += 1
212+
213+
max_line_digits = len(str(max_line_digits)) # digits = len(string of number).
214+
max_line_digits = max(MIN_LINE_PADDING, max_line_digits + 1)
215+
return resulting, max_line_digits

0 commit comments

Comments
 (0)