Try all available formatters until one works

This commit is contained in:
Chiel92 2015-05-23 10:02:05 +02:00
parent dfd9461f23
commit 2ed8f00bb5
3 changed files with 90 additions and 40 deletions

View File

@ -148,11 +148,19 @@ For the exact default definitions, have a look in `vim-autoformat/plugin/default
If you have a composite filetype with dots (like `django.python` or `php.wordpress`), vim-autoformat internally replaces the dots with underscores so you can define formatters through `g:formatprg_django_python` and so on.
Debugging
---------
If you're struggling with getting a formatter to work, it may help to set vim-autoformat in
verbose-mode. Vim-autoformat will then output errors on formatters that failed.
```vim
let g:autoformat_verbosemode = 1
```
To read all messages in a vim session type `:messages`.
Things that are not (yet) implemented
----------------------------------------------------------
--------------------------------------
* Support toggling between multiple formatters, as requested and described in #46.
* Make Autoformat command accept ranges and provide range information to formatter if they support that, as requested and described in #47.
* Make `:Autoformat` command accept ranges and provide range information to formatter if they support that, as requested and described in #47.
* Automatically check for formatters of supertypes, as requested and described in #50.
* Option for on-the-fly code-formatting, like visual studio (If ever. When you have a clever idea about how to do this, I'd be glad to hear.)
@ -162,6 +170,12 @@ If you have any suggestions on this plugin or on this readme, if you have some n
Change log
----------
### May 21 2015
* Backwards incompatible patch!
* Multiple formatters per filetype are now supported
* configuration variable names changed
* `gq` no longer supported
### Dec 9 2014
* Added `rbeautify` to the defaults for formatting ruby files

View File

@ -1,46 +1,46 @@
" TODO:
" - Make :Autoformat accept ranges
" Function for finding the formatters for this filetype
" Result is stored in b:formatters
function! s:find_formatters(...)
" Detect verbosity
let s:verbose = &verbose || exists("g:autoformat_verbosemode")
let verbose = &verbose || exists("g:autoformat_verbosemode")
" Extract filetype to be used
let type = a:0 ? a:1 : &filetype
" Support composite filetypes by replacing dots with underscores
let type = substitute(type, "[.]", "_", "g")
let s:formatters_var = "g:formatters_".type
let formatters_var = "g:formatters_".type
let b:formatters = []
if !exists(s:formatters_var)
if !exists(formatters_var)
" No formatters defined
if s:verbose
if verbose
echoerr "No formatters defined for filetype '".type."'."
endif
return 0
endif
let s:formatters = eval(s:formatters_var)
if len(s:formatters) == 0
let formatters = eval(formatters_var)
if len(formatters) == 0
" No formatters defined
if s:verbose
if verbose
echoerr "No formatters defined for filetype '".type."'."
endif
return 0
endif
let b:formatters = s:formatters
let b:formatters = formatters
return 1
endfunction
" Function for finding and setting the currently selected formatter
function! s:set_formatter(...)
" Detect verbosity
let s:verbose = &verbose || exists("g:autoformat_verbosemode")
" Try all formatters, starting with the currently selected one, until one
" works. If none works, autoindent the buffer.
function! s:TryAllFormatters(...)
" Make sure formatters are defined and detected
if !call('<SID>find_formatters', a:000)
return 0
@ -54,45 +54,75 @@ function! s:set_formatter(...)
let b:current_formatter_index = 0
endif
" Try all formatters, starting with selected one
let index = b:current_formatter_index
while 1
let format_def_var = 'g:format_def_'.b:formatters[index]
" Formatter definition must be existent
if !exists(format_def_var)
echoerr "No format definition found in '".s:format_def_var."'."
return 0
endif
" Eval twice, once for getting definition content,
" once for getting the final expression
let &formatprg = eval(eval(format_def_var))
if s:TryFormatter()
return 1
else
let index = (index + 1) % len(b:formatters)
endif
" Tried all formatters, none worked
if index == b:current_formatter_index
return 0
endif
endwhile
" Autoindent code if no formatters work
exe "normal gg=G"
let &formatprg = eval(s:formatters[b:current_formatter_index])
return 1
endfunction
" Call formatter
" If stderr is empty, apply result, return 1
" Otherwise, return 0
function! s:TryFormatter()
" Detect verbosity
let verbose = &verbose || exists("g:autoformat_verbosemode")
" Function for formatting the entire buffer
function! s:Autoformat(...)
" Save window state
let winview=winsaveview()
if call('<SID>set_formatter', a:000)
" Autoformat code
python << EOF
import vim, subprocess
from subprocess import Popen, PIPE
text = '\n'.join(vim.current.buffer[:])
formatprg = vim.eval('&formatprg')
verbose = vim.eval('verbose')
p = subprocess.Popen(formatprg, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
stdoutdata, stderrdata = p.communicate(text)
if stderrdata:
vim.command('echoerr "Error communicating with formatter: {}"'.format(stderrdata))
if verbose:
vim.command('echom "Formatter {} has errors: {}. Skipping."'.format(formatprg,
stderrdata))
vim.command('return 0')
else:
vim.current.buffer[:] = stdoutdata.split('\n')
EOF
else
" Autoindent code
exe "normal gg=G"
endif
" Recall window state
call winrestview(winview)
return 1
endfunction
" Create a command for formatting the entire buffer
command! -nargs=? -complete=filetype Autoformat call s:Autoformat(<f-args>)
command! -nargs=? -complete=filetype Autoformat call s:TryAllFormatters(<f-args>)
" Functions for iterating through list of available formatters
@ -109,8 +139,8 @@ function! s:PreviousFormatter()
if !exists('b:current_formatter_index')
let b:current_formatter_index = 0
endif
let s:l = len(b:formatters)
let b:current_formatter_index = (b:current_formatter_index - 1 + s:l) % s:l
let l = len(b:formatters)
let b:current_formatter_index = (b:current_formatter_index - 1 + l) % l
endfunction
" Create commands for iterating through formatter list

View File

@ -1,9 +1,15 @@
if !exists("g:formatters_python") | let g:formatters_python = [] | endif
let g:formatters_python += [
\ '"autopep8 - ".(&textwidth ? "--max-line-length=".&textwidth : "")',
\ '"asdf"',
\ '"autopep8 - --indent-size 2 ".(&textwidth ? "--max-line-length=".&textwidth : "")'
\ ]
let g:format_def_autopep8 = '"autopep8 - ".(&textwidth ? "--max-line-length=".&textwidth : "")'
let g:format_def_test = '"asdf"'
let g:format_def_another_autopep8 = '"autopep8 - --indent-size 2 ".(&textwidth ? "--max-line-length=".&textwidth : "")'
if !exists("g:formatters_python")
let g:formatters_python = [
\ 'test',
\ 'another_autopep8',
\ 'autopep8',
\ ]
endif
"if !exists("g:formatters_cs")
"let g:formatters_cs = ['"astyle --mode=cs --style=ansi --indent-namespaces -pcH".(&expandtab ? "s".&shiftwidth : "t")']