diff options
Diffstat (limited to 'plugin/toggle_option_flag.vim')
-rw-r--r-- | plugin/toggle_option_flag.vim | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/plugin/toggle_option_flag.vim b/plugin/toggle_option_flag.vim new file mode 100644 index 0000000..bc7ccd7 --- /dev/null +++ b/plugin/toggle_option_flag.vim @@ -0,0 +1,104 @@ +" +" toggle_option_flag.vim: Provide commands to toggle flags in grouped options +" like 'formatoptions', 'shortmess', 'complete', 'switchbuf', etc. +" +" Author: Tom Ryder <tom@sanctum.geek.nz> +" License: Same as Vim itself +" +if exists('g:loaded_toggle_option_flag') || &compatible + finish +endif +if !has('user_commands') + finish +endif +let g:loaded_toggle_option_flag = 1 + +" Show an error-highlighted message and beep, but without a real :echoerr +function! s:Error(message) + execute 'normal! \<Esc>' + echohl ErrorMsg + echomsg a:message + echohl None +endfunction + +" Test whether an option currently has a flag as part of its value +function! s:Has(option, flag) + + " Horrible :execute to get the option's current setting into a variable + " (I couldn't get {curly braces} indirection to work) + let l:current = '' + execute 'let l:current = &' . a:option + + " If the flag we're toggling is longer than one character, this must by + " necessity be a delimited option. I think all of those in VimL are + " comma-separated. Extend the flag and value so that they'll still match at + " the start and end. Otherwise, use them as-is. + if strlen(a:flag) > 1 + let l:search_flag = ',' . a:flag . ',' + let l:search_value = ',' . l:current . ',' + else + let l:search_flag = a:flag + let l:search_value = l:current + endif + + " Return whether + return stridx(l:search_value, l:search_flag) > -1 + +endfunction + +" Internal function to do the toggling +function! s:Toggle(option, flag, local) + + " Check for spurious option strings, we don't want to :execute anything funny + if a:option =~# '\m\L' + call s:Error('Illegal option name') + return 0 + endif + + " Check the option actually exists + if !exists('&' . a:option) + call s:Error('No such option: ' . a:option) + return 0 + endif + + " Choose which set command to use + let l:set = a:local + \ ? 'setlocal' + \ : 'set' + + " Find whether the flag is set before the change + let l:before = s:Has(a:option, a:flag) + + " Assign -= or += as the operation to run based on whether the flag already + " appears in the option value or not + let l:operation = l:before + \ ? '-=' + \ : '+=' + + " Try to set the option; suppress errors, we'll check our work + silent! execute l:set + \ . ' ' + \ . a:option . l:operation . escape(a:flag, '\ ') + + " Find whether the flag is set after the change + let l:after = s:Has(a:option, a:flag) + + " If we made a difference, report the new value; if we didn't, admit it + if l:before != l:after + execute l:set . ' ' . a:option . '?' + else + call s:Error('Unable to toggle '.a:option.' flag '.a:flag) + endif + + " Return value is whether we made a change + return l:before != l:after + +endfunction + +" User commands wrapping around calls to the above function +command -nargs=+ -complete=option + \ ToggleOptionFlag + \ call <SID>Toggle(<f-args>, 0) +command -nargs=+ -complete=option + \ ToggleOptionFlagLocal + \ call <SID>Toggle(<f-args>, 1) |