[PATCH] D78198: [Format] Work around current vim bugs in clang-format.py

Sam McCall via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 15 06:32:32 PDT 2020


sammccall created this revision.
sammccall added a reviewer: hokein.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Do line/col to byte conversions on the python side rather than relying on vim.
Its calculations are off when text annotations are present:

- https://github.com/vim/vim/issues/5930
- https://github.com/vim/vim/issues/3718 (fixed, but vim 8.1 is still common)


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D78198

Files:
  clang/tools/clang-format/clang-format.py


Index: clang/tools/clang-format/clang-format.py
===================================================================
--- clang/tools/clang-format/clang-format.py
+++ 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()


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D78198.257693.patch
Type: text/x-patch
Size: 3107 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200415/bb524b6f/attachment-0001.bin>


More information about the cfe-commits mailing list