clang-format-diff.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. #!/usr/bin/python
  2. #
  3. #===- clang-format-diff.py - ClangFormat Diff Reformatter ----*- python -*--===#
  4. #
  5. # The LLVM Compiler Infrastructure
  6. #
  7. # This file is distributed under the University of Illinois Open Source
  8. # License. See LICENSE.TXT for details.
  9. #
  10. #===------------------------------------------------------------------------===#
  11. r"""
  12. ClangFormat Diff Reformatter
  13. ============================
  14. This script reads input from a unified diff and reformats all the changed
  15. lines. This is useful to reformat all the lines touched by a specific patch.
  16. Example usage for git users:
  17. git diff -U0 HEAD^ | clang-format-diff.py -p1
  18. """
  19. import argparse
  20. import re
  21. import subprocess
  22. import sys
  23. # Change this to the full path if clang-format is not on the path.
  24. binary = 'clang-format'
  25. def main():
  26. parser = argparse.ArgumentParser(description=
  27. 'Reformat changed lines in diff.')
  28. parser.add_argument('-p', default=0,
  29. help='strip the smallest prefix containing P slashes')
  30. parser.add_argument(
  31. '-style',
  32. help=
  33. 'formatting style to apply (LLVM, Google, Chromium, Mozilla, WebKit)')
  34. args = parser.parse_args()
  35. # Extract changed lines for each file.
  36. filename = None
  37. lines_by_file = {}
  38. for line in sys.stdin:
  39. match = re.search('^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line)
  40. if match:
  41. filename = match.group(2)
  42. if filename == None:
  43. continue
  44. # FIXME: Add other types containing C++/ObjC code.
  45. if not (filename.endswith(".cpp") or filename.endswith(".cc") or
  46. filename.endswith(".h")):
  47. continue
  48. match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
  49. if match:
  50. start_line = int(match.group(1))
  51. line_count = 1
  52. if match.group(3):
  53. line_count = int(match.group(3))
  54. if line_count == 0:
  55. continue
  56. end_line = start_line + line_count - 1;
  57. lines_by_file.setdefault(filename, []).extend(
  58. ['-lines', str(start_line) + ':' + str(end_line)])
  59. # Reformat files containing changes in place.
  60. for filename, lines in lines_by_file.iteritems():
  61. command = [binary, '-i', filename]
  62. command.extend(lines)
  63. if args.style:
  64. command.extend(['-style', args.style])
  65. p = subprocess.Popen(command, stdout=subprocess.PIPE,
  66. stderr=subprocess.PIPE,
  67. stdin=subprocess.PIPE)
  68. stdout, stderr = p.communicate()
  69. if stderr:
  70. print stderr
  71. return
  72. if __name__ == '__main__':
  73. main()