Skip to content

Commit 34d049f

Browse files
authored
Added stdin option for formatters (#16)
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.
1 parent 87dc222 commit 34d049f

35 files changed

+270
-226
lines changed

README.md

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@
22

33
A [Neovim](https://neovim.io) and Vim8 plugin for formatting code.
44

5-
Neoformat uses a variety of formatters for differing filetypes. Currently, Neoformat
6-
will run a formatter _asynchronously_, and on success it will update the current
7-
buffer with the formatted text. On a formatter failure, Neoformat will try the next
8-
formatter defined for the filetype.
5+
Neoformat uses a variety of formatters for many filetypes. Currently, Neoformat
6+
will run a formatter using the current buffer data, and on success it will
7+
update the current buffer with the formatted text. On a formatter failure,
8+
Neoformat will try the next formatter defined for the filetype.
99

10-
The job control is based off [vim-go's](https://github.com/fatih/vim-go).
10+
By using `getbufline()` to read from the current buffer instead of file,
11+
Neoformat is able to format your buffer without you having to `:w` your file first.
12+
Also, by using `setline()`, marks, jumps, etc. are all maintained after formatting.
13+
14+
Neoformat supports both sending buffer data to formatters via stdin, and also
15+
writing buffer data to `/tmp/` for formatters to read that do not support input
16+
via stdin.
1117

1218
## Basic Usage
1319

@@ -33,28 +39,33 @@ Plug 'sbdchd/neoformat'
3339

3440
## Current Limitation(s)
3541

36-
In order to preserve marks, jumps, etc., Neoformat uses Vim's `setline()` function
37-
to insert the formatted text. If the buffer is changed before the formatter has
38-
completed, then the updated text will be put into the current buffer.
39-
40-
To prevent this, format jobs are cancelled when changing / closing the buffer.
42+
If a formatter is either not configured to use `stdin`, or is not able to read
43+
from `stdin`, then buffer data will be written to a file in `/tmp/neoformat/`,
44+
where the formatter will then read from
4145

42-
**So don't switch buffers before the the formatting is complete!**
43-
44-
Note: This should be resolved when [`setbufline()`](https://github.com/vim/vim/blob/9bd547aca41799605c3a3f83444f6725c2d6eda9/runtime/doc/todo.txt#L177) is added.
46+
## Config [Optional]
4547

46-
By default, Neoformat reads from the current buffer, not the current file. This
47-
can be changed via the configuration variable `g:neoformat_read_from_buffer`.
48+
Define custom formatters.
4849

49-
With Vim, some of the formatters do not function, e.g. remark.
50+
Options:
5051

51-
## Config [Optional]
52+
| name | description | default | optional / required |
53+
| ----------- | ----------------------------------------------------------------------------------------------------------------- | ------- | ------------------- |
54+
| `exe` | the name the formatter executable in the path | n/a | **required** |
55+
| `args` | list of arguments | \[] | optional |
56+
| `replace` | overwrite the file, instead of updating the buffer | 0 | optional |
57+
| `stdin` | send data to the stdin of the formatter | 0 | optional |
58+
| `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 |
5259

53-
Define custom formatters.
60+
Example:
5461

5562
```viml
5663
let g:neoformat_python_autopep8 = {
57-
\ 'exe': 'autopep8'
64+
\ 'exe': 'autopep8',
65+
\ 'args': ['-s 4', '-E'],
66+
\ 'replace': 1 " replace the file, instead of updating buffer (default: 0),
67+
\ 'stdin': 1, " send data to stdin of formatter (default: 0)
68+
\ 'no_append': 1,
5869
\ }
5970
6071
let g:neoformat_enabled_python = ['autopep8']
@@ -93,6 +104,35 @@ let g:neoformat_verbose = 1 " only affects the verbosity of Neoformat
93104
let &verbose = 1 " also increases verbosity of the editor as a whole
94105
```
95106

107+
## Adding a New Formatter
108+
109+
Note: you should replace everything `{{ }}` accordingly
110+
111+
1. Create a file in `autoload/neoformat/formatters/{{ filetype }}.vim` if it does not
112+
already exist for your filetype.
113+
114+
2. Follow the following format
115+
116+
See Config above for options
117+
118+
```viml
119+
function! neoformat#formatters#{{ filetype }}#enabled() abort
120+
return ['{{ formatter name }}', '{{ other formatter name for filetype }}']
121+
endfunction
122+
123+
function! neoformat#formatters#{{ filetype }}#{{ formatter name }}() abort
124+
return {
125+
\ 'exe': '{{ formatter name }}',
126+
\ 'args': ['-s 4', '-q'],
127+
\ 'stdin': 1
128+
\ }
129+
endfunction
130+
131+
function! neoformat#formatters#{{ filetype }}#{{ other formatter name }}() abort
132+
return {'exe': {{ other formatter name }}
133+
endfunction
134+
```
135+
96136
## Supported Filetypes
97137

98138
- Arduino

autoload/neoformat.vim

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,15 @@ function! neoformat#Start(user_formatter) abort
44
endfunction
55

66
function! neoformat#Neoformat(user_formatter) abort
7-
let s:vim_jobcontrol = !has('nvim') && has('job') && has('patch-7-4-1590')
8-
if !(has('nvim') || s:vim_jobcontrol)
9-
return neoformat#utils#warn('Neovim, or Vim with job control, is currently required to run this plugin')
10-
endif
117

128
if !&modifiable
139
return neoformat#utils#warn('buffer not modifiable')
1410
endif
1511

12+
let filetype = s:split_filetypes(&filetype)
1613
if !empty(a:user_formatter)
1714
let formatter = a:user_formatter
1815
else
19-
let filetype = s:split_filetypes(&filetype)
2016
let formatters = s:get_enabled_formatters(filetype)
2117
if formatters == []
2218
call neoformat#utils#msg('formatter not defined for ' . filetype . ' filetype')
@@ -47,14 +43,49 @@ function! neoformat#Neoformat(user_formatter) abort
4743
let cmd = s:generate_cmd(definition, filetype)
4844
if cmd == {}
4945
if !empty(a:user_formatter)
50-
return neoformat#utils#log('user specified formatter failed')
46+
return neoformat#utils#warn('formatter ' . a:user_formatter . ' failed')
5147
endif
5248
return neoformat#NextNeoformat()
5349
endif
5450

55-
call neoformat#utils#log(cmd)
56-
57-
return neoformat#run#Neoformat(cmd)
51+
let stdin = getbufline(bufnr('%'), 1, '$')
52+
if cmd.stdin == 1
53+
let stdout = systemlist(cmd.exe, stdin)
54+
else
55+
let stdout = systemlist(cmd.exe)
56+
endif
57+
call neoformat#utils#log(stdin)
58+
call neoformat#utils#log(stdout)
59+
if v:shell_error == 0
60+
if stdout != stdin
61+
" 1. set lines to '' aka \n from end of file when new data < old data
62+
let datalen = len(stdout)
63+
64+
while datalen <= line('$')
65+
call setline(datalen, '')
66+
let datalen += 1
67+
endwhile
68+
69+
" 2. remove extra newlines at the end of the file
70+
let search = @/
71+
let view = winsaveview()
72+
" http://stackoverflow.com/a/7496112/3720597
73+
" vint: -ProhibitCommandRelyOnUser -ProhibitCommandWithUnintendedSideEffect
74+
silent! %s#\($\n\)\+\%$##
75+
" vint: +ProhibitCommandRelyOnUser +ProhibitCommandWithUnintendedSideEffect
76+
let @/=search
77+
call winrestview(view)
78+
79+
" 3. write new data to buffer
80+
call setline(1, stdout)
81+
call neoformat#utils#msg(cmd.name . ' formatted buffer')
82+
else
83+
call neoformat#utils#msg('no change necessary with ' . cmd.name)
84+
endif
85+
else
86+
call neoformat#utils#log(v:shell_error)
87+
return neoformat#NextNeoformat()
88+
endif
5889
endfunction
5990

6091
function! s:get_enabled_formatters(filetype) abort
@@ -136,7 +167,8 @@ function! s:generate_cmd(definition, filetype) abort
136167
let path = fnameescape(expand('%:p'))
137168
endif
138169

139-
if no_append
170+
let using_stdin = get(a:definition, 'stdin', 0)
171+
if no_append || using_stdin
140172
let path = ''
141173
endif
142174

@@ -146,6 +178,7 @@ function! s:generate_cmd(definition, filetype) abort
146178

147179
return {
148180
\ 'exe': fullcmd,
181+
\ 'stdin': using_stdin,
149182
\ 'name': a:definition.exe,
150183
\ 'no_append': no_append,
151184
\ 'path': path,

autoload/neoformat/formatters/c.vim

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,22 @@ endfunction
55
function! neoformat#formatters#c#uncrustify() abort
66
return {
77
\ 'exe': 'uncrustify',
8-
\ 'args': ['-q', '-l C', '-f']
8+
\ 'args': ['-q', '-l C', '-f'],
9+
\ 'stdin': 1,
910
\ }
1011
endfunction
1112

1213
function! neoformat#formatters#c#clangformat() abort
13-
return {'exe': 'clang-format'}
14+
return {
15+
\ 'exe': 'clang-format',
16+
\ 'stdin': 1,
17+
\ }
1418
endfunction
1519

1620
function! neoformat#formatters#c#astyle() abort
1721
return {
1822
\ 'exe': 'astyle',
1923
\ 'args': ['--mode=c'],
20-
\ 'replace': 1
24+
\ 'stdin': 1,
2125
\ }
2226
endfunction

autoload/neoformat/formatters/cpp.vim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ endfunction
55
function! neoformat#formatters#cpp#uncrustify() abort
66
return {
77
\ 'exe': 'uncrustify',
8-
\ 'args': ['-q', '-l CPP', '-f']
8+
\ 'args': ['-q', '-l CPP', '-f'],
9+
\ 'stdin': 1,
910
\ }
1011
endfunction
1112

autoload/neoformat/formatters/cs.vim

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ endfunction
55
function! neoformat#formatters#cs#uncrustify() abort
66
return {
77
\ 'exe': 'uncrustify',
8-
\ 'args': ['-q', '-l CS', '-f']
8+
\ 'args': ['-q', '-l CS', '-f'],
9+
\ 'stdin': 1,
910
\ }
1011
endfunction
1112

1213
function! neoformat#formatters#cs#astyle() abort
1314
return {
1415
\ 'exe': 'astyle',
1516
\ 'args': ['--mode=cs'],
16-
\ 'replace': 1
17+
\ 'stdin': 1,
1718
\ }
1819
endfunction

autoload/neoformat/formatters/css.vim

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ function! neoformat#formatters#css#enabled() abort
33
endfunction
44

55
function! neoformat#formatters#css#cssbeautify() abort
6-
return { 'exe': 'css-beautify' }
6+
return {
7+
\ 'exe': 'css-beautify',
8+
\ 'stdin': 1,
9+
\ }
710
endfunction
811

912
function! neoformat#formatters#css#csscomb() abort
@@ -28,6 +31,6 @@ endfunction
2831
function! neoformat#formatters#css#stylefmt() abort
2932
return {
3033
\ 'exe': 'stylefmt',
31-
\ 'replace': 1
34+
\ 'stdin': 1,
3235
\ }
3336
endfunction

autoload/neoformat/formatters/d.vim

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ endfunction
44

55
function! neoformat#formatters#d#dfmt() abort
66
return {
7-
\ 'exe': 'dfmt'
7+
\ 'exe': 'dfmt',
8+
\ 'stdin': 1,
89
\ }
910
endfunction
1011

1112
function! neoformat#formatters#d#uncrustify() abort
1213
return {
1314
\ 'exe': 'uncrustify',
14-
\ 'args': ['-q', '-l D', '-f']
15+
\ 'args': ['-q', '-l D'],
16+
\ 'stdin': 1,
1517
\ }
1618
endfunction

autoload/neoformat/formatters/dart.vim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ endfunction
55
function! neoformat#formatters#dart#dartfmt() abort
66
return {
77
\ 'exe': 'dartfmt',
8+
\ 'stdin': 1,
89
\ }
910
endfunction

autoload/neoformat/formatters/elm.vim

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ endfunction
44

55
function! neoformat#formatters#elm#elmformat() abort
66
return {
7-
\ 'exe': 'elm-format'
7+
\ 'exe': 'elm-format',
8+
\ 'args': ['--stdin'],
9+
\ 'stdin': 1,
810
\ }
911
endfunction
1012

autoload/neoformat/formatters/go.vim

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@ function! neoformat#formatters#go#enabled() abort
33
endfunction
44

55
function! neoformat#formatters#go#gofmt() abort
6-
return {'exe': 'gofmt'}
6+
return {
7+
\ 'exe': 'gofmt',
8+
\ 'stdin': 1,
9+
\ }
710
endfunction
811

912
function! neoformat#formatters#go#goimports() abort
10-
return {'exe': 'goimports'}
13+
return {
14+
\ 'exe': 'goimports',
15+
\ 'stdin': 1,
16+
\ }
1117
endfunction
1218

0 commit comments

Comments
 (0)