Skip to content

Instantly share code, notes, and snippets.

@iain
Created June 7, 2014 17:42
Show Gist options
  • Save iain/a41e7111d4bbf4243671 to your computer and use it in GitHub Desktop.
Save iain/a41e7111d4bbf4243671 to your computer and use it in GitHub Desktop.
" Automatically align multiline hashes in Ruby (Ruby 1.9 syntax only).
function! AlignRubyHashes()
" Only look for lines that start with a simple keyword, colon, space, and
" ending in a comma.
let p = '^\s*\w\+:\s.*,$'
" Don't do anything if there is no Tabularize, or there is no surrounding
" line that can be aligned with.
if exists(':Tabularize') && (getline(line('.')) =~# '^\s*\w\+:\s$') && (getline(line('.')-1) =~# p || getline(line('.')+1) =~# p)
" save current position because later command moves the cursor
let currentLine = line(".")
let currentCol = col(".")
call DoAlignRubyHashes()
" Since the current line cannot be aligned yet when it is too short, find
" a line to compare it with. This is either the previous line or the next
" line.
if (getline(currentLine-1) =~ p)
let compareLine = currentLine - 1
else
let compareLine = currentLine + 1
endif
" Calculate how many spaces to add.
let positionOfValues = strlen(matchstr(getline(compareLine), '^.*:\s\+'))
let missingSpaces = (positionOfValues - currentCol) + 1
" Add missing spaces
if missingSpaces > 0
exe currentLine.'s/$/'.repeat(' ', missingSpaces)
endif
" Set the cursor to the proper position
call cursor(currentLine, currentCol + missingSpaces)
endif
endfunction
function! DoAlignRubyHashes()
let p = '^\s*\w\+:\s.*,$'
" Calculate the range to act. Default Tabularize doesn't do this properly,
" because the range is determined by a different regex than the alignment
" regex.
let from = line('.')
while (getline(from - 1) =~ p)
let from -= 1
endwhile
let to = line('.')
while (getline(to + 1) =~ p)
let to += 1
endwhile
" Call Tabularize with the new range
exe from.','.to.'Tabularize/\(:.*\)\@<!\(:\s\)\zs/l1'
normal! 0
endfunction
function! EnableRubyHash()
inoremap <silent> <space> <space><Esc>:call AlignRubyHashes()<cr>a
endfunction
au FileType ruby call EnableRubyHash()
" Align after colons, but only the first one in the line,
" In normal mode, determine range automatically
nmap <Leader>a: :call DoAlignRubyHashes()<cr>
" In visual mode, the range is already fixed
vmap <Leader>a: :Tabularize/\(:.*\)\@<!:\zs/l1<cr>gv
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment