Last active
July 2, 2020 12:20
-
-
Save adscriven/fb72f3838189cb8d60025d83734c6d01 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
" 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