From ba1be90a0d33c09f2ddb2196c4edb6ae20986def Mon Sep 17 00:00:00 2001 From: bzvl Date: Mon, 3 Sep 2018 22:00:32 -0700 Subject: [PATCH] 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. --- autoload/neoformat.vim | 43 ++++++++++++++++---- autoload/neoformat/formatters/javascript.vim | 9 +++- autoload/neoformat/formatters/python.vim | 2 + doc/neoformat.txt | 33 +++++++++++++++ 4 files changed, 78 insertions(+), 9 deletions(-) diff --git a/autoload/neoformat.vim b/autoload/neoformat.vim index 1e8fae9a..29e922cd 100644 --- a/autoload/neoformat.vim +++ b/autoload/neoformat.vim @@ -75,20 +75,42 @@ 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 + " Pass the entire buffer, the formatter itself takes a range. + let stdin = getbufline(bufnr('%'), 1, '$') + else + let lines_after = getbufline(bufnr('%'), a:end_line + 1, '$') + let lines_before = getbufline(bufnr('%'), 1, a:start_line - 1) + 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 @@ -108,11 +130,15 @@ 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 + 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('$')) @@ -274,6 +300,7 @@ function! s:generate_cmd(definition, filetype) abort \ 'name': a:definition.exe, \ 'replace': get(a:definition, 'replace', 0), \ 'tmp_file_path': path, + \ 'range': get(a:definition, 'range', 0), \ 'valid_exit_codes': get(a:definition, 'valid_exit_codes', [0]), \ } endfunction diff --git a/autoload/neoformat/formatters/javascript.vim b/autoload/neoformat/formatters/javascript.vim index 98362f2c..b2ccbb00 100644 --- a/autoload/neoformat/formatters/javascript.vim +++ b/autoload/neoformat/formatters/javascript.vim @@ -39,8 +39,15 @@ endfunction function! neoformat#formatters#javascript#prettier() abort return { \ 'exe': 'prettier', - \ 'args': ['--stdin', '--stdin-filepath', '%:p'], + \ 'args': ['--stdin', + \ '--stdin-filepath', + \ '%:p', + \ '--range-start', + \ '', + \ '--range-end', + \ ''], \ 'stdin': 1, + \ 'range': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/python.vim b/autoload/neoformat/formatters/python.vim index ec56cf6c..4d12f0a8 100644 --- a/autoload/neoformat/formatters/python.vim +++ b/autoload/neoformat/formatters/python.vim @@ -5,7 +5,9 @@ endfunction function! neoformat#formatters#python#yapf() abort return { \ 'exe': 'yapf', + \ 'args': ['--lines', '-'], \ 'stdin': 1, + \ 'range': 1, \ } endfunction diff --git a/doc/neoformat.txt b/doc/neoformat.txt index c9158b99..e46a3ea3 100644 --- a/doc/neoformat.txt +++ b/doc/neoformat.txt @@ -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| ============================================================================== @@ -92,6 +93,9 @@ 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` | formatter takes range as argument when using visual formatting. when set to 1, the entire buffer + will be passed in, the range shoudl be passed as an argument to the formatter | + 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 @@ -202,6 +206,35 @@ 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: + + - - starting line of range + - - ending line of range + - - number of lines in range + - - starting byte of range (from line2byte) + - - ending byte of range (from line2byte) + - - number of bytes in range + - any expressions supported by |expand()| + +Example: + + let g:neoformat_cpp_clangformat = { + \ 'exe': 'clang-format', + \ 'args': ['-lines=:'], + \ 'range': 1, + \ 'stdin', 1, + \ } + + let g:neoformat_cpp_clangformat = { + \ 'exe': 'clang-format', + \ 'args': ['-offset=', '-length='], + \ 'range': 1, + \ 'stdin', 1, + \ } + ============================================================================== SUPPORTED FILETYPES *neoformat-supported-filetypes*