User Tools

Site Tools


vim

VIM snippets

Redirect Command output

:help :redir

Align columns in ASCII-art table (ala wiki syntax)

'<,'>v/^|[^|]\+\%27v|/ s/\(^|[^|]\+\)|/\1 |/

To repeat this command numerous times, record executing it as a macro, then use normal macro repetition.

Wtf?

The break down is below, but the gist is that we find lines of text which don't have a “|” in the column we want, and then use a substition to grab the text before the second “|” and add a space between them, hence pushing the “|” one column to the right. You then repeat this command until no substitions take place.

'<,'>            From mark "<" to mark ">" execute the following command

v/ --- /         Check each line against Regular Expression "---", if it
                 **doesn't** match do the following commands

^|[^|]\+\%27v|   Match a vertical bar, followed by 1-or-more "not vertical bar"
		 characters ( [^|]\+ ), followed by an assertion at we're in
                 visual column 27 ( \%27v ), followed by a vertical bar

s/ --- / ### /   Substitute text matching RegExp "---" with text in "###"

\(^|[^|]\+\)|    (Match) Capture between \( and \) a vertical bar followed by 1
		 or more not-vertical-bars. This capture should be immediately
                 followed by a vertical bar

\1 |             (Replacement) Put our first captured group back, followed by a
                 space, followed by a vertical bar.

A complete function for aligning ASCII-art tables

To use: source this into Vim (“:source <filename>”), and then invoke AlignTable() over the range of the table. EG Visually select table and then “'<,'>call AlignTable()”

" Align a single ASCII-art table column
" tcol: Which column of the table to align (i.e. first column = 1, second = 2 etc)
" vcol: Align table column to which virtual/visual column on the screen?
function! AlignTableColumn ( tcol, vcol ) range
    let i = a:vcol - a:tcol " Worst case
    while i
	" Edge one screen column closer to desired location
	execute 'silent! ' . a:firstline . ',' . a:lastline . 'v/^\(\(|[^|]*\)\{' . a:tcol . '}\)\%' . a:vcol . 'v|/ s/^\(\(|[^|]*\)\{' . a:tcol . '}\)|/\1 |/'
	let i -= 1
    endwhile
endfunction
 
" Align a whole ASCII-art table
" Tables are expected to be drawn using "|" characters, including the header
"
" Usage: Invoke this function with the range of lines the table occupies,
" including the header - which will be used as the "desired column location"
"
" TODO: Tally the maximum width for each column by scanning all rows, and use
" these values to calculate new column boundry locations
function! AlignTable() range
    let header = getline(a:firstline)
    let bars = 0
 
    let i = 0
    " Count number of "|"s
    while i < strlen(header)
	if header[i] == '|'
	    let bars += 1
	endif
	let i += 1
    endwhile
    unlet i
    unlet header
 
    " Now get column widths for each row, keeping the maximum in colwidth
    let colwidth = []
    let i = bars
    " Init list of correct length
    while i
	let colwidth += [0]
	let i -= 1
    endwhile
    unlet i
 
    let i = a:firstline
    while i <= a:lastline
	let row = getline(i)
	let curbar = 0
	let pos = 0
	let poslist = []
	while curbar < bars
	    let pos = match(row, '|', pos)
	    let poslist += [pos]
	    let pos += 1 " Move past current match, ready for next
	    if len(poslist) > 1
		if colwidth[curbar] < ( poslist[curbar] - poslist[(curbar-1)] )
		    let colwidth[curbar] = ( poslist[curbar] - poslist[(curbar-1)] )
		endif
	    endif
	    let curbar += 1
	endwhile
	let i += 1
    endwhile
 
    let poslist = [ match(getline(a:firstline), '|') ]
    call remove(colwidth, 0) " Strip first column (always width 0)
    for width in colwidth
	let poslist += [ (poslist[(len(poslist)-1)] + width) ]
    endfor
 
    " NB There is one more bar than there are cols, and we ignore the first
    " bar
    let i = 1
    call remove(poslist, 0)
    for vcol in poslist
	" Note that every bar must be moved at least once to avoid bugs, hence
	" the (vcol+1) below
	execute (a:firstline).",".a:lastline."call AlignTableColumn(".i.", ".(vcol+1).")"
	let i += 1
    endfor
endfunction

XMLFolding

Adapted from XML Folding : Folds XML / HTML Tags, CDATA and comments, by Thadeu Aparecido Coelho de Paula.

" Basic vim commands for folding definition
syn sync fromstart
set foldmethod=syntax
 
"                                                ┌ Up to end-of-tag                                                      
"                             Name of tag ╗      │      ┌ End-of-tag not preceeded by "/"                                
"External capture ("\z1" in end= param) ┐ ║      │      │   ┌ End-of-tag                                                 
"            Normal capture ("\1")═╦════╪═╬════╗ │      │   │ ┌ End-of-match                                             
"       Forbidden first chars ┐    ║ ┌──┴─╫──┐ ║ │      │   │ │  ┌ Assert that a matching closing tag occurs later   
"            Start of tag ┐┌──┴───┐║ │  ╔═╩╗ │ ║┌┴────┐┌┴──┐│┌┴┐┌┴──────┐                                               
syn region XMLFold start=#<[/?!]\@!\(\z(\S\+\)\)\_[^>]*/\@<!>\ze\_.*</\1># end=#</\z1># fold transparent keepend extend
"                                                                               └───┬┘                                  
"                                                          Closing tag of same name ┘                                   
 
syn match XMLCData "<!\[CDATA\[\_.\{-}\]\]>" fold transparent extend
syn match XMLCommentFold "<!--\_.\{-}-->" fold transparent extend 
 
 
" Label shown for folded lines
set foldtext=XMLFoldLabel()
 fun! XMLFoldLabel()
  let getcontent = substitute(getline(v:foldstart), "^[[:space:]]*", "", 'g')
	let linestart = substitute(v:folddashes, ".", '»', 'g')
	return linestart . " " . getcontent
endfunction

(The line drawings were made with the excellent BoxDraw vim plugin by Andrew Nikitin.)

Win32 Paths

When under Cygwin, 'ifsname' is set to the Unix default, which means that paths such as dir\to\file are broken up into sections when you try to <C-w><C-f> or gf to them.

You can fix this with:

set isfname=@,48-57,/,\\,.,-,_,+,,,#,$,%,{,},[,],:,@-@,!,~,=

Pop-up menu colours

The default pop-up menu colour for auto-complete (e.g. ^X^O) is grey-on-pink, which is hard to read. So I added the following to my desert256 colour scheme:

" ~/.vim/colors/desert256.vim
"Pmenu
call <SID>X("Pmenu", "ffffff", "cc00cc", "")
call <SID>X("PmenuSel", "ffffff", "990044", "")
call <SID>X("PmenuSbar", "ffffff", "550077", "")
call <SID>X("PmenuThumb", "ffffff", "440088", "")

See also this post and :help Pmenu.

Here's how it looks:

Screenshot showing VIM's popup menu

I really like the function summary in the lower pane, and all this for a Python module I wrote myself! I'm amazed that vim can work out the type of jobtags and then parse the classes help!

vim.txt · Last modified: 2009/01/22 10:59 (external edit)