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

Commit

Permalink
moved the process_diff_method from gitless to gitpylib
Browse files Browse the repository at this point in the history
  • Loading branch information
spderosso committed Nov 23, 2013
1 parent 7bd9a55 commit c306bca
Showing 1 changed file with 81 additions and 2 deletions.
83 changes: 81 additions & 2 deletions gitpylib/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"""Module for dealing with Git files."""


import collections
import os.path
import re

import common

Expand All @@ -14,6 +16,12 @@
FILE_NOT_FOUND = 2
FILE_NOT_FOUND_AT_CP = 3

# Possible diff output lines.
DIFF_INFO = 4 # line carrying diff info for new hunk.
DIFF_SAME = 5 # line that git diff includes for context.
DIFF_ADDED = 6
DIFF_MINUS = 7


def stage(fp):
"""Stages the given file.
Expand Down Expand Up @@ -118,7 +126,7 @@ def diff(fp):
fp = common.real_case(fp)

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


def staged_diff(fp):
Expand All @@ -133,4 +141,75 @@ def staged_diff(fp):
fp = common.real_case(fp)

out, unused_err = common.safe_git_call('diff --cached -- "%s"' % fp)
return out
return _process_diff_output(_strip_diff_header(out.splitlines()))


# Private functions.


def _strip_diff_header(diff_out):
"""Removes the diff header lines."""
first_non_header_line = 0
for line in diff_out:
if line.startswith('@@'):
break
first_non_header_line += 1
return diff_out[first_non_header_line:]


def _process_diff_output(diff_out):
"""Process the git diff output.
Args:
diff_out: a list of lines output by the git diff command.
Returns:
a 2-tuple of:
- a list of namedtuples with fields 'line', 'status', 'old_line_number'
and 'new_line_number' where 'status' is one of DIFF_INFO, DIFF_SAME,
DIFF_ADDED or DIFF_MINUS and 'old_line_number', 'new_line_number'
correspond to the line's old line number and new line number respectively.
(Note that, for example, if the line is DIFF_ADDED, then 'old_line_number'
is None since that line is not present in the old file).
- max_line_digits: return the maximum amount of line digits found while
parsing the git diff output, this is useful for padding.
"""
MIN_LINE_PADDING = 8
LineData = collections.namedtuple(
'LineData',
['line', 'status', 'old_line_number', 'new_line_number'])

resulting = [] # accumulates line information for formatting.
max_line_digits = 0
old_line_number = 1
new_line_number = 1

for line in diff_out:
# @@ -(start of old),(length of old) +(start of new),(length of new) @@
new_hunk_regex = "^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@"
new_hunk_info = re.search(new_hunk_regex, line)
if new_hunk_info:
old_line_number = int(new_hunk_info.group(1))
old_diff_length = int(new_hunk_info.group(2))
new_line_number = int(new_hunk_info.group(3))
new_diff_length = int(new_hunk_info.group(4))
resulting.append(
LineData(line, DIFF_INFO, old_line_number, new_line_number))
max_line_digits = max([old_line_number + old_diff_length,
new_line_number + new_diff_length,
max_line_digits]) # start + length of each diff.
elif line.startswith(' '):
resulting.append(
LineData(line, DIFF_SAME, old_line_number, new_line_number))
old_line_number += 1
new_line_number += 1
elif line.startswith('-'):
resulting.append(LineData(line, DIFF_MINUS, old_line_number, None))
old_line_number += 1
elif line.startswith('+'):
resulting.append(LineData(line, DIFF_ADDED, None, new_line_number))
new_line_number += 1

max_line_digits = len(str(max_line_digits)) # digits = len(string of number).
max_line_digits = max(MIN_LINE_PADDING, max_line_digits + 1)
return resulting, max_line_digits

0 comments on commit c306bca

Please sign in to comment.