[docs] Add LICENSE.txt to the root of the mono-repo
[llvm-project.git] / clang / tools / clang-format / clang-format.py
blob76fedb6481474594612a81be25a4073a96c3d44a
1 # This file is a minimal clang-format vim-integration. To install:
2 # - Change 'binary' if clang-format is not on the path (see below).
3 # - Add to your .vimrc:
5 # if has('python')
6 # map <C-I> :pyf <path-to-this-file>/clang-format.py<cr>
7 # imap <C-I> <c-o>:pyf <path-to-this-file>/clang-format.py<cr>
8 # elseif has('python3')
9 # map <C-I> :py3f <path-to-this-file>/clang-format.py<cr>
10 # imap <C-I> <c-o>:py3f <path-to-this-file>/clang-format.py<cr>
11 # endif
13 # The if-elseif-endif conditional should pick either the python3 or python2
14 # integration depending on your vim setup.
16 # The first mapping enables clang-format for NORMAL and VISUAL mode, the second
17 # mapping adds support for INSERT mode. Change "C-I" to another binding if you
18 # need clang-format on a different key (C-I stands for Ctrl+i).
20 # With this integration you can press the bound key and clang-format will
21 # format the current line in NORMAL and INSERT mode or the selected region in
22 # VISUAL mode. The line or region is extended to the next bigger syntactic
23 # entity.
25 # You can also pass in the variable "l:lines" to choose the range for
26 # formatting. This variable can either contain "<start line>:<end line>" or
27 # "all" to format the full file. So, to format the full file, write a function
28 # like:
29 # :function FormatFile()
30 # : let l:lines="all"
31 # : if has('python')
32 # : pyf <path-to-this-file>/clang-format.py
33 # : elseif has('python3')
34 # : py3f <path-to-this-file>/clang-format.py
35 # : endif
36 # :endfunction
38 # It operates on the current, potentially unsaved buffer and does not create
39 # or save any files. To revert a formatting, just undo.
40 from __future__ import absolute_import, division, print_function
42 import difflib
43 import json
44 import platform
45 import subprocess
46 import sys
47 import vim
49 # set g:clang_format_path to the path to clang-format if it is not on the path
50 # Change this to the full path if clang-format is not on the path.
51 binary = 'clang-format'
52 if vim.eval('exists("g:clang_format_path")') == "1":
53 binary = vim.eval('g:clang_format_path')
55 # Change this to format according to other formatting styles. See the output of
56 # 'clang-format --help' for a list of supported styles. The default looks for
57 # a '.clang-format' or '_clang-format' file to indicate the style that should be
58 # used.
59 style = None
60 fallback_style = None
61 if vim.eval('exists("g:clang_format_fallback_style")') == "1":
62 fallback_style = vim.eval('g:clang_format_fallback_style')
64 def get_buffer(encoding):
65 if platform.python_version_tuple()[0] == '3':
66 return vim.current.buffer
67 return [ line.decode(encoding) for line in vim.current.buffer ]
69 def main():
70 # Get the current text.
71 encoding = vim.eval("&encoding")
72 buf = get_buffer(encoding)
73 # Join the buffer into a single string with a terminating newline
74 text = ('\n'.join(buf) + '\n').encode(encoding)
76 # Determine range to format.
77 if vim.eval('exists("l:lines")') == '1':
78 lines = ['-lines', vim.eval('l:lines')]
79 elif vim.eval('exists("l:formatdiff")') == '1':
80 with open(vim.current.buffer.name, 'r') as f:
81 ondisk = f.read().splitlines();
82 sequence = difflib.SequenceMatcher(None, ondisk, vim.current.buffer)
83 lines = []
84 for op in reversed(sequence.get_opcodes()):
85 if op[0] not in ['equal', 'delete']:
86 lines += ['-lines', '%s:%s' % (op[3] + 1, op[4])]
87 if lines == []:
88 return
89 else:
90 lines = ['-lines', '%s:%s' % (vim.current.range.start + 1,
91 vim.current.range.end + 1)]
93 # Convert cursor (line, col) to bytes.
94 # Don't use line2byte: https://github.com/vim/vim/issues/5930
95 _, cursor_line, cursor_col, _ = vim.eval('getpos(".")') # 1-based
96 cursor_byte = 0
97 for line in text.split(b'\n')[:int(cursor_line) - 1]:
98 cursor_byte += len(line) + 1
99 cursor_byte += int(cursor_col) - 1
100 if cursor_byte < 0:
101 print('Couldn\'t determine cursor position. Is your file empty?')
102 return
104 # Avoid flashing an ugly, ugly cmd prompt on Windows when invoking clang-format.
105 startupinfo = None
106 if sys.platform.startswith('win32'):
107 startupinfo = subprocess.STARTUPINFO()
108 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
109 startupinfo.wShowWindow = subprocess.SW_HIDE
111 # Call formatter.
112 command = [binary, '-cursor', str(cursor_byte)]
113 if lines != ['-lines', 'all']:
114 command += lines
115 if style:
116 command.extend(['-style', style])
117 if fallback_style:
118 command.extend(['-fallback-style', fallback_style])
119 if vim.current.buffer.name:
120 command.extend(['-assume-filename', vim.current.buffer.name])
121 p = subprocess.Popen(command,
122 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
123 stdin=subprocess.PIPE, startupinfo=startupinfo)
124 stdout, stderr = p.communicate(input=text)
126 # If successful, replace buffer contents.
127 if stderr:
128 print(stderr)
130 if not stdout:
131 print(
132 'No output from clang-format (crashed?).\n'
133 'Please report to bugs.llvm.org.'
135 else:
136 header, content = stdout.split(b'\n', 1)
137 header = json.loads(header)
138 # Strip off the trailing newline (added above).
139 # This maintains trailing empty lines present in the buffer if
140 # the -lines specification requests them to remain unchanged.
141 lines = content.decode(encoding).split('\n')[:-1]
142 sequence = difflib.SequenceMatcher(None, buf, lines)
143 for op in reversed(sequence.get_opcodes()):
144 if op[0] != 'equal':
145 vim.current.buffer[op[1]:op[2]] = lines[op[3]:op[4]]
146 if header.get('IncompleteFormat'):
147 print('clang-format: incomplete (syntax errors)')
148 # Convert cursor bytes to (line, col)
149 # Don't use goto: https://github.com/vim/vim/issues/5930
150 cursor_byte = int(header['Cursor'])
151 prefix = content[0:cursor_byte]
152 cursor_line = 1 + prefix.count(b'\n')
153 cursor_column = 1 + len(prefix.rsplit(b'\n', 1)[-1])
154 vim.command('call cursor(%d, %d)' % (cursor_line, cursor_column))
156 main()