Skip to content

Commit

Permalink
Fix difflib ? hint in diff output when dealing with tabs (#15201)
Browse files Browse the repository at this point in the history
  • Loading branch information
asottile authored and tim-one committed Aug 21, 2019
1 parent 092911d commit e1c638d
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 23 deletions.
33 changes: 11 additions & 22 deletions Lib/difflib.py
Original file line number Diff line number Diff line change
Expand Up @@ -733,20 +733,15 @@ def get_close_matches(word, possibilities, n=3, cutoff=0.6):
# Strip scores for the best n matches
return [x for score, x in result]

def _count_leading(line, ch):
"""
Return number of `ch` characters at the start of `line`.

Example:
def _keep_original_ws(s, tag_s):
"""Replace whitespace with the original whitespace characters in `s`"""
return ''.join(
c if tag_c == " " and c.isspace() else tag_c
for c, tag_c in zip(s, tag_s)
)

>>> _count_leading(' abc', ' ')
3
"""

i, n = 0, len(line)
while i < n and line[i] == ch:
i += 1
return i

class Differ:
r"""
Expand Down Expand Up @@ -1033,7 +1028,7 @@ def _fancy_helper(self, a, alo, ahi, b, blo, bhi):

def _qformat(self, aline, bline, atags, btags):
r"""
Format "?" output and deal with leading tabs.
Format "?" output and deal with tabs.
Example:
Expand All @@ -1047,22 +1042,16 @@ def _qformat(self, aline, bline, atags, btags):
'+ \tabcdefGhijkl\n'
'? \t ^ ^ ^\n'
"""

# Can hurt, but will probably help most of the time.
common = min(_count_leading(aline, "\t"),
_count_leading(bline, "\t"))
common = min(common, _count_leading(atags[:common], " "))
common = min(common, _count_leading(btags[:common], " "))
atags = atags[common:].rstrip()
btags = btags[common:].rstrip()
atags = _keep_original_ws(aline, atags).rstrip()
btags = _keep_original_ws(bline, btags).rstrip()

yield "- " + aline
if atags:
yield "? %s%s\n" % ("\t" * common, atags)
yield f"? {atags}\n"

yield "+ " + bline
if btags:
yield "? %s%s\n" % ("\t" * common, btags)
yield f"? {btags}\n"

# With respect to junk, an earlier version of ndiff simply refused to
# *start* a match with a junk element. The result was cases like this:
Expand Down
8 changes: 7 additions & 1 deletion Lib/test/test_difflib.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,16 @@ def test_added_tab_hint(self):
# Check fix for bug #1488943
diff = list(difflib.Differ().compare(["\tI am a buggy"],["\t\tI am a bug"]))
self.assertEqual("- \tI am a buggy", diff[0])
self.assertEqual("? --\n", diff[1])
self.assertEqual("? \t --\n", diff[1])
self.assertEqual("+ \t\tI am a bug", diff[2])
self.assertEqual("? +\n", diff[3])

def test_hint_indented_properly_with_tabs(self):
diff = list(difflib.Differ().compare(["\t \t \t^"], ["\t \t \t^\n"]))
self.assertEqual("- \t \t \t^", diff[0])
self.assertEqual("+ \t \t \t^\n", diff[1])
self.assertEqual("? \t \t \t +\n", diff[2])

def test_mdiff_catch_stop_iteration(self):
# Issue #33224
self.assertEqual(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix :mod:`difflib` ``?`` hint in diff output when dealing with tabs. Patch
by Anthony Sottile.

0 comments on commit e1c638d

Please sign in to comment.