diff --git a/README.md b/README.md index ed1a6a66..431043bc 100644 --- a/README.md +++ b/README.md @@ -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 '], \ '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'] diff --git a/autoload/neoformat.vim b/autoload/neoformat.vim index 7891c83d..22ace645 100644 --- a/autoload/neoformat.vim +++ b/autoload/neoformat.vim @@ -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 @@ -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('$')) @@ -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 diff --git a/autoload/neoformat/formatters/javascript.vim b/autoload/neoformat/formatters/javascript.vim index 0ab4ed11..75f63f82 100644 --- a/autoload/neoformat/formatters/javascript.vim +++ b/autoload/neoformat/formatters/javascript.vim @@ -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', '', + \ '--range-end', ''], \ 'stdin': 1, + \ 'range_mode': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/python.vim b/autoload/neoformat/formatters/python.vim index ec56cf6c..03ea851d 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_mode': 1, \ } endfunction diff --git a/doc/neoformat.txt b/doc/neoformat.txt index c111d8a3..69f31c45 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,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 @@ -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: + + - - 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()| + +Examples: + + let g:neoformat_cpp_clangformat = { + \ 'exe': 'clang-format', + \ 'args': ['-lines=:'], + \ 'range_mode': 1, + \ 'stdin', 1, + \ } + +or + + let g:neoformat_cpp_clangformat = { + \ 'exe': 'clang-format', + \ 'args': ['-offset=', '-length='], + \ 'range_mode': 1, + \ 'stdin', 1, + \ } + ============================================================================== SUPPORTED FILETYPES *neoformat-supported-filetypes* diff --git a/test/visual_after/python_yapf_2_4 b/test/visual_after/python_yapf_2_4 new file mode 100644 index 00000000..ad125286 --- /dev/null +++ b/test/visual_after/python_yapf_2_4 @@ -0,0 +1,5 @@ +def one(): pass + + +def two(): + pass diff --git a/test/visual_before/python_yapf_2_4 b/test/visual_before/python_yapf_2_4 new file mode 100644 index 00000000..74025966 --- /dev/null +++ b/test/visual_before/python_yapf_2_4 @@ -0,0 +1,4 @@ +def one(): pass + +def two(): pass +