Skip to content

Instantly share code, notes, and snippets.

@adscriven
Last active July 2, 2020 12:20
Show Gist options
  • Save adscriven/fb72f3838189cb8d60025d83734c6d01 to your computer and use it in GitHub Desktop.
Save adscriven/fb72f3838189cb8d60025d83734c6d01 to your computer and use it in GitHub Desktop.
" vertregion.vim -- jump to the start and end of vertical regions
" SUMMARY
" Allow the cursor to move to the start or end of a vertical region of
" text. If you are familiar with <C-Up> and <C-Down> in Microsoft
" Excel to move to the edge of a data region, this will feel natural.
" INSTALLATION
" Chuck it in ~/.vim/plugin
" CONFIGURATION
" By default only <plug> mappings are defined. As a convenience you
" may set a global variable in your vimrc to have the up and down
" mappings created for you.
" E.g.
" let g:vertregion_mappings = {'up': '\k', 'down': '\j'}
" or
" let g:vertregion_mappings = {'up': '(', 'down': ')'}
" DESCRIPTION
" This plugin allows the cursor to move either to the start or end of
" the next vertical region of text, whichever comes first.
" A vertical region is defined as a contiguous vertical sequence of
" either non-whitespace characters, or a single space character
" immediately surrounded by non-whitespace characters.
" The second part of the definition above allows the cursor to land on
" a space provided there is non-whitespace either side. This stops the
" cursor travelling through lines where you might not expect it to.
" It's useful for selecting blocks of text, jumping to the start
" and end of blocks of text, or for jumping across whitespace gaps
" to the next block of text. If the cursor is on the first non-blank
" of a line, you can use it to jump to the next block with the same
" indentation.
" FEATURES
" * It supports Normal mode, Visual mode, Operator-pending mode, counts,
" and you can use v and V with the Operator-pending mappings.
" * It sets mark ' if the cursor moved.
" * It doesn't wrap around the ends of the buffer.
let s:cpo = &cpo
set cpo&vim
fun! s:searchboundary(dir, count, mode)
" XXX: gv must come before the call to virtcol(), otherwise the
" cursor moves to the start of the line in linewise Visual mode.
if a:mode == 'v'
norm!gv
endif
let n = a:count
let rgnchar = '\%(\S\|\S\@<= \S\@=\)'
let v = virtcol('.')
let initpos = getcurpos()
let curcol = '\%' . v . 'v'
let nextline = '.*\n.*'
" A region delimiting line has no character at the cursor column ...
let delim = '\%(^\%(' . curcol . '\@!.\)*$'
" ... or has whitespace at the cursor column, preceded by whitespace
" or the start of the line ...
let delim .= '\|\%(\s\|^\)' . curcol . '\s'
" ... or has whitespace at the cursor column, succeeded by whitespace
" or the end of the line.
let delim .= '\|' . curcol . '\s\%(\s\|$\)\)'
" Need to also handle start of buffer here.
let rgnstart = '\%(\%^.*\|' . delim. nextline . '\)\zs' . curcol . rgnchar
let rgnend = curcol . rgnchar . nextline . delim
let boundary = rgnstart . '\|' . rgnend
let here = line('.')
while n
let there = search(boundary, 'W' . a:dir)
if there == here
break
endif
let here = there
let n -= 1
endwhile
if getcurpos() != initpos
call setpos("''", initpos)
endif
endfun
nno <silent> <plug>[vertregion-down-n] :<c-u>call <sid>searchboundary('', v:count1, '')<cr>
nno <silent> <plug>[vertregion-up-n] :<c-u>call <sid>searchboundary('b', v:count1, '')<cr>
ono <silent> <plug>[vertregion-down-o] :<c-u>call <sid>searchboundary('', v:count1, '')<cr>
ono <silent> <plug>[vertregion-up-o] :<c-u>call <sid>searchboundary('b', v:count1, '')<cr>
xno <silent> <plug>[vertregion-down-x] :<c-u>call <sid>searchboundary('', v:count1, 'v')<cr>
xno <silent> <plug>[vertregion-up-x] :<c-u>call <sid>searchboundary('b', v:count1, 'v')<cr>
let s:key = get(g:, 'vertregion_mappings', {})
if !empty(s:key)
exe 'nmap <silent> ' . s:key.down . ' <plug>[vertregion-down-n]'
exe 'nmap <silent> ' . s:key.up . ' <plug>[vertregion-up-n]'
exe 'omap <silent> ' . s:key.down . ' <plug>[vertregion-down-o]'
exe 'omap <silent> ' . s:key.up . ' <plug>[vertregion-up-o]'
exe 'xmap <silent> ' . s:key.down . ' <plug>[vertregion-down-x]'
exe 'xmap <silent> ' . s:key.up . ' <plug>[vertregion-up-x]'
endif
let &cpo = s:cpo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment