@@ -55,6 +55,36 @@ function! s:ClangFormatHasAtLeastVersion(minimum_version) abort
55
55
endfunction
56
56
57
57
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
+
58
88
" "
59
89
" @private
60
90
" Invalidates the cached clang-format version.
@@ -120,32 +150,37 @@ function! codefmt#clangformat#GetFormatter() abort
120
150
let l: cmd += [' -lines' , l: startline . ' :' . l: endline ]
121
151
endfor
122
152
153
+ let l: lines = getline (1 , line (' $' ))
154
+
123
155
" Version 3.4 introduced support for cursor tracking
124
156
" http://llvm.org/releases/3.4/tools/clang/docs/ClangFormat.html
125
157
let l: supports_cursor = s: ClangFormatHasAtLeastVersion ([3 , 4 ])
126
158
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 )
129
161
let l: cmd += [' -cursor' , string (l: cursor_pos )]
130
162
endif
131
163
132
- let l: input = join (getline ( 1 , line ( ' $ ' )) , " \n " )
164
+ let l: input = join (l: lines , " \n " )
133
165
let l: result = maktaba#syscall#Create (l: cmd ).WithStdin (l: input ).Call ()
134
166
let l: formatted = split (l: result .stdout, " \n " )
135
167
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 )
140
172
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 )
145
178
catch
146
179
call maktaba#error#Warn (' Unable to parse clang-format cursor pos: %s' ,
147
180
\ v: exception )
148
181
endtry
182
+ else
183
+ call maktaba#buffer#Overwrite (1 , line (' $' ), l: formatted )
149
184
endif
150
185
endfunction
151
186
0 commit comments