@@ -55,6 +55,36 @@ function! s:ClangFormatHasAtLeastVersion(minimum_version) abort
5555endfunction
5656
5757
58+ " Inputs are 1-based (row, col) coordinates into lines.
59+ " Returns the corresponding zero-based offset into lines->join("\n")
60+ function ! s: PositionToOffset (row, col , lines ) abort
61+ let l: offset = a: col - 1 " 1-based to 0-based
62+ if a: row > 1
63+ for l: line in a: lines [0 : a: row - 2 ] " 1-based to 0-based, exclude current
64+ let l: offset += len (l: line ) + 1 " +1 for newline
65+ endfor
66+ endif
67+ return l: offset
68+ endfunction
69+
70+
71+ " Input is zero-based offset into lines->join("\n")
72+ " Returns the 1-based [row, col] coordinates into lines.
73+ function ! s: OffsetToPosition (offset, lines ) abort
74+ let l: lines_consumed = 0
75+ let l: chars_left = a: offset
76+ for l: line in a: lines
77+ let l: line_len = len (l: line ) + 1 " +1 for newline
78+ if l: chars_left < l: line_len
79+ break
80+ endif
81+ let l: chars_left -= l: line_len
82+ let l: lines_consumed += 1
83+ endfor
84+ return [l: lines_consumed + 1 , l: chars_left + 1 ] " 0-based to 1-based
85+ endfunction
86+
87+
5888" "
5989" @private
6090" Invalidates the cached clang-format version.
@@ -120,32 +150,37 @@ function! codefmt#clangformat#GetFormatter() abort
120150 let l: cmd += [' -lines' , l: startline . ' :' . l: endline ]
121151 endfor
122152
153+ let l: lines = getline (1 , line (' $' ))
154+
123155 " Version 3.4 introduced support for cursor tracking
124156 " http://llvm.org/releases/3.4/tools/clang/docs/ClangFormat.html
125157 let l: supports_cursor = s: ClangFormatHasAtLeastVersion ([3 , 4 ])
126158 if l: supports_cursor
127- " line2byte counts bytes from 1, and col counts from 1, so -2
128- let l: cursor_pos = line2byte (line (' .' )) + col (' .' ) - 2
159+ " Avoid line2byte: https://github.com/vim/vim/issues/5930
160+ let l: cursor_pos = s: PositionToOffset (line (' .' ), col (' .' ), l: lines )
129161 let l: cmd += [' -cursor' , string (l: cursor_pos )]
130162 endif
131163
132- let l: input = join (getline ( 1 , line ( ' $ ' )) , " \n " )
164+ let l: input = join (l: lines , " \n " )
133165 let l: result = maktaba#syscall#Create (l: cmd ).WithStdin (l: input ).Call ()
134166 let l: formatted = split (l: result .stdout, " \n " )
135167
136- if ! l: supports_cursor
137- call maktaba#buffer#Overwrite ( 1 , line ( ' $ ' ), l: formatted [ 0 :])
138- else
139- call maktaba#buffer#Overwrite (1 , line (' $' ), l: formatted[ 1 :] )
168+ if l: supports_cursor
169+ " With -cursor, the first line is a JSON object.
170+ let l: header = remove ( l: formatted , 0 )
171+ call maktaba#buffer#Overwrite (1 , line (' $' ), l: formatted )
140172 try
141- let l: clang_format_output_json = maktaba#json#Parse (l: formatted [0 ])
142- let l: new_cursor_pos =
143- \ maktaba#ensure#IsNumber (l: clang_format_output_json .Cursor ) + 1
144- execute ' goto' l: new_cursor_pos
173+ let l: header_json = maktaba#json#Parse (l: header )
174+ let l: offset = maktaba#ensure#IsNumber (l: header_json .Cursor )
175+ " Compute line/col, avoid goto: https://github.com/vim/vim/issues/5930
176+ let [l: new_line , l: new_col ] = s: OffsetToPosition (l: offset , l: formatted )
177+ call cursor (l: new_line , l: new_col )
145178 catch
146179 call maktaba#error#Warn (' Unable to parse clang-format cursor pos: %s' ,
147180 \ v: exception )
148181 endtry
182+ else
183+ call maktaba#buffer#Overwrite (1 , line (' $' ), l: formatted )
149184 endif
150185 endfunction
151186
0 commit comments