Skip to content

Commit

Permalink
Added stdin option for formatters (#16)
Browse files Browse the repository at this point in the history
Before:

buffer --> /tmp/file --> formatter --> /tmp/file --> buffer

Now (with 'stdin': 1):

buffer --> formatter --> buffer

Removed job_control as it isn't necessary

Adjusted formatters that support stdin to have stdin option set to 1.
  • Loading branch information
sbdchd committed Jan 6, 2017
1 parent 87dc222 commit 34d049f
Show file tree
Hide file tree
Showing 35 changed files with 270 additions and 226 deletions.
78 changes: 59 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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']
Expand Down Expand Up @@ -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
Expand Down
53 changes: 43 additions & 10 deletions autoload/neoformat.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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,
Expand Down
10 changes: 7 additions & 3 deletions autoload/neoformat/formatters/c.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 2 additions & 1 deletion autoload/neoformat/formatters/cpp.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 3 additions & 2 deletions autoload/neoformat/formatters/cs.vim
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ endfunction
function! neoformat#formatters#cs#uncrustify() abort
return {
\ 'exe': 'uncrustify',
\ 'args': ['-q', '-l CS', '-f']
\ 'args': ['-q', '-l CS', '-f'],
\ 'stdin': 1,
\ }
endfunction

function! neoformat#formatters#cs#astyle() abort
return {
\ 'exe': 'astyle',
\ 'args': ['--mode=cs'],
\ 'replace': 1
\ 'stdin': 1,
\ }
endfunction
7 changes: 5 additions & 2 deletions autoload/neoformat/formatters/css.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -28,6 +31,6 @@ endfunction
function! neoformat#formatters#css#stylefmt() abort
return {
\ 'exe': 'stylefmt',
\ 'replace': 1
\ 'stdin': 1,
\ }
endfunction
6 changes: 4 additions & 2 deletions autoload/neoformat/formatters/d.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions autoload/neoformat/formatters/dart.vim
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ endfunction
function! neoformat#formatters#dart#dartfmt() abort
return {
\ 'exe': 'dartfmt',
\ 'stdin': 1,
\ }
endfunction
4 changes: 3 additions & 1 deletion autoload/neoformat/formatters/elm.vim
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ endfunction

function! neoformat#formatters#elm#elmformat() abort
return {
\ 'exe': 'elm-format'
\ 'exe': 'elm-format',
\ 'args': ['--stdin'],
\ 'stdin': 1,
\ }
endfunction

Expand Down
10 changes: 8 additions & 2 deletions autoload/neoformat/formatters/go.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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

3 changes: 2 additions & 1 deletion autoload/neoformat/formatters/haskell.vim
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ endfunction

function! neoformat#formatters#haskell#stylishhaskell() abort
return {
\ 'exe': 'stylish-haskell'
\ 'exe': 'stylish-haskell',
\ 'stdin': 1,
\ }
endfunction
5 changes: 4 additions & 1 deletion autoload/neoformat/formatters/html.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions autoload/neoformat/formatters/java.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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


Loading

0 comments on commit 34d049f

Please sign in to comment.