Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 46 additions & 11 deletions autoload/codefmt/clangformat.vim
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,36 @@ function! s:ClangFormatHasAtLeastVersion(minimum_version) abort
endfunction


" Inputs are 1-based (row, col) coordinates into lines.
" Returns the corresponding zero-based offset into lines->join("\n")
function! s:PositionToOffset(row, col, lines) abort
let l:offset = a:col - 1 " 1-based to 0-based
if a:row > 1
for l:line in a:lines[0 : a:row - 2] " 1-based to 0-based, exclude current
let l:offset += len(l:line) + 1 " +1 for newline
endfor
endif
return l:offset
endfunction


" Input is zero-based offset into lines->join("\n")
" Returns the 1-based [row, col] coordinates into lines.
function! s:OffsetToPosition(offset, lines) abort
let l:lines_consumed = 0
let l:chars_left = a:offset
for l:line in a:lines
let l:line_len = len(l:line) + 1 " +1 for newline
if l:chars_left < l:line_len
break
endif
let l:chars_left -= l:line_len
let l:lines_consumed += 1
endfor
return [l:lines_consumed + 1, l:chars_left + 1] " 0-based to 1-based
endfunction


""
" @private
" Invalidates the cached clang-format version.
Expand Down Expand Up @@ -120,32 +150,37 @@ function! codefmt#clangformat#GetFormatter() abort
let l:cmd += ['-lines', l:startline . ':' . l:endline]
endfor

let l:lines = getline(1, line('$'))

" Version 3.4 introduced support for cursor tracking
" http://llvm.org/releases/3.4/tools/clang/docs/ClangFormat.html
let l:supports_cursor = s:ClangFormatHasAtLeastVersion([3, 4])
if l:supports_cursor
" line2byte counts bytes from 1, and col counts from 1, so -2
let l:cursor_pos = line2byte(line('.')) + col('.') - 2
" Avoid line2byte: https://github.com/vim/vim/issues/5930
let l:cursor_pos = s:PositionToOffset(line('.'), col('.'), l:lines)
let l:cmd += ['-cursor', string(l:cursor_pos)]
endif

let l:input = join(getline(1, line('$')), "\n")
let l:input = join(l:lines, "\n")
let l:result = maktaba#syscall#Create(l:cmd).WithStdin(l:input).Call()
let l:formatted = split(l:result.stdout, "\n")

if !l:supports_cursor
call maktaba#buffer#Overwrite(1, line('$'), l:formatted[0:])
else
call maktaba#buffer#Overwrite(1, line('$'), l:formatted[1:])
if l:supports_cursor
" With -cursor, the first line is a JSON object.
let l:header = remove(l:formatted, 0)
call maktaba#buffer#Overwrite(1, line('$'), l:formatted)
try
let l:clang_format_output_json = maktaba#json#Parse(l:formatted[0])
let l:new_cursor_pos =
\ maktaba#ensure#IsNumber(l:clang_format_output_json.Cursor) + 1
execute 'goto' l:new_cursor_pos
let l:header_json = maktaba#json#Parse(l:header)
let l:offset = maktaba#ensure#IsNumber(l:header_json.Cursor)
" Compute line/col, avoid goto: https://github.com/vim/vim/issues/5930
let [l:new_line, l:new_col] = s:OffsetToPosition(l:offset, l:formatted)
call cursor(l:new_line, l:new_col)
catch
call maktaba#error#Warn('Unable to parse clang-format cursor pos: %s',
\ v:exception)
endtry
else
call maktaba#buffer#Overwrite(1, line('$'), l:formatted)
endif
endfunction

Expand Down
26 changes: 26 additions & 0 deletions vroom/clangformat.vroom
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,33 @@ that clang-format has a version >= 3.4).
:echomsg getline('.')[col('.')-1]
~ 5

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

@clear
% int f() {<CR>
| int i=1;<CR>
| return 1234567890; }<CR>
:call prop_type_add('keyword', {})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, these make the vroom tests blow up on older versions of vim: https://travis-ci.org/github/google/vim-codefmt/jobs/680186570.

Can you change those to only conditionally add the props if vim supports them? And then IIUC the rest of the test should pass regardless on older vims, just won't be covering your workaround logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, sorry about that. Sent #150

:call prop_add(1, 1, {'length': 3, 'type': 'keyword'})
:call cursor(2, 10)
:echomsg getline('.')[col('.')-1]
~ =
:FormatCode clang-format
! clang-format -style file .* -cursor 23 .*2>.*
$ { "Cursor": 18 }
$ int f() {
$ int i = 1;
$ return 1234567890;
$ }
int f() {
int i = 1;
return 1234567890;
}
@end
:echomsg getline('.')[col('.')-1]
~ =

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