Skip to content

Commit d8dd427

Browse files
authored
Merge pull request #145 from sam-mccall/fix
clang-format: work around vim/vim#5930 when positioning cursor
2 parents 37c401b + eac7b92 commit d8dd427

File tree

2 files changed

+72
-11
lines changed

2 files changed

+72
-11
lines changed

autoload/codefmt/clangformat.vim

+46-11
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,36 @@ function! s:ClangFormatHasAtLeastVersion(minimum_version) abort
5555
endfunction
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

vroom/clangformat.vroom

+26
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,33 @@ that clang-format has a version >= 3.4).
178178
:echomsg getline('.')[col('.')-1]
179179
~ 5
180180

181+
This should work when with textprops set in the file, despite various functions
182+
like line2byte() and :goto being buggy in that case.
183+
(See https://github.com/vim/vim/issues/5930 for bug details)
181184

185+
@clear
186+
% int f() {<CR>
187+
| int i=1;<CR>
188+
| return 1234567890; }<CR>
189+
:call prop_type_add('keyword', {})
190+
:call prop_add(1, 1, {'length': 3, 'type': 'keyword'})
191+
:call cursor(2, 10)
192+
:echomsg getline('.')[col('.')-1]
193+
~ =
194+
:FormatCode clang-format
195+
! clang-format -style file .* -cursor 23 .*2>.*
196+
$ { "Cursor": 18 }
197+
$ int f() {
198+
$ int i = 1;
199+
$ return 1234567890;
200+
$ }
201+
int f() {
202+
int i = 1;
203+
return 1234567890;
204+
}
205+
@end
206+
:echomsg getline('.')[col('.')-1]
207+
~ =
182208

183209
You might have wondered where the "-style file" above comes from. The
184210
clang-format tool accepts a "style" option to control the formatting style. By

0 commit comments

Comments
 (0)