Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allowing passing of ranges directly to formatting tools #188

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,18 +86,20 @@ Options:
| `no_append` | do not append the `path` of the file to the formatter command, used when the `path` is in the middle of a command | 0 | optional |
| `env` | list of environment variable definitions to be prepended to the formatter command | \[] | optional |
| `valid_exit_codes` | list of valid exit codes for formatters who do not respect common unix practices | \[0] | optional |
| `range_mode` | determines behavior when a range is used with Neoformat | 0 | optional |

Example:

```viml
let g:neoformat_python_autopep8 = {
\ 'exe': 'autopep8',
\ 'args': ['-s 4', '-E'],
\ 'args': ['-s 4', '-E', '--range <start_line> <end_line>'],
\ 'replace': 1 " replace the file, instead of updating buffer (default: 0),
\ 'stdin': 1, " send data to stdin of formatter (default: 0)
\ 'env': ["DEBUG=1"], " prepend environment variables to formatter command
\ 'valid_exit_codes': [0, 23],
\ 'no_append': 1,
\ 'range_mode': 1,
\ }

let g:neoformat_enabled_python = ['autopep8']
Expand Down
42 changes: 34 additions & 8 deletions autoload/neoformat.vim
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,40 @@ function! s:neoformat(bang, user_input, start_line, end_line) abort
continue
endif

let stdin = getbufline(bufnr('%'), a:start_line, a:end_line)
if cmd.range_mode > 0
" Pass the entire buffer, the formatter itself takes a range.
let stdin = getbufline(bufnr('%'), 1, '$')
else
let stdin = getbufline(bufnr('%'), a:start_line, a:end_line)
end

let original_buffer = getbufline(bufnr('%'), 1, '$')

let exe = cmd.exe
let replacements = {
\ 'start_byte': line2byte(a:start_line),
\ 'end_byte': line2byte(a:end_line),
\ 'bytes': line2byte(a:end_line) - line2byte(a:start_line),
\ 'start_line': a:start_line,
\ 'end_line': a:end_line,
\ 'lines': a:end_line - a:start_line,
\ }

for [key, value] in items(replacements)
let exe = substitute(exe, '<'.key.'>', value, 'g')
endfor

call neoformat#utils#log(stdin)

call neoformat#utils#log(cmd.exe)
call neoformat#utils#log(exe)
if cmd.stdin
call neoformat#utils#log('using stdin')
let stdin_str = join(stdin, "\n")
let stdout = split(system(cmd.exe, stdin_str), '\n')
let stdout = split(system(exe, stdin_str), '\n')
else
call neoformat#utils#log('using tmp file')
call writefile(stdin, cmd.tmp_file_path)
let stdout = split(system(cmd.exe), '\n')
let stdout = split(system(exe), '\n')
endif

" read from /tmp file if formatter replaces file on format
Expand All @@ -108,11 +128,16 @@ function! s:neoformat(bang, user_input, start_line, end_line) abort
call neoformat#utils#log_file_content(cmd.stderr_log)
endif
if process_ran_succesfully
" 1. append the lines that are before and after the formatterd content
let lines_after = getbufline(bufnr('%'), a:end_line + 1, '$')
let lines_before = getbufline(bufnr('%'), 1, a:start_line - 1)
if cmd.range_mode == 1
" In range_mode 1, the formatter outputs the entire file contents.
let new_buffer = stdout
else
" 1. append the lines that are before and after the formatterd content
let lines_after = getbufline(bufnr('%'), a:end_line + 1, '$')
let lines_before = getbufline(bufnr('%'), 1, a:start_line - 1)
let new_buffer = lines_before + stdout + lines_after
endif

let new_buffer = lines_before + stdout + lines_after
if new_buffer !=# original_buffer

call s:deletelines(len(new_buffer), line('$'))
Expand Down Expand Up @@ -279,6 +304,7 @@ function! s:generate_cmd(definition, filetype) abort
\ 'name': a:definition.exe,
\ 'replace': get(a:definition, 'replace', 0),
\ 'tmp_file_path': path,
\ 'range_mode': get(a:definition, 'range_mode', 0),
\ 'valid_exit_codes': get(a:definition, 'valid_exit_codes', [0]),
\ }
endfunction
Expand Down
5 changes: 4 additions & 1 deletion autoload/neoformat/formatters/javascript.vim
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ endfunction
function! neoformat#formatters#javascript#prettier() abort
return {
\ 'exe': 'prettier',
\ 'args': ['--stdin', '--stdin-filepath', '"%:p"'],
\ 'args': ['--stdin', '--stdin-filepath', '%:p',
\ '--range-start', '<start_byte>',
\ '--range-end', '<end_byte>'],
\ 'stdin': 1,
\ 'range_mode': 1,
\ }
endfunction

Expand Down
2 changes: 2 additions & 0 deletions autoload/neoformat/formatters/python.vim
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ endfunction
function! neoformat#formatters#python#yapf() abort
return {
\ 'exe': 'yapf',
\ 'args': ['--lines', '<start_line>-<end_line>'],
\ 'stdin': 1,
\ 'range_mode': 1,
\ }
endfunction

Expand Down
42 changes: 42 additions & 0 deletions doc/neoformat.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Introduction |neoformat-introduction|
Install |neoformat-install|
Usage |neoformat-usage|
Managing Undo History |neoformat-managing-undo-history|
Argument Templates |neoformat-argument-templates|
Supported Filetypes |neoformat-supported-filetypes|

==============================================================================
Expand Down Expand Up @@ -92,6 +93,16 @@ Options:
| `stderr` | used to specify whether stderr output should be read along with
the stdin, otherwise redirects stderr to `stderr.log` file in neoformat's
temporary directory | default 0 | optional
| `range_mode` | Sets behavior when neoformat is run with a range (e.g. visual mode).
when using this mode, make sure the range arguments are sent via `args`
(See |neoformat-argument-templates|)
mode 0: only the selected lines are sent to the formatter
mode 1: The range is passed as an argument. the formatter
returns the entire buffer, with only those lines formatted.
mode 2: The range is passed as an argument. the entire file is
sent to the formatter with a range argument. The formatter
returns only the lines that it formatted.
default: 0 | optional
| `no_append` | do not append the `path` of the file to the formatter command,
used when the `path` is in the middle of a command | default: 0 |
optional
Expand Down Expand Up @@ -202,6 +213,37 @@ When |undojoin| is used this way pressing |u| will "skip over" the Neoformat
changes - it will revert both the changes made by Neoformat and the change
that caused Neoformat to be invoked.

==============================================================================
ARGUMENT TEMPLATES *neoformat-argument-templates*

The following strings will be expanded in the 'args' field:

- <start_line> - starting line of range
- <end_line> - ending line of range
- <lines> - number of lines in range
- <start_byte> - starting byte of range (from line2byte)
- <end_byte> - ending byte of range (from line2byte)
- <bytes> - number of bytes in range
- any expressions supported by |expand()|

Examples:

let g:neoformat_cpp_clangformat = {
\ 'exe': 'clang-format',
\ 'args': ['-lines=<start_line>:<end_line>'],
\ 'range_mode': 1,
\ 'stdin', 1,
\ }

or

let g:neoformat_cpp_clangformat = {
\ 'exe': 'clang-format',
\ 'args': ['-offset=<start_byte>', '-length=<bytes>'],
\ 'range_mode': 1,
\ 'stdin', 1,
\ }

==============================================================================
SUPPORTED FILETYPES *neoformat-supported-filetypes*

Expand Down
3 changes: 2 additions & 1 deletion test/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ def test_visual_selection_multi_filetype():
output_file = '/tmp/neoformat_' + filename_before
copyfile(filename_before, output_file)

for test in [('python', 4, 7), ('css', 9, 9), ('css', 14, 15)]:

for test in [('json', 1, 5), ('typescript', 7, 10)]:
(filetype, start_line, end_line) = test
print(start_line)
vim_cmd = f'{start_line},{end_line}Neoformat! {filetype}'
Expand Down
4 changes: 4 additions & 0 deletions test/visual_after/python_yapf_2_4
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
def one(): pass

def two():
pass
4 changes: 4 additions & 0 deletions test/visual_before/python_yapf_2_4
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
def one(): pass

def two(): pass

17 changes: 5 additions & 12 deletions test/visual_selection_after.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@



def main():

pass


.body {
color: red;
{
"key1": "val",
"key2": 5
}


.textleft {
text-align: left;
function doit(obj: Pancakes) {
return "This " + obj.name " + "is yummy";
}
21 changes: 9 additions & 12 deletions test/visual_selection_before.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
{
"key1":
"val",
"key2": 5
}



def main():


pass


.body{color:red;}


.textleft{
text-align:left;}
function doit(obj: Pancakes)
{
return "This " + obj.name " + "is yummy";
}