mercurial/patch.py
changeset 37471 51d5e1ff0613
parent 37468 ef661ce45cdb
child 37568 f5833651ad07
equal deleted inserted replaced
37470:d658cbef8041 37471:51d5e1ff0613
    58 # public functions
    58 # public functions
    59 
    59 
    60 def split(stream):
    60 def split(stream):
    61     '''return an iterator of individual patches from a stream'''
    61     '''return an iterator of individual patches from a stream'''
    62     def isheader(line, inheader):
    62     def isheader(line, inheader):
    63         if inheader and line[0] in (' ', '\t'):
    63         if inheader and line.startswith((' ', '\t')):
    64             # continuation
    64             # continuation
    65             return True
    65             return True
    66         if line[0] in (' ', '-', '+'):
    66         if line.startswith((' ', '-', '+')):
    67             # diff line - don't check for header pattern in there
    67             # diff line - don't check for header pattern in there
    68             return False
    68             return False
    69         l = line.split(': ', 1)
    69         l = line.split(': ', 1)
    70         return len(l) == 2 and ' ' not in l[0]
    70         return len(l) == 2 and ' ' not in l[0]
    71 
    71 
  1389             top = 0
  1389             top = 0
  1390             bot = 0
  1390             bot = 0
  1391             hlen = len(self.hunk)
  1391             hlen = len(self.hunk)
  1392             for x in xrange(hlen - 1):
  1392             for x in xrange(hlen - 1):
  1393                 # the hunk starts with the @@ line, so use x+1
  1393                 # the hunk starts with the @@ line, so use x+1
  1394                 if self.hunk[x + 1][0] == ' ':
  1394                 if self.hunk[x + 1].startswith(' '):
  1395                     top += 1
  1395                     top += 1
  1396                 else:
  1396                 else:
  1397                     break
  1397                     break
  1398             if not toponly:
  1398             if not toponly:
  1399                 for x in xrange(hlen - 1):
  1399                 for x in xrange(hlen - 1):
  1400                     if self.hunk[hlen - bot - 1][0] == ' ':
  1400                     if self.hunk[hlen - bot - 1].startswith(' '):
  1401                         bot += 1
  1401                         bot += 1
  1402                     else:
  1402                     else:
  1403                         break
  1403                         break
  1404 
  1404 
  1405             bot = min(fuzz, bot)
  1405             bot = min(fuzz, bot)
  1797                 tofile = lr.readline()
  1797                 tofile = lr.readline()
  1798                 header += [fromfile, tofile]
  1798                 header += [fromfile, tofile]
  1799             else:
  1799             else:
  1800                 lr.push(fromfile)
  1800                 lr.push(fromfile)
  1801             yield 'file', header
  1801             yield 'file', header
  1802         elif line[0:1] == ' ':
  1802         elif line.startswith(' '):
  1803             yield 'context', scanwhile(line, lambda l: l[0] in ' \\')
  1803             cs = (' ', '\\')
  1804         elif line[0] in '-+':
  1804             yield 'context', scanwhile(line, lambda l: l.startswith(cs))
  1805             yield 'hunk', scanwhile(line, lambda l: l[0] in '-+\\')
  1805         elif line.startswith(('-', '+')):
       
  1806             cs = ('-', '+', '\\')
       
  1807             yield 'hunk', scanwhile(line, lambda l: l.startswith(cs))
  1806         else:
  1808         else:
  1807             m = lines_re.match(line)
  1809             m = lines_re.match(line)
  1808             if m:
  1810             if m:
  1809                 yield 'range', m.groups()
  1811                 yield 'range', m.groups()
  1810             else:
  1812             else:
  2502                 yield ('\n', '')
  2504                 yield ('\n', '')
  2503             if head:
  2505             if head:
  2504                 if line.startswith('@'):
  2506                 if line.startswith('@'):
  2505                     head = False
  2507                     head = False
  2506             else:
  2508             else:
  2507                 if line and line[0] not in ' +-@\\':
  2509                 if line and not line.startswith((' ', '+', '-', '@', '\\')):
  2508                     head = True
  2510                     head = True
  2509             stripline = line
  2511             stripline = line
  2510             diffline = False
  2512             diffline = False
  2511             if not head and line and line[0] in '+-':
  2513             if not head and line and line.startswith(('+', '-')):
  2512                 # highlight tabs and trailing whitespace, but only in
  2514                 # highlight tabs and trailing whitespace, but only in
  2513                 # changed lines
  2515                 # changed lines
  2514                 stripline = line.rstrip()
  2516                 stripline = line.rstrip()
  2515                 diffline = True
  2517                 diffline = True
  2516 
  2518 
  2546     lastmatch = 0
  2548     lastmatch = 0
  2547     matches = {}
  2549     matches = {}
  2548     for i, line in enumerate(slist):
  2550     for i, line in enumerate(slist):
  2549         if line == '':
  2551         if line == '':
  2550             continue
  2552             continue
  2551         if line[0] == '-':
  2553         if line.startswith('-'):
  2552             lastmatch = max(lastmatch, i)
  2554             lastmatch = max(lastmatch, i)
  2553             newgroup = False
  2555             newgroup = False
  2554             for j, newline in enumerate(slist[lastmatch + 1:]):
  2556             for j, newline in enumerate(slist[lastmatch + 1:]):
  2555                 if newline == '':
  2557                 if newline == '':
  2556                     continue
  2558                     continue
  2557                 if newline[0] == '-' and newgroup: # too far, no match
  2559                 if newline.startswith('-') and newgroup: # too far, no match
  2558                     break
  2560                     break
  2559                 if newline[0] == '+': # potential match
  2561                 if newline.startswith('+'): # potential match
  2560                     newgroup = True
  2562                     newgroup = True
  2561                     sim = difflib.SequenceMatcher(None, line, newline).ratio()
  2563                     sim = difflib.SequenceMatcher(None, line, newline).ratio()
  2562                     if sim > 0.7:
  2564                     if sim > 0.7:
  2563                         lastmatch = lastmatch + 1 + j
  2565                         lastmatch = lastmatch + 1 + j
  2564                         matches[i] = lastmatch
  2566                         matches[i] = lastmatch
  2566                         break
  2568                         break
  2567     return matches
  2569     return matches
  2568 
  2570 
  2569 def _inlinediff(s1, s2, operation):
  2571 def _inlinediff(s1, s2, operation):
  2570     '''Perform string diff to highlight specific changes.'''
  2572     '''Perform string diff to highlight specific changes.'''
  2571     operation_skip = '+?' if operation == 'diff.deleted' else '-?'
  2573     operation_skip = ('+', '?') if operation == 'diff.deleted' else ('-', '?')
  2572     if operation == 'diff.deleted':
  2574     if operation == 'diff.deleted':
  2573         s2, s1 = s1, s2
  2575         s2, s1 = s1, s2
  2574 
  2576 
  2575     buff = []
  2577     buff = []
  2576     # we never want to higlight the leading +-
  2578     # we never want to higlight the leading +-
  2588         raise error.ProgrammingError("Case not expected, operation = %s" %
  2590         raise error.ProgrammingError("Case not expected, operation = %s" %
  2589                                      operation)
  2591                                      operation)
  2590 
  2592 
  2591     s = difflib.ndiff(_nonwordre.split(s2), _nonwordre.split(s1))
  2593     s = difflib.ndiff(_nonwordre.split(s2), _nonwordre.split(s1))
  2592     for part in s:
  2594     for part in s:
  2593         if part[0] in operation_skip or len(part) == 2:
  2595         if part.startswith(operation_skip) or len(part) == 2:
  2594             continue
  2596             continue
  2595         l = operation + '.highlight'
  2597         l = operation + '.highlight'
  2596         if part[0] in ' ':
  2598         if part.startswith(' '):
  2597             l = operation
  2599             l = operation
  2598         if part[2:] == '\t':
  2600         if part[2:] == '\t':
  2599             l = 'diff.tab'
  2601             l = 'diff.tab'
  2600         if l == label: # contiguous token with same label
  2602         if l == label: # contiguous token with same label
  2601             token += part[2:]
  2603             token += part[2:]