diff --git a/clang/tools/clang-format/clang-format.py b/clang/tools/clang-format/clang-format.py --- a/clang/tools/clang-format/clang-format.py +++ b/clang/tools/clang-format/clang-format.py @@ -71,7 +71,7 @@ encoding = vim.eval("&encoding") buf = get_buffer(encoding) # Join the buffer into a single string with a terminating newline - text = '\n'.join(buf) + '\n' + text = ('\n'.join(buf) + '\n').encode(encoding) # Determine range to format. if vim.eval('exists("l:lines")') == '1': @@ -90,9 +90,14 @@ lines = ['-lines', '%s:%s' % (vim.current.range.start + 1, vim.current.range.end + 1)] - # Determine the cursor position. - cursor = int(vim.eval('line2byte(line("."))+col(".")')) - 2 - if cursor < 0: + # Convert cursor (line, col) to bytes. + # Don't use line2byte: https://github.com/vim/vim/issues/5930 + _, cursor_line, cursor_col, _ = vim.eval('getpos(".")') # 1-based + 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 @@ -104,7 +109,7 @@ startupinfo.wShowWindow = subprocess.SW_HIDE # Call formatter. - command = [binary, '-cursor', str(cursor)] + command = [binary, '-cursor', str(cursor_byte)] if lines != ['-lines', 'all']: command += lines if style: @@ -116,7 +121,7 @@ p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, startupinfo=startupinfo) - stdout, stderr = p.communicate(input=text.encode(encoding)) + stdout, stderr = p.communicate(input=text) # If successful, replace buffer contents. if stderr: @@ -128,18 +133,24 @@ 'Please report to bugs.llvm.org.' ) else: - lines = stdout.decode(encoding).split('\n') - output = json.loads(lines[0]) + header, content = stdout.split(b'\n', 1) + header = json.loads(header) # Strip off the trailing newline (added above). # This maintains trailing empty lines present in the buffer if # the -lines specification requests them to remain unchanged. - lines = lines[1:-1] + 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 output.get('IncompleteFormat'): + if header.get('IncompleteFormat'): print('clang-format: incomplete (syntax errors)') - vim.command('goto %d' % (output['Cursor'] + 1)) + # Convert cursor bytes to (line, col) + # Don't use goto: https://github.com/vim/vim/issues/5930 + 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()