Skip to content

Commit c8e76bd

Browse files
committed
Allowing passing of ranges directly to formatting tools
Neoformat supports formatting only part of a file, but it just passes that chunk to formatting tools. A lot of tools need the context of the surrounding lines, but support passing the requested range as an argument. This commit adds support for ranges by allowing certain variables to be substituted in the arguments. In that case the 'range' option should be set to '1' to indicate that the tool itself will handle the range.
1 parent 1c27419 commit c8e76bd

4 files changed

Lines changed: 78 additions & 9 deletions

File tree

autoload/neoformat.vim

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,20 +75,42 @@ function! s:neoformat(bang, user_input, start_line, end_line) abort
7575
continue
7676
endif
7777

78-
let stdin = getbufline(bufnr('%'), a:start_line, a:end_line)
78+
if cmd.range
79+
" Pass the entire buffer, the formatter itself takes a range.
80+
let stdin = getbufline(bufnr('%'), 1, '$')
81+
else
82+
let lines_after = getbufline(bufnr('%'), a:end_line + 1, '$')
83+
let lines_before = getbufline(bufnr('%'), 1, a:start_line - 1)
84+
let stdin = getbufline(bufnr('%'), a:start_line, a:end_line)
85+
end
86+
7987
let original_buffer = getbufline(bufnr('%'), 1, '$')
8088

89+
let exe = cmd.exe
90+
let replacements = {
91+
\ 'start_byte': line2byte(a:start_line),
92+
\ 'end_byte': line2byte(a:end_line),
93+
\ 'bytes': line2byte(a:end_line) - line2byte(a:start_line),
94+
\ 'start_line': a:start_line,
95+
\ 'end_line': a:end_line,
96+
\ 'lines': a:end_line - a:start_line,
97+
\ }
98+
99+
for [key, value] in items(replacements)
100+
let exe = substitute(exe, '<'.key.'>', value, 'g')
101+
endfor
102+
81103
call neoformat#utils#log(stdin)
82104

83-
call neoformat#utils#log(cmd.exe)
105+
call neoformat#utils#log(exe)
84106
if cmd.stdin
85107
call neoformat#utils#log('using stdin')
86108
let stdin_str = join(stdin, "\n")
87-
let stdout = split(system(cmd.exe, stdin_str), '\n')
109+
let stdout = split(system(exe, stdin_str), '\n')
88110
else
89111
call neoformat#utils#log('using tmp file')
90112
call writefile(stdin, cmd.tmp_file_path)
91-
let stdout = split(system(cmd.exe), '\n')
113+
let stdout = split(system(exe), '\n')
92114
endif
93115

94116
" read from /tmp file if formatter replaces file on format
@@ -103,11 +125,15 @@ function! s:neoformat(bang, user_input, start_line, end_line) abort
103125

104126
let process_ran_succesfully = index(cmd.valid_exit_codes, v:shell_error) != -1
105127
if process_ran_succesfully
106-
" 1. append the lines that are before and after the formatterd content
107-
let lines_after = getbufline(bufnr('%'), a:end_line + 1, '$')
108-
let lines_before = getbufline(bufnr('%'), 1, a:start_line - 1)
128+
if cmd.range
129+
let new_buffer = stdout
130+
else
131+
" 1. append the lines that are before and after the formatterd content
132+
let lines_after = getbufline(bufnr('%'), a:end_line + 1, '$')
133+
let lines_before = getbufline(bufnr('%'), 1, a:start_line - 1)
134+
let new_buffer = lines_before + stdout + lines_after
135+
endif
109136

110-
let new_buffer = lines_before + stdout + lines_after
111137
if new_buffer !=# original_buffer
112138

113139
call s:deletelines(len(new_buffer), line('$'))
@@ -257,6 +283,7 @@ function! s:generate_cmd(definition, filetype) abort
257283
\ 'name': a:definition.exe,
258284
\ 'replace': get(a:definition, 'replace', 0),
259285
\ 'tmp_file_path': path,
286+
\ 'range': get(a:definition, 'range', 0),
260287
\ 'valid_exit_codes': get(a:definition, 'valid_exit_codes', [0]),
261288
\ }
262289
endfunction

autoload/neoformat/formatters/javascript.vim

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,15 @@ endfunction
3939
function! neoformat#formatters#javascript#prettier() abort
4040
return {
4141
\ 'exe': 'prettier',
42-
\ 'args': ['--stdin', '--stdin-filepath', '%:p'],
42+
\ 'args': ['--stdin',
43+
\ '--stdin-filepath',
44+
\ '%:p',
45+
\ '--range-start',
46+
\ '<start_byte>',
47+
\ '--range-end',
48+
\ '<end_byte>'],
4349
\ 'stdin': 1,
50+
\ 'range': 1,
4451
\ }
4552
endfunction
4653

autoload/neoformat/formatters/python.vim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ endfunction
55
function! neoformat#formatters#python#yapf() abort
66
return {
77
\ 'exe': 'yapf',
8+
\ 'args': ['--lines', '<start_line>-<end_line>'],
89
\ 'stdin': 1,
10+
\ 'range': 1,
911
\ }
1012
endfunction
1113

doc/neoformat.txt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Introduction |neoformat-introduction|
66
Install |neoformat-install|
77
Usage |neoformat-usage|
88
Managing Undo History |neoformat-managing-undo-history|
9+
Argument Templates neoformat-argument-templates
910
Supported Filetypes |neoformat-supported-filetypes|
1011

1112
==============================================================================
@@ -89,6 +90,9 @@ Options:
8990
| `args` | list of arguments | default: [] | optional
9091
| `replace` | overwrite the file, instead of updating the buffer | default: 0 | optional
9192
| `stdin` | send data to the stdin of the formatter | default 0 | optional
93+
| `range` | formatter takes range as argument when using visual formatting. when set to 1, the entire buffer
94+
will be passed in, the range shoudl be passed as an argument to the formatter |
95+
default: 0 | optional
9296
| `no_append` | do not append the `path` of the file to the formatter command,
9397
used when the `path` is in the middle of a command | default: 0 |
9498
optional
@@ -199,6 +203,35 @@ When |undojoin| is used this way pressing |u| will "skip over" the Neoformat
199203
changes - it will revert both the changes made by Neoformat and the change
200204
that caused Neoformat to be invoked.
201205

206+
==============================================================================
207+
ARGUMENT TEMPLATES *neoformat-argument-templates*
208+
209+
The following strings will be expanded in the 'args' field:
210+
211+
- <start_line> - starting line of range
212+
- <end_line> - ending line of range
213+
- <lines> - number of lines in range
214+
- <start_byte> - starting byte of range (from line2byte)
215+
- <end_byte> - ending byte of range (from line2byte)
216+
- <bytes> - number of bytes in range
217+
- any expressions supported by |expand()|
218+
219+
Example:
220+
221+
let g:neoformat_cpp_clangformat = {
222+
\ 'exe': 'clang-format',
223+
\ 'args': ['-lines=<start_line>:<end_line>'],
224+
\ 'range': 1,
225+
\ 'stdin', 1,
226+
\ }
227+
228+
let g:neoformat_cpp_clangformat = {
229+
\ 'exe': 'clang-format',
230+
\ 'args': ['-offset=<start_byte>', '-length=<bytes>'],
231+
\ 'range': 1,
232+
\ 'stdin', 1,
233+
\ }
234+
202235
==============================================================================
203236
SUPPORTED FILETYPES *neoformat-supported-filetypes*
204237

0 commit comments

Comments
 (0)