diff --git a/README.md b/README.md index ac701587..c12ff7ac 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,18 @@ A [Neovim](https://neovim.io) and Vim8 plugin for formatting code. -Neoformat uses a variety of formatters for differing filetypes. Currently, Neoformat -will run a formatter _asynchronously_, and on success it will update the current -buffer with the formatted text. On a formatter failure, Neoformat will try the next -formatter defined for the filetype. +Neoformat uses a variety of formatters for many filetypes. Currently, Neoformat +will run a formatter using the current buffer data, and on success it will +update the current buffer with the formatted text. On a formatter failure, +Neoformat will try the next formatter defined for the filetype. -The job control is based off [vim-go's](https://github.com/fatih/vim-go). +By using `getbufline()` to read from the current buffer instead of file, +Neoformat is able to format your buffer without you having to `:w` your file first. +Also, by using `setline()`, marks, jumps, etc. are all maintained after formatting. + +Neoformat supports both sending buffer data to formatters via stdin, and also +writing buffer data to `/tmp/` for formatters to read that do not support input +via stdin. ## Basic Usage @@ -33,28 +39,33 @@ Plug 'sbdchd/neoformat' ## Current Limitation(s) -In order to preserve marks, jumps, etc., Neoformat uses Vim's `setline()` function -to insert the formatted text. If the buffer is changed before the formatter has -completed, then the updated text will be put into the current buffer. - -To prevent this, format jobs are cancelled when changing / closing the buffer. +If a formatter is either not configured to use `stdin`, or is not able to read +from `stdin`, then buffer data will be written to a file in `/tmp/neoformat/`, +where the formatter will then read from -**So don't switch buffers before the the formatting is complete!** - -Note: This should be resolved when [`setbufline()`](https://github.com/vim/vim/blob/9bd547aca41799605c3a3f83444f6725c2d6eda9/runtime/doc/todo.txt#L177) is added. +## Config [Optional] -By default, Neoformat reads from the current buffer, not the current file. This -can be changed via the configuration variable `g:neoformat_read_from_buffer`. +Define custom formatters. -With Vim, some of the formatters do not function, e.g. remark. +Options: -## Config [Optional] +| name | description | default | optional / required | +| ----------- | ----------------------------------------------------------------------------------------------------------------- | ------- | ------------------- | +| `exe` | the name the formatter executable in the path | n/a | **required** | +| `args` | list of arguments | \[] | optional | +| `replace` | overwrite the file, instead of updating the buffer | 0 | optional | +| `stdin` | send data to the stdin of the formatter | 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 | 0 | optional | -Define custom formatters. +Example: ```viml let g:neoformat_python_autopep8 = { - \ 'exe': 'autopep8' + \ 'exe': 'autopep8', + \ 'args': ['-s 4', '-E'], + \ 'replace': 1 " replace the file, instead of updating buffer (default: 0), + \ 'stdin': 1, " send data to stdin of formatter (default: 0) + \ 'no_append': 1, \ } let g:neoformat_enabled_python = ['autopep8'] @@ -93,6 +104,35 @@ let g:neoformat_verbose = 1 " only affects the verbosity of Neoformat let &verbose = 1 " also increases verbosity of the editor as a whole ``` +## Adding a New Formatter + +Note: you should replace everything `{{ }}` accordingly + +1. Create a file in `autoload/neoformat/formatters/{{ filetype }}.vim` if it does not + already exist for your filetype. + +2. Follow the following format + +See Config above for options + +```viml +function! neoformat#formatters#{{ filetype }}#enabled() abort + return ['{{ formatter name }}', '{{ other formatter name for filetype }}'] +endfunction + +function! neoformat#formatters#{{ filetype }}#{{ formatter name }}() abort + return { + \ 'exe': '{{ formatter name }}', + \ 'args': ['-s 4', '-q'], + \ 'stdin': 1 + \ } +endfunction + +function! neoformat#formatters#{{ filetype }}#{{ other formatter name }}() abort + return {'exe': {{ other formatter name }} +endfunction +``` + ## Supported Filetypes - Arduino diff --git a/autoload/neoformat.vim b/autoload/neoformat.vim index 8638f013..1fae192c 100644 --- a/autoload/neoformat.vim +++ b/autoload/neoformat.vim @@ -4,19 +4,15 @@ function! neoformat#Start(user_formatter) abort endfunction function! neoformat#Neoformat(user_formatter) abort - let s:vim_jobcontrol = !has('nvim') && has('job') && has('patch-7-4-1590') - if !(has('nvim') || s:vim_jobcontrol) - return neoformat#utils#warn('Neovim, or Vim with job control, is currently required to run this plugin') - endif if !&modifiable return neoformat#utils#warn('buffer not modifiable') endif + let filetype = s:split_filetypes(&filetype) if !empty(a:user_formatter) let formatter = a:user_formatter else - let filetype = s:split_filetypes(&filetype) let formatters = s:get_enabled_formatters(filetype) if formatters == [] call neoformat#utils#msg('formatter not defined for ' . filetype . ' filetype') @@ -47,14 +43,49 @@ function! neoformat#Neoformat(user_formatter) abort let cmd = s:generate_cmd(definition, filetype) if cmd == {} if !empty(a:user_formatter) - return neoformat#utils#log('user specified formatter failed') + return neoformat#utils#warn('formatter ' . a:user_formatter . ' failed') endif return neoformat#NextNeoformat() endif - call neoformat#utils#log(cmd) - - return neoformat#run#Neoformat(cmd) + let stdin = getbufline(bufnr('%'), 1, '$') + if cmd.stdin == 1 + let stdout = systemlist(cmd.exe, stdin) + else + let stdout = systemlist(cmd.exe) + endif + call neoformat#utils#log(stdin) + call neoformat#utils#log(stdout) + if v:shell_error == 0 + if stdout != stdin + " 1. set lines to '' aka \n from end of file when new data < old data + let datalen = len(stdout) + + while datalen <= line('$') + call setline(datalen, '') + let datalen += 1 + endwhile + + " 2. remove extra newlines at the end of the file + let search = @/ + let view = winsaveview() + " http://stackoverflow.com/a/7496112/3720597 + " vint: -ProhibitCommandRelyOnUser -ProhibitCommandWithUnintendedSideEffect + silent! %s#\($\n\)\+\%$## + " vint: +ProhibitCommandRelyOnUser +ProhibitCommandWithUnintendedSideEffect + let @/=search + call winrestview(view) + + " 3. write new data to buffer + call setline(1, stdout) + call neoformat#utils#msg(cmd.name . ' formatted buffer') + else + call neoformat#utils#msg('no change necessary with ' . cmd.name) + endif + else + call neoformat#utils#log(v:shell_error) + return neoformat#NextNeoformat() + endif endfunction function! s:get_enabled_formatters(filetype) abort @@ -136,7 +167,8 @@ function! s:generate_cmd(definition, filetype) abort let path = fnameescape(expand('%:p')) endif - if no_append + let using_stdin = get(a:definition, 'stdin', 0) + if no_append || using_stdin let path = '' endif @@ -146,6 +178,7 @@ function! s:generate_cmd(definition, filetype) abort return { \ 'exe': fullcmd, + \ 'stdin': using_stdin, \ 'name': a:definition.exe, \ 'no_append': no_append, \ 'path': path, diff --git a/autoload/neoformat/formatters/c.vim b/autoload/neoformat/formatters/c.vim index 3a629be7..9c182fac 100644 --- a/autoload/neoformat/formatters/c.vim +++ b/autoload/neoformat/formatters/c.vim @@ -5,18 +5,22 @@ endfunction function! neoformat#formatters#c#uncrustify() abort return { \ 'exe': 'uncrustify', - \ 'args': ['-q', '-l C', '-f'] + \ 'args': ['-q', '-l C', '-f'], + \ 'stdin': 1, \ } endfunction function! neoformat#formatters#c#clangformat() abort - return {'exe': 'clang-format'} + return { + \ 'exe': 'clang-format', + \ 'stdin': 1, + \ } endfunction function! neoformat#formatters#c#astyle() abort return { \ 'exe': 'astyle', \ 'args': ['--mode=c'], - \ 'replace': 1 + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/cpp.vim b/autoload/neoformat/formatters/cpp.vim index d896d7c7..b43d7ef4 100644 --- a/autoload/neoformat/formatters/cpp.vim +++ b/autoload/neoformat/formatters/cpp.vim @@ -5,7 +5,8 @@ endfunction function! neoformat#formatters#cpp#uncrustify() abort return { \ 'exe': 'uncrustify', - \ 'args': ['-q', '-l CPP', '-f'] + \ 'args': ['-q', '-l CPP', '-f'], + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/cs.vim b/autoload/neoformat/formatters/cs.vim index dec9b94e..84c05522 100644 --- a/autoload/neoformat/formatters/cs.vim +++ b/autoload/neoformat/formatters/cs.vim @@ -5,7 +5,8 @@ endfunction function! neoformat#formatters#cs#uncrustify() abort return { \ 'exe': 'uncrustify', - \ 'args': ['-q', '-l CS', '-f'] + \ 'args': ['-q', '-l CS', '-f'], + \ 'stdin': 1, \ } endfunction @@ -13,6 +14,6 @@ function! neoformat#formatters#cs#astyle() abort return { \ 'exe': 'astyle', \ 'args': ['--mode=cs'], - \ 'replace': 1 + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/css.vim b/autoload/neoformat/formatters/css.vim index 21c2966b..20528dba 100644 --- a/autoload/neoformat/formatters/css.vim +++ b/autoload/neoformat/formatters/css.vim @@ -3,7 +3,10 @@ function! neoformat#formatters#css#enabled() abort endfunction function! neoformat#formatters#css#cssbeautify() abort - return { 'exe': 'css-beautify' } + return { + \ 'exe': 'css-beautify', + \ 'stdin': 1, + \ } endfunction function! neoformat#formatters#css#csscomb() abort @@ -28,6 +31,6 @@ endfunction function! neoformat#formatters#css#stylefmt() abort return { \ 'exe': 'stylefmt', - \ 'replace': 1 + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/d.vim b/autoload/neoformat/formatters/d.vim index 0fba65b8..e8413024 100644 --- a/autoload/neoformat/formatters/d.vim +++ b/autoload/neoformat/formatters/d.vim @@ -4,13 +4,15 @@ endfunction function! neoformat#formatters#d#dfmt() abort return { - \ 'exe': 'dfmt' + \ 'exe': 'dfmt', + \ 'stdin': 1, \ } endfunction function! neoformat#formatters#d#uncrustify() abort return { \ 'exe': 'uncrustify', - \ 'args': ['-q', '-l D', '-f'] + \ 'args': ['-q', '-l D'], + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/dart.vim b/autoload/neoformat/formatters/dart.vim index 590b9707..0f32faf3 100644 --- a/autoload/neoformat/formatters/dart.vim +++ b/autoload/neoformat/formatters/dart.vim @@ -5,5 +5,6 @@ endfunction function! neoformat#formatters#dart#dartfmt() abort return { \ 'exe': 'dartfmt', + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/elm.vim b/autoload/neoformat/formatters/elm.vim index 0b829a99..f320ecd7 100644 --- a/autoload/neoformat/formatters/elm.vim +++ b/autoload/neoformat/formatters/elm.vim @@ -4,7 +4,9 @@ endfunction function! neoformat#formatters#elm#elmformat() abort return { - \ 'exe': 'elm-format' + \ 'exe': 'elm-format', + \ 'args': ['--stdin'], + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/go.vim b/autoload/neoformat/formatters/go.vim index c271c81c..33387ff3 100644 --- a/autoload/neoformat/formatters/go.vim +++ b/autoload/neoformat/formatters/go.vim @@ -3,10 +3,16 @@ function! neoformat#formatters#go#enabled() abort endfunction function! neoformat#formatters#go#gofmt() abort - return {'exe': 'gofmt'} + return { + \ 'exe': 'gofmt', + \ 'stdin': 1, + \ } endfunction function! neoformat#formatters#go#goimports() abort - return {'exe': 'goimports'} + return { + \ 'exe': 'goimports', + \ 'stdin': 1, + \ } endfunction diff --git a/autoload/neoformat/formatters/haskell.vim b/autoload/neoformat/formatters/haskell.vim index 6cf054fb..502e7935 100644 --- a/autoload/neoformat/formatters/haskell.vim +++ b/autoload/neoformat/formatters/haskell.vim @@ -4,6 +4,7 @@ endfunction function! neoformat#formatters#haskell#stylishhaskell() abort return { - \ 'exe': 'stylish-haskell' + \ 'exe': 'stylish-haskell', + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/html.vim b/autoload/neoformat/formatters/html.vim index b26d3d79..1dcbe92a 100644 --- a/autoload/neoformat/formatters/html.vim +++ b/autoload/neoformat/formatters/html.vim @@ -15,7 +15,10 @@ function! neoformat#formatters#html#tidy() abort endfunction function! neoformat#formatters#html#htmlbeautify() abort - return {'exe': 'html-beautify'} + return { + \ 'exe': 'html-beautify', + \ 'stdin': 1, + \ } endfunction function! neoformat#formatters#html#prettydiff() abort diff --git a/autoload/neoformat/formatters/java.vim b/autoload/neoformat/formatters/java.vim index 23832936..68b0df93 100644 --- a/autoload/neoformat/formatters/java.vim +++ b/autoload/neoformat/formatters/java.vim @@ -5,7 +5,8 @@ endfunction function! neoformat#formatters#java#uncrustify() abort return { \ 'exe': 'uncrustify', - \ 'args': ['-q', '-l JAVA', '-f'] + \ 'args': ['-q', '-l JAVA', '-f'], + \ 'stdin': 1, \ } endfunction @@ -14,13 +15,16 @@ function! neoformat#formatters#java#astyle() abort return { \ 'exe': 'astyle', \ 'args': ['--mode=java'], - \ 'replace': 1 + \ 'stdin': 1, \ } endfunction function! neoformat#formatters#java#clangformat() abort - return {'exe': 'clang-format'} + return { + \ 'exe': 'clang-format', + \ 'stdin': 1, + \ } endfunction diff --git a/autoload/neoformat/formatters/javascript.vim b/autoload/neoformat/formatters/javascript.vim index ffc8b664..14c74e38 100644 --- a/autoload/neoformat/formatters/javascript.vim +++ b/autoload/neoformat/formatters/javascript.vim @@ -3,11 +3,17 @@ function! neoformat#formatters#javascript#enabled() abort endfunction function! neoformat#formatters#javascript#jsbeautify() abort - return {'exe': 'js-beautify'} + return { + \ 'exe': 'js-beautify', + \ 'stdin': 1, + \ } endfunction function! neoformat#formatters#javascript#clangformat() abort - return {'exe': 'clang-format'} + return { + \ 'exe': 'clang-format', + \ 'stdin': 1 + \ } endfunction function! neoformat#formatters#javascript#prettydiff() abort @@ -24,6 +30,7 @@ endfunction function! neoformat#formatters#javascript#esformatter() abort return { - \ 'exe': 'esformatter' + \ 'exe': 'esformatter', + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/markdown.vim b/autoload/neoformat/formatters/markdown.vim index 722ad097..224a1765 100644 --- a/autoload/neoformat/formatters/markdown.vim +++ b/autoload/neoformat/formatters/markdown.vim @@ -5,6 +5,7 @@ endfunction function! neoformat#formatters#markdown#remark() abort return { \ 'exe': 'remark', - \ 'args': ['--no-color', '--silent'] + \ 'args': ['--no-color', '--silent'], + \ 'stdin': 1 \ } endfunction diff --git a/autoload/neoformat/formatters/objc.vim b/autoload/neoformat/formatters/objc.vim index 5f3ab91d..5144e521 100644 --- a/autoload/neoformat/formatters/objc.vim +++ b/autoload/neoformat/formatters/objc.vim @@ -5,7 +5,8 @@ endfunction function! neoformat#formatters#objc#uncrustify() abort return { \ 'exe': 'uncrustify', - \ 'args': ['-q', '-l OC+', '-f'] + \ 'args': ['-q', '-l OC+', '-f'], + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/pandoc.vim b/autoload/neoformat/formatters/pandoc.vim index aedc0810..a5c41b4b 100644 --- a/autoload/neoformat/formatters/pandoc.vim +++ b/autoload/neoformat/formatters/pandoc.vim @@ -11,10 +11,9 @@ function! neoformat#formatters#pandoc#pandoc() abort \ '-s', \ '--wrap=auto', \ '--atx-headers', - \ '%:p', \ '|', \ "sed -e 's/\\\[/[/g'", "-e 's/\\\]/]/g'",], - \ 'no_append': 1 + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/pawn.vim b/autoload/neoformat/formatters/pawn.vim index 73e75c43..75f0895b 100644 --- a/autoload/neoformat/formatters/pawn.vim +++ b/autoload/neoformat/formatters/pawn.vim @@ -5,7 +5,8 @@ endfunction function! neoformat#formatters#pawn#uncrustify() abort return { \ 'exe': 'uncrustify', - \ 'args': ['-q', '-l PAWN', '-f'] + \ 'args': ['-q', '-l PAWN', '-f'], + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/perl.vim b/autoload/neoformat/formatters/perl.vim index 736e2062..d0a403da 100644 --- a/autoload/neoformat/formatters/perl.vim +++ b/autoload/neoformat/formatters/perl.vim @@ -5,6 +5,6 @@ endfunction function! neoformat#formatters#perl#perltidy() abort return { \ 'exe': 'perltidy', - \ 'args': ['--standard-output'] + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/pug.vim b/autoload/neoformat/formatters/pug.vim index a2e74b24..1bfebd0b 100644 --- a/autoload/neoformat/formatters/pug.vim +++ b/autoload/neoformat/formatters/pug.vim @@ -5,6 +5,7 @@ endfunction function! neoformat#formatters#pug#pugbeautifier() abort return { \ 'exe': 'pug-beautifier', - \ 'args': ['-s 2'] + \ 'args': ['-s 2'], + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/python.vim b/autoload/neoformat/formatters/python.vim index f54f0a0c..97958e48 100644 --- a/autoload/neoformat/formatters/python.vim +++ b/autoload/neoformat/formatters/python.vim @@ -3,9 +3,15 @@ function! neoformat#formatters#python#enabled() abort endfunction function! neoformat#formatters#python#yapf() abort - return {'exe': 'yapf'} + return { + \ 'exe': 'yapf', + \ 'stdin': 1 + \ } endfunction function! neoformat#formatters#python#autopep8() abort - return {'exe': 'autopep8'} + return { + \ 'exe': 'autopep8', + \ 'args': ['-'], + \ 'stdin': 1} endfunction diff --git a/autoload/neoformat/formatters/ruby.vim b/autoload/neoformat/formatters/ruby.vim index b5f58f0b..464bb4df 100644 --- a/autoload/neoformat/formatters/ruby.vim +++ b/autoload/neoformat/formatters/ruby.vim @@ -5,6 +5,6 @@ endfunction function! neoformat#formatters#ruby#rubybeautify() abort return { \ 'exe': 'ruby-beautify', - \ 'args': ['--spaces', '-c 2'] + \ 'args': ['--spaces', '-c 2'], \ } endfunction diff --git a/autoload/neoformat/formatters/rust.vim b/autoload/neoformat/formatters/rust.vim index cdbea4fc..76254231 100644 --- a/autoload/neoformat/formatters/rust.vim +++ b/autoload/neoformat/formatters/rust.vim @@ -5,6 +5,6 @@ endfunction function! neoformat#formatters#rust#rustfmt() abort return { \ 'exe': 'rustfmt', - \ 'replace': 1 + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/sass.vim b/autoload/neoformat/formatters/sass.vim index 9b5feda9..4d4e9153 100644 --- a/autoload/neoformat/formatters/sass.vim +++ b/autoload/neoformat/formatters/sass.vim @@ -5,7 +5,8 @@ endfunction function! neoformat#formatters#sass#sassconvert() abort return { \ 'exe': 'sass-convert', - \ 'args': ['-T sass'] + \ 'args': ['-F sass', '-T sass', '-s'], + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/scala.vim b/autoload/neoformat/formatters/scala.vim index 9a6daed9..81f2a672 100644 --- a/autoload/neoformat/formatters/scala.vim +++ b/autoload/neoformat/formatters/scala.vim @@ -5,6 +5,7 @@ endfunction function! neoformat#formatters#scala#scalariform() abort return { \ 'exe': 'scalariform', - \ 'args': ['--stdout'] + \ 'args': ['--stdin'], + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/scss.vim b/autoload/neoformat/formatters/scss.vim index ec48f977..891e6b81 100644 --- a/autoload/neoformat/formatters/scss.vim +++ b/autoload/neoformat/formatters/scss.vim @@ -5,7 +5,8 @@ endfunction function! neoformat#formatters#scss#sassconvert() abort return { \ 'exe': 'sass-convert', - \ 'args': ['-T scss'] + \ 'args': ['-F scss', '-T scss', '-s'], + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/sh.vim b/autoload/neoformat/formatters/sh.vim index 9617010e..303c0500 100644 --- a/autoload/neoformat/formatters/sh.vim +++ b/autoload/neoformat/formatters/sh.vim @@ -3,5 +3,8 @@ function! neoformat#formatters#sh#enabled() abort endfunction function! neoformat#formatters#sh#shfmt() abort - return {'exe': 'shfmt'} + return { + \ 'exe': 'shfmt', + \ 'stdin': 1, + \ } endfunction diff --git a/autoload/neoformat/formatters/sql.vim b/autoload/neoformat/formatters/sql.vim index d58170f0..41977643 100644 --- a/autoload/neoformat/formatters/sql.vim +++ b/autoload/neoformat/formatters/sql.vim @@ -5,6 +5,7 @@ endfunction function! neoformat#formatters#sql#sqlformat() abort return { \ 'exe': 'sqlformat', - \ 'args': ['--reindent'] + \ 'args': ['--reindent', '-'], + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/typescript.vim b/autoload/neoformat/formatters/typescript.vim index 93a36ba9..f5895225 100644 --- a/autoload/neoformat/formatters/typescript.vim +++ b/autoload/neoformat/formatters/typescript.vim @@ -4,6 +4,8 @@ endfunction function! neoformat#formatters#typescript#tsfmt() abort return { - \ 'exe': 'tsfmt' + \ 'exe': 'tsfmt', + \ 'args': ['--stdin'], + \ 'stdin': 1 \ } endfunction diff --git a/autoload/neoformat/formatters/vala.vim b/autoload/neoformat/formatters/vala.vim index 23a81352..dfb7e855 100644 --- a/autoload/neoformat/formatters/vala.vim +++ b/autoload/neoformat/formatters/vala.vim @@ -1,7 +1,8 @@ function! neoformat#formatters#vala#uncrustify() abort return { \ 'exe': 'uncrustify', - \ 'args': ['-q', '-l VALA', '-f'] + \ 'args': ['-q', '-l VALA'], + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/xhtml.vim b/autoload/neoformat/formatters/xhtml.vim index bb188dcf..bc0c2020 100644 --- a/autoload/neoformat/formatters/xhtml.vim +++ b/autoload/neoformat/formatters/xhtml.vim @@ -11,7 +11,8 @@ function! neoformat#formatters#xhtml#tidy() abort \ '--indent-spaces 4', \ '--vertical-space yes', \ '--tidy-mark no' - \ ] + \ ], + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/formatters/xml.vim b/autoload/neoformat/formatters/xml.vim index 019b024b..7506a98e 100644 --- a/autoload/neoformat/formatters/xml.vim +++ b/autoload/neoformat/formatters/xml.vim @@ -11,7 +11,8 @@ function! neoformat#formatters#xml#tidy() abort \ '--indent-spaces 4', \ '--vertical-space yes', \ '--tidy-mark no' - \ ] + \ ], + \ 'stdin': 1, \ } endfunction diff --git a/autoload/neoformat/run.vim b/autoload/neoformat/run.vim deleted file mode 100644 index 79b6ae37..00000000 --- a/autoload/neoformat/run.vim +++ /dev/null @@ -1,143 +0,0 @@ -let s:jobs = {} - -function! s:job_id(job) abort - " 8 is the type Job - if type(a:job) == 8 - let i = job_getchannel(a:job) - else - let i = a:job - endif - return split(i)[1] -endfunction - -function! neoformat#run#Neoformat(cmd) abort - - if has('nvim') - let id = jobstart(a:cmd.exe, { - \ 'on_stdout': function('s:on_stdout'), - \ 'on_exit': function('s:on_exit'), - \ }) - else - call neoformat#utils#log('using vim stuff') - let id = s:job_id(job_start(a:cmd.exe, { - \ 'out_cb': function('s:on_stdout_vim'), - \ 'exit_cb': function('s:on_exit_vim'), - \ }) - \ ) - endif - - let job = {} - let job.stdout = [] - let job.name = a:cmd.name - let job.replace = a:cmd.replace - let job.path = a:cmd.path - let job.filetype = a:cmd.filetype - - let s:jobs[id] = job -endfunction - -function! s:on_stdout(job_id, data, event) abort - if !has_key(s:jobs, a:job_id) - return - endif - let job = s:jobs[a:job_id] - - call extend(job.stdout, a:data) -endfunction - -function! s:on_stdout_vim(job, data) abort - let id = s:job_id(a:job) - " passing an empty string to on_exit as vim jobs don't use a third - " argument - call s:on_stdout(id, [a:data], '') -endfunction - - -function! s:on_exit_vim(job, data) abort - let id = s:job_id(a:job) - call s:on_exit(id, a:data, '') -endfunction - - -function! s:on_exit(job_id, data, event) abort - if !has_key(s:jobs, a:job_id) - return - endif - let job = s:jobs[a:job_id] - - call s:update_file(job) - - unlet s:jobs[a:job_id] -endfunction - -function! neoformat#run#KillAll() abort - if empty(s:jobs) - return - endif - - for id in keys(s:jobs) - if id > 0 - silent! call jobstop(id) - endif - endfor - - let s:jobs = {} -endfunction - -function! s:update_file(job) abort - let data = a:job.stdout - let filetype = a:job.filetype - let formatter = a:job.name - - if a:job.replace - let data = readfile(a:job.path) - endif - - if len(data) < 1 - call neoformat#utils#log('no data was provided by ' . formatter) - return neoformat#NextNeoformat() - endif - - let last = len(data) - 1 - let end = data[last] - - " needed for some formatters that add two new lines (\n\n) at the end of files - " ex: remark - if end == '' - let datalen = len(data) - else - let datalen = len(data) + 1 - endif - - " cleanup the end of the file - while datalen <= line('$') - call setline(datalen, '') - let datalen += 1 - endwhile - - " trim trailing newlines - let search = @/ - let view = winsaveview() - " http://stackoverflow.com/a/7496112/3720597 - " vint: -ProhibitCommandRelyOnUser -ProhibitCommandWithUnintendedSideEffect - silent! %s#\($\n\)\+\%$## - " vint: +ProhibitCommandRelyOnUser +ProhibitCommandWithUnintendedSideEffect - let @/=search - call winrestview(view) - - " remove extra newlines at the end of formatted file data - if end == '' - call remove(data, last) - endif - - " ensure file needs to be changed - let lines = getbufline(bufnr('%'), 1, '$') - if data ==# lines - return neoformat#utils#msg('no change necessary with ' . formatter . ' as ' . filetype) - endif - - " setline() is used instead of writefile() so that marks, jumps, etc. are kept - call setline(1, data) - - return neoformat#utils#msg('formatted file with ' . formatter . ' as ' . filetype) -endfunction diff --git a/doc/neoformat.txt b/doc/neoformat.txt index 9e32db1f..cc15d434 100644 --- a/doc/neoformat.txt +++ b/doc/neoformat.txt @@ -1,7 +1,5 @@ *neoformat.txt* A Neovim plugin for formatting. -Version: 0.1 - CONTENTS *neoformat-contents* Introduction |neoformat-introduction| @@ -12,12 +10,20 @@ Supported Filetypes |neoformat-supported-filetypes| ============================================================================== INTRODUCTION *neoformat-introduction* -*neoformat* uses a variety of formatters for differing filetypes. -Currently, neoformat will run a formatter asynchronously, and on success it -will update the current buffer with the formatted text. On a formatter failure, -neoformat will try the next formatter defined for the filetype. +A [Neovim](https://neovim.io) and Vim8 plugin for formatting code. + +*Neoformat* uses a variety of formatters for many filetypes. Currently, Neoformat +will run a formatter using the current buffer data, and on success it will +update the current buffer with the formatted text. On a formatter failure, +Neoformat will try the next formatter defined for the filetype. + +By using `getbufline()` to read from the current buffer instead of file, +Neoformat is able to format your buffer without you having to `:w` your file first. +Also, by using `setline()`, marks, jumps, etc. are all maintained after formatting. -The job control is based off of vim-go's. +Neoformat supports both sending buffer data to formatters via stdin, and also +writing buffer data to `/tmp/` for formatters to read that do not support input +via stdin. ============================================================================== INSTALL *neoformat-install* @@ -32,18 +38,44 @@ USAGE *neoformat-usage* *Neoformat* Format the current file using its filetype > :Neoformat + :Neoformat js-beautify -< + +============================================================================== +CURRENT LIMITATION(S) *neoformat-limitations* + +If a formatter is either not configured to use `stdin`, or is not able to read +from `stdin`, then buffer data will be written to a file in `/tmp/neoformat/`, +where the formatter will then read from + ============================================================================== CONFIG *neoformat-config* +Define custom formatters. + +Options: + +| `exe` | the name the formatter executable in the path | required +| `args` | list of arguments | default: [] | optional +| `replace` | overwrite the file, instead of updating the buffer | default: 0 | optional +| `stdin` | send data to the stdin of 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 + +Example: + Define custom formatters. > let g:neoformat_python_autopep8 = { - \ 'exe': 'autopep8' - \ } + \ 'exe': 'autopep8', + \ 'args': ['-s 4', '-E'], + \ 'replace': 1 " replace the file, instead of updating buffer (default: 0), + \ 'stdin': 1, " send data to stdin of formatter (default: 0) + \ 'no_append': 1, + \ } let g:neoformat_enabled_python = ['autopep8'] < @@ -68,6 +100,35 @@ When debugging, you can enable either of following variables for extra logging. " Or let &verbose = 1 " also increases verbosity of the editor as a whole < +============================================================================== +ADDING A NEW FORMATTER *neoformat-adding-new-formatter* + +Note: you should replace everything `{{ }}` accordingly + +1. Create a file in `autoload/neoformat/formatters/{{ filetype }}.vim` if it does not + already exist for your filetype. + +2. Follow the following format + +See Config above for options +> + function! neoformat#formatters#{{ filetype }}#enabled() abort + return ['{{ formatter name }}', '{{ other formatter name for filetype }}'] + endfunction + + function! neoformat#formatters#{{ filetype }}#{{ formatter name }}() abort + return { + \ 'exe': '{{ formatter name }}', + \ 'args': ['-s 4', '-q'], + \ 'stdin': 1 + \ } + endfunction + + function! neoformat#formatters#{{ filetype }}#{{ other formatter name }}() abort + return {'exe': {{ other formatter name }} + endfunction +< + ============================================================================== SUPPORTED FILETYPES *neoformat-supported-filetypes* diff --git a/plugin/neoformat.vim b/plugin/neoformat.vim index 8d77cae3..5466fb4b 100644 --- a/plugin/neoformat.vim +++ b/plugin/neoformat.vim @@ -1,5 +1,2 @@ command! -nargs=? -bar -complete=customlist,neoformat#CompleteFormatters Neoformat \ call neoformat#Start() - -autocmd! BufWipeout,BufDelete,BufLeave,BufWinLeave,QuitPre - \ call neoformat#run#KillAll()