from __future__ import absolute_import, division, print_function
import difflib
import json
import platform
import subprocess
import sys
import vim
binary = 'clang-format'
if vim.eval('exists("g:clang_format_path")') == "1":
binary = vim.eval('g:clang_format_path')
style = None
fallback_style = None
if vim.eval('exists("g:clang_format_fallback_style")') == "1":
fallback_style = vim.eval('g:clang_format_fallback_style')
def get_buffer(encoding):
if platform.python_version_tuple()[0] == '3':
return vim.current.buffer
return [ line.decode(encoding) for line in vim.current.buffer ]
def main():
encoding = vim.eval("&encoding")
buf = get_buffer(encoding)
text = ('\n'.join(buf) + '\n').encode(encoding)
if vim.eval('exists("l:lines")') == '1':
lines = ['-lines', vim.eval('l:lines')]
elif vim.eval('exists("l:formatdiff")') == '1':
with open(vim.current.buffer.name, 'r') as f:
ondisk = f.read().splitlines();
sequence = difflib.SequenceMatcher(None, ondisk, vim.current.buffer)
lines = []
for op in reversed(sequence.get_opcodes()):
if op[0] not in ['equal', 'delete']:
lines += ['-lines', '%s:%s' % (op[3] + 1, op[4])]
if lines == []:
return
else:
lines = ['-lines', '%s:%s' % (vim.current.range.start + 1,
vim.current.range.end + 1)]
_, cursor_line, cursor_col, _ = vim.eval('getpos(".")') cursor_byte = 0
for line in text.split(b'\n')[:int(cursor_line) - 1]:
cursor_byte += len(line) + 1
cursor_byte += int(cursor_col) - 1
if cursor_byte < 0:
print('Couldn\'t determine cursor position. Is your file empty?')
return
startupinfo = None
if sys.platform.startswith('win32'):
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
command = [binary, '-cursor', str(cursor_byte)]
if lines != ['-lines', 'all']:
command += lines
if style:
command.extend(['-style', style])
if fallback_style:
command.extend(['-fallback-style', fallback_style])
if vim.current.buffer.name:
command.extend(['-assume-filename', vim.current.buffer.name])
p = subprocess.Popen(command,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
stdin=subprocess.PIPE, startupinfo=startupinfo)
stdout, stderr = p.communicate(input=text)
if stderr:
print(stderr)
if not stdout:
print(
'No output from clang-format (crashed?).\n'
'Please report to bugs.llvm.org.'
)
else:
header, content = stdout.split(b'\n', 1)
header = json.loads(header)
lines = content.decode(encoding).split('\n')[:-1]
sequence = difflib.SequenceMatcher(None, buf, lines)
for op in reversed(sequence.get_opcodes()):
if op[0] != 'equal':
vim.current.buffer[op[1]:op[2]] = lines[op[3]:op[4]]
if header.get('IncompleteFormat'):
print('clang-format: incomplete (syntax errors)')
cursor_byte = int(header['Cursor'])
prefix = content[0:cursor_byte]
cursor_line = 1 + prefix.count(b'\n')
cursor_column = 1 + len(prefix.rsplit(b'\n', 1)[-1])
vim.command('call cursor(%d, %d)' % (cursor_line, cursor_column))
main()