From 2ed8f00bb51c93ebec4005e2b4e04ce3a1b4a170 Mon Sep 17 00:00:00 2001 From: Chiel92 Date: Sat, 23 May 2015 10:02:05 +0200 Subject: [PATCH] Try all available formatters until one works --- README.md | 18 ++++++++- plugin/autoformat.vim | 94 ++++++++++++++++++++++++++++--------------- plugin/defaults.vim | 18 ++++++--- 3 files changed, 90 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index ac0c8f4..966884e 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/plugin/autoformat.vim b/plugin/autoformat.vim index 20b569e..94f5d9e 100644 --- a/plugin/autoformat.vim +++ b/plugin/autoformat.vim @@ -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('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('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() +command! -nargs=? -complete=filetype Autoformat call s:TryAllFormatters() " 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 diff --git a/plugin/defaults.vim b/plugin/defaults.vim index deae885..487754c 100644 --- a/plugin/defaults.vim +++ b/plugin/defaults.vim @@ -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")']