diff options
Diffstat (limited to 'tools/clang-format/clang-format-diff.py')
-rwxr-xr-x | tools/clang-format/clang-format-diff.py | 118 |
1 files changed, 55 insertions, 63 deletions
diff --git a/tools/clang-format/clang-format-diff.py b/tools/clang-format/clang-format-diff.py index 68b5113..60b8fb7 100755 --- a/tools/clang-format/clang-format-diff.py +++ b/tools/clang-format/clang-format-diff.py @@ -17,13 +17,16 @@ This script reads input from a unified diff and reformats all the changed lines. This is useful to reformat all the lines touched by a specific patch. Example usage for git users: - git diff -U0 HEAD^ | clang-format-diff.py -p1 + git diff -U0 HEAD^ | clang-format-diff.py -p1 -i """ import argparse +import difflib import re +import string import subprocess +import StringIO import sys @@ -31,67 +34,24 @@ import sys binary = 'clang-format' -def getOffsetLength(filename, line_number, line_count): - """ - Calculates the field offset and length based on line number and count. - """ - offset = 0 - length = 0 - with open(filename, 'r') as f: - for line in f: - if line_number > 1: - offset += len(line) - line_number -= 1 - elif line_count > 0: - length += len(line) - line_count -= 1 - else: - break - return offset, length - - -def formatRange(r, style): - """ - Formats range 'r' according to style 'style'. - """ - filename, line_number, line_count = r - # FIXME: Add other types containing C++/ObjC code. - if not (filename.endswith(".cpp") or filename.endswith(".cc") or - filename.endswith(".h")): - return - - offset, length = getOffsetLength(filename, line_number, line_count) - with open(filename, 'r') as f: - text = f.read() - command = [binary, '-offset', str(offset), '-length', str(length)] - if style: - command.extend(['-style', style]) - p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - stdin=subprocess.PIPE) - stdout, stderr = p.communicate(input=text) - if stderr: - print stderr - return - if not stdout: - print 'Segfault occurred while formatting', filename - print 'Please report a bug on llvm.org/bugs.' - return - with open(filename, 'w') as f: - f.write(stdout) - - def main(): parser = argparse.ArgumentParser(description= - 'Reformat changed lines in diff') - parser.add_argument('-p', default=1, + 'Reformat changed lines in diff. Without -i ' + 'option just output the diff that would be' + 'introduced.') + parser.add_argument('-i', action='store_true', default=False, + help='apply edits to files instead of displaying a diff') + parser.add_argument('-p', default=0, help='strip the smallest prefix containing P slashes') - parser.add_argument('-style', - help='formatting style to apply (LLVM, Google, Chromium)') + parser.add_argument( + '-style', + help= + 'formatting style to apply (LLVM, Google, Chromium, Mozilla, WebKit)') args = parser.parse_args() + # Extract changed lines for each file. filename = None - ranges = [] - + lines_by_file = {} for line in sys.stdin: match = re.search('^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line) if match: @@ -99,18 +59,50 @@ def main(): if filename == None: continue + # FIXME: Add other types containing C++/ObjC code. + if not (filename.endswith(".cpp") or filename.endswith(".cc") or + filename.endswith(".h")): + continue + match = re.search('^@@.*\+(\d+)(,(\d+))?', line) if match: + start_line = int(match.group(1)) line_count = 1 if match.group(3): line_count = int(match.group(3)) - ranges.append((filename, int(match.group(1)), line_count)) - - # Reverse the ranges so that the reformatting does not influence file offsets. - for r in reversed(ranges): - # Do the actual formatting. - formatRange(r, args.style) - + if line_count == 0: + continue + end_line = start_line + line_count - 1; + lines_by_file.setdefault(filename, []).extend( + ['-lines', str(start_line) + ':' + str(end_line)]) + + # Reformat files containing changes in place. + for filename, lines in lines_by_file.iteritems(): + command = [binary, filename] + if args.i: + command.append('-i') + command.extend(lines) + if args.style: + command.extend(['-style', args.style]) + p = subprocess.Popen(command, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE) + stdout, stderr = p.communicate() + if stderr: + print stderr + if p.returncode != 0: + sys.exit(p.returncode); + + if not args.i: + with open(filename) as f: + code = f.readlines() + formatted_code = StringIO.StringIO(stdout).readlines() + diff = difflib.unified_diff(code, formatted_code, + filename, filename, + '(before formatting)', '(after formatting)') + diff_string = string.join(diff, '') + if len(diff_string) > 0: + print diff_string if __name__ == '__main__': main() |