diff options
author | Nick Shipp <nick@shipp.ninja> | 2017-05-07 09:04:01 -0400 |
---|---|---|
committer | Nick Shipp <nick@shipp.ninja> | 2017-05-07 09:04:01 -0400 |
commit | c012f55efda29f09179e921cf148d79deb57616e (patch) | |
tree | ff0ad37f22622d51194cab192a2aa4b0106d7ad0 /vim/bundle/tabular/plugin | |
parent | 4ca8f6608883d230131f8a9e8b6d6c091c516049 (diff) |
Much maturering of vim configs
Diffstat (limited to 'vim/bundle/tabular/plugin')
-rw-r--r-- | vim/bundle/tabular/plugin/Tabular.vim | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/vim/bundle/tabular/plugin/Tabular.vim b/vim/bundle/tabular/plugin/Tabular.vim new file mode 100644 index 0000000..e73329a --- /dev/null +++ b/vim/bundle/tabular/plugin/Tabular.vim @@ -0,0 +1,346 @@ +" Tabular: Align columnar data using regex-designated column boundaries +" Maintainer: Matthew Wozniski (godlygeek@gmail.com) +" Date: Thu, 03 May 2012 20:49:32 -0400 +" Version: 1.0 +" +" Long Description: +" Sometimes, it's useful to line up text. Naturally, it's nicer to have the +" computer do this for you, since aligning things by hand quickly becomes +" unpleasant. While there are other plugins for aligning text, the ones I've +" tried are either impossibly difficult to understand and use, or too simplistic +" to handle complicated tasks. This plugin aims to make the easy things easy +" and the hard things possible, without providing an unnecessarily obtuse +" interface. It's still a work in progress, and criticisms are welcome. +" +" License: +" Copyright (c) 2012, Matthew J. Wozniski +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" * Redistributions of source code must retain the above copyright notice, +" this list of conditions and the following disclaimer. +" * Redistributions in binary form must reproduce the above copyright +" notice, this list of conditions and the following disclaimer in the +" documentation and/or other materials provided with the distribution. +" * The names of the contributors may not be used to endorse or promote +" products derived from this software without specific prior written +" permission. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS +" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +" NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, +" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +" OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +" Abort if running in vi-compatible mode or the user doesn't want us. +if &cp || exists('g:tabular_loaded') + if &cp && &verbose + echo "Not loading Tabular in compatible mode." + endif + finish +endif + +let g:tabular_loaded = 1 + +" Stupid vimscript crap {{{1 +let s:savecpo = &cpo +set cpo&vim + +" Private Things {{{1 + +" Dictionary of command name to command +let s:TabularCommands = {} + +" Generate tab completion list for :Tabularize {{{2 +" Return a list of commands that match the command line typed so far. +" NOTE: Tries to handle commands with spaces in the name, but Vim doesn't seem +" to handle that terribly well... maybe I should give up on that. +function! s:CompleteTabularizeCommand(argstart, cmdline, cursorpos) + let names = keys(s:TabularCommands) + if exists("b:TabularCommands") + let names += keys(b:TabularCommands) + endif + + let cmdstart = substitute(a:cmdline, '^\s*\S\+\s*', '', '') + + return filter(names, 'v:val =~# ''^\V'' . escape(cmdstart, ''\'')') +endfunction + +" Choose the proper command map from the given command line {{{2 +" Returns [ command map, command line with leading <buffer> removed ] +function! s:ChooseCommandMap(commandline) + let map = s:TabularCommands + let cmd = a:commandline + + if cmd =~# '^<buffer>\s\+' + if !exists('b:TabularCommands') + let b:TabularCommands = {} + endif + let map = b:TabularCommands + let cmd = substitute(cmd, '^<buffer>\s\+', '', '') + endif + + return [ map, cmd ] +endfunction + +" Parse '/pattern/format' into separate pattern and format parts. {{{2 +" If parsing fails, return [ '', '' ] +function! s:ParsePattern(string) + if a:string[0] != '/' + return ['',''] + endif + + let pat = '\\\@<!\%(\\\\\)\{-}\zs/' . tabular#ElementFormatPattern() . '*$' + let format = matchstr(a:string[1:-1], pat) + if !empty(format) + let format = format[1 : -1] + let pattern = a:string[1 : -len(format) - 2] + else + let pattern = a:string[1 : -1] + endif + + return [pattern, format] +endfunction + +" Split apart a list of | separated expressions. {{{2 +function! s:SplitCommands(string) + if a:string =~ '^\s*$' + return [] + endif + + let end = match(a:string, "[\"'|]") + + " Loop until we find a delimiting | or end-of-string + while end != -1 && (a:string[end] != '|' || a:string[end+1] == '|') + if a:string[end] == "'" + let end = match(a:string, "'", end+1) + 1 + if end == 0 + throw "No matching end single quote" + endif + elseif a:string[end] == '"' + " Find a " preceded by an even number of \ (or 0) + let pattern = '\%(\\\@<!\%(\\\\\)*\)\@<="' + let end = matchend(a:string, pattern, end+1) + 1 + if end == 0 + throw "No matching end double quote" + endif + else " Found || + let end += 2 + endif + + let end = match(a:string, "[\"'|]", end) + endwhile + + if end == 0 || a:string[0 : end - (end > 0)] =~ '^\s*$' + throw "Empty element" + endif + + if end == -1 + let rv = [ a:string ] + else + let rv = [ a:string[0 : end-1] ] + s:SplitCommands(a:string[end+1 : -1]) + endif + + return rv +endfunction + +" Public Things {{{1 + +" Command associating a command name with a simple pattern command {{{2 +" AddTabularPattern[!] [<buffer>] name /pattern[/format] +" +" If <buffer> is provided, the command will only be available in the current +" buffer, and will be used instead of any global command with the same name. +" +" If a command with the same name and scope already exists, it is an error, +" unless the ! is provided, in which case the existing command will be +" replaced. +" +" pattern is a regex describing the delimiter to be used. +" +" format describes the format pattern to be used. The default will be used if +" none is provided. +com! -nargs=+ -bang AddTabularPattern + \ call AddTabularPattern(<q-args>, <bang>0) + +function! AddTabularPattern(command, force) + try + let [ commandmap, rest ] = s:ChooseCommandMap(a:command) + + let name = matchstr(rest, '.\{-}\ze\s*/') + let pattern = substitute(rest, '.\{-}\s*\ze/', '', '') + + let [ pattern, format ] = s:ParsePattern(pattern) + + if empty(name) || empty(pattern) + throw "Invalid arguments!" + endif + + if !a:force && has_key(commandmap, name) + throw string(name) . " is already defined, use ! to overwrite." + endif + + let command = "tabular#TabularizeStrings(a:lines, " . string(pattern) + + if !empty(format) + let command .= ", " . string(format) + endif + + let command .= ")" + + let commandmap[name] = { 'pattern' : pattern, 'commands' : [ command ] } + catch + echohl ErrorMsg + echomsg "AddTabularPattern: " . v:exception + echohl None + endtry +endfunction + +" Command associating a command name with a pipeline of functions {{{2 +" AddTabularPipeline[!] [<buffer>] name /pattern/ func [ | func2 [ | func3 ] ] +" +" If <buffer> is provided, the command will only be available in the current +" buffer, and will be used instead of any global command with the same name. +" +" If a command with the same name and scope already exists, it is an error, +" unless the ! is provided, in which case the existing command will be +" replaced. +" +" pattern is a regex that will be used to determine which lines will be +" filtered. If the cursor line doesn't match the pattern, using the command +" will be a no-op, otherwise the cursor and all contiguous lines matching the +" pattern will be filtered. +" +" Each 'func' argument represents a function to be called. This function +" will have access to a:lines, a List containing one String per line being +" filtered. +com! -nargs=+ -bang AddTabularPipeline + \ call AddTabularPipeline(<q-args>, <bang>0) + +function! AddTabularPipeline(command, force) + try + let [ commandmap, rest ] = s:ChooseCommandMap(a:command) + + let name = matchstr(rest, '.\{-}\ze\s*/') + let pattern = substitute(rest, '.\{-}\s*\ze/', '', '') + + let commands = matchstr(pattern, '^/.\{-}\\\@<!\%(\\\\\)\{-}/\zs.*') + let pattern = matchstr(pattern, '/\zs.\{-}\\\@<!\%(\\\\\)\{-}\ze/') + + if empty(name) || empty(pattern) + throw "Invalid arguments!" + endif + + if !a:force && has_key(commandmap, name) + throw string(name) . " is already defined, use ! to overwrite." + endif + + let commandlist = s:SplitCommands(commands) + + if empty(commandlist) + throw "Must provide a list of functions!" + endif + + let commandmap[name] = { 'pattern' : pattern, 'commands' : commandlist } + catch + echohl ErrorMsg + echomsg "AddTabularPipeline: " . v:exception + echohl None + endtry +endfunction + +" Tabularize /pattern[/format] {{{2 +" Tabularize name +" +" Align text, either using the given pattern, or the command associated with +" the given name. +com! -nargs=* -range -complete=customlist,<SID>CompleteTabularizeCommand + \ Tabularize <line1>,<line2>call Tabularize(<q-args>) + +function! Tabularize(command, ...) range + let piperange_opt = {} + if a:0 + let piperange_opt = a:1 + endif + + if empty(a:command) + if !exists("s:last_tabularize_command") + echohl ErrorMsg + echomsg "Tabularize hasn't been called yet; no pattern/command to reuse!" + echohl None + return + endif + else + let s:last_tabularize_command = a:command + endif + + let command = s:last_tabularize_command + + let range = a:firstline . ',' . a:lastline + + try + let [ pattern, format ] = s:ParsePattern(command) + + if !empty(pattern) + let cmd = "tabular#TabularizeStrings(a:lines, " . string(pattern) + + if !empty(format) + let cmd .= "," . string(format) + endif + + let cmd .= ")" + + exe range . 'call tabular#PipeRangeWithOptions(pattern, [ cmd ], ' + \ . 'piperange_opt)' + else + if exists('b:TabularCommands') && has_key(b:TabularCommands, command) + let usercmd = b:TabularCommands[command] + elseif has_key(s:TabularCommands, command) + let usercmd = s:TabularCommands[command] + else + throw "Unrecognized command " . string(command) + endif + + exe range . 'call tabular#PipeRangeWithOptions(usercmd["pattern"], ' + \ . 'usercmd["commands"], piperange_opt)' + endif + catch + echohl ErrorMsg + echomsg "Tabularize: " . v:exception + echohl None + return + endtry +endfunction + +" GTabularize /pattern[/format] {{{2 +" GTabularize name +" +" Align text on only matching lines, either using the given pattern, or the +" command associated with the given name. Mnemonically, this is similar to +" the :global command, which takes some action on all rows matching a pattern +" in a range. This command is different from normal :Tabularize in 3 ways: +" 1) If a line in the range does not match the pattern, it will be left +" unchanged, and not in any way affect the outcome of other lines in the +" range (at least, normally - but Pipelines can and will still look at +" non-matching rows unless they are specifically written to be aware of +" tabular#DoGTabularize() and handle it appropriately). +" 2) No automatic range determination - :Tabularize automatically expands +" a single-line range (or a call with no range) to include all adjacent +" matching lines. That behavior does not make sense for this command. +" 3) If called without a range, it will act on all lines in the buffer (like +" :global) rather than only a single line +com! -nargs=* -range=% -complete=customlist,<SID>CompleteTabularizeCommand + \ GTabularize <line1>,<line2> + \ call Tabularize(<q-args>, { 'mode': 'GTabularize' } ) + +" Stupid vimscript crap, part 2 {{{1 +let &cpo = s:savecpo +unlet s:savecpo + +" vim:set sw=2 sts=2 fdm=marker: |