Merge pull request #319 from lfilho/next-textobject-update
Updating next-textobject to Steve Losh's new version
This commit is contained in:
commit
c6ce42485a
@ -1,29 +1,136 @@
|
||||
" Stolen from Steve Losh
|
||||
" https://bitbucket.org/sjl/dotfiles/src/tip/vim/.vimrc
|
||||
" https://github.com/sjl/dotfiles/blob/master/vim/vimrc#L1380
|
||||
"
|
||||
" Motion for "next/last object". For example, "din(" would go to the next "()"
|
||||
" pair and delete its contents.
|
||||
onoremap an :<c-u>call <SID>NextTextObject('a', 'f')<cr>
|
||||
xnoremap an :<c-u>call <SID>NextTextObject('a', 'f')<cr>
|
||||
onoremap in :<c-u>call <SID>NextTextObject('i', 'f')<cr>
|
||||
xnoremap in :<c-u>call <SID>NextTextObject('i', 'f')<cr>
|
||||
" Motion for "next/last object". "Last" here means "previous", not "final".
|
||||
" Unfortunately the "p" motion was already taken for paragraphs.
|
||||
"
|
||||
" Next acts on the next object of the given type, last acts on the previous
|
||||
" object of the given type. These don't necessarily have to be in the current
|
||||
" line.
|
||||
"
|
||||
" Currently works for (, [, {, and their shortcuts b, r, B.
|
||||
"
|
||||
" Next kind of works for ' and " as long as there are no escaped versions of
|
||||
" them in the string (TODO: fix that). Last is currently broken for quotes
|
||||
" (TODO: fix that).
|
||||
"
|
||||
" Some examples (C marks cursor positions, V means visually selected):
|
||||
"
|
||||
" din' -> delete in next single quotes foo = bar('spam')
|
||||
" C
|
||||
" foo = bar('')
|
||||
" C
|
||||
"
|
||||
" canb -> change around next parens foo = bar('spam')
|
||||
" C
|
||||
" foo = bar
|
||||
" C
|
||||
"
|
||||
" vin" -> select inside next double quotes print "hello ", name
|
||||
" C
|
||||
" print "hello ", name
|
||||
" VVVVVV
|
||||
|
||||
onoremap an :<c-u>call <SID>NextTextObject('a', '/')<cr>
|
||||
xnoremap an :<c-u>call <SID>NextTextObject('a', '/')<cr>
|
||||
onoremap in :<c-u>call <SID>NextTextObject('i', '/')<cr>
|
||||
xnoremap in :<c-u>call <SID>NextTextObject('i', '/')<cr>
|
||||
|
||||
onoremap al :<c-u>call <SID>NextTextObject('a', '?')<cr>
|
||||
xnoremap al :<c-u>call <SID>NextTextObject('a', '?')<cr>
|
||||
onoremap il :<c-u>call <SID>NextTextObject('i', '?')<cr>
|
||||
xnoremap il :<c-u>call <SID>NextTextObject('i', '?')<cr>
|
||||
|
||||
onoremap al :<c-u>call <SID>NextTextObject('a', 'F')<cr>
|
||||
xnoremap al :<c-u>call <SID>NextTextObject('a', 'F')<cr>
|
||||
onoremap il :<c-u>call <SID>NextTextObject('i', 'F')<cr>
|
||||
xnoremap il :<c-u>call <SID>NextTextObject('i', 'F')<cr>
|
||||
|
||||
function! s:NextTextObject(motion, dir)
|
||||
let c = nr2char(getchar())
|
||||
let c = nr2char(getchar())
|
||||
let d = ''
|
||||
|
||||
if c ==# "b"
|
||||
let c = "("
|
||||
elseif c ==# "B"
|
||||
let c = "{"
|
||||
elseif c ==# "d"
|
||||
let c = "["
|
||||
endif
|
||||
if c ==# "b" || c ==# "(" || c ==# ")"
|
||||
let c = "("
|
||||
elseif c ==# "B" || c ==# "{" || c ==# "}"
|
||||
let c = "{"
|
||||
elseif c ==# "r" || c ==# "[" || c ==# "]"
|
||||
let c = "["
|
||||
elseif c ==# "'"
|
||||
let c = "'"
|
||||
elseif c ==# '"'
|
||||
let c = '"'
|
||||
else
|
||||
return
|
||||
endif
|
||||
|
||||
exe "normal! ".a:dir.c."v".a:motion.c
|
||||
" Find the next opening-whatever.
|
||||
execute "normal! " . a:dir . c . "\<cr>"
|
||||
|
||||
if a:motion ==# 'a'
|
||||
" If we're doing an 'around' method, we just need to select around it
|
||||
" and we can bail out to Vim.
|
||||
execute "normal! va" . c
|
||||
else
|
||||
" Otherwise we're looking at an 'inside' motion. Unfortunately these
|
||||
" get tricky when you're dealing with an empty set of delimiters because
|
||||
" Vim does the wrong thing when you say vi(.
|
||||
|
||||
let open = ''
|
||||
let close = ''
|
||||
|
||||
if c ==# "("
|
||||
let open = "("
|
||||
let close = ")"
|
||||
elseif c ==# "{"
|
||||
let open = "{"
|
||||
let close = "}"
|
||||
elseif c ==# "["
|
||||
let open = "\\["
|
||||
let close = "\\]"
|
||||
elseif c ==# "'"
|
||||
let open = "'"
|
||||
let close = "'"
|
||||
elseif c ==# '"'
|
||||
let open = '"'
|
||||
let close = '"'
|
||||
endif
|
||||
|
||||
" We'll start at the current delimiter.
|
||||
let start_pos = getpos('.')
|
||||
let start_l = start_pos[1]
|
||||
let start_c = start_pos[2]
|
||||
|
||||
" Then we'll find it's matching end delimiter.
|
||||
if c ==# "'" || c ==# '"'
|
||||
" searchpairpos() doesn't work for quotes, because fuck me.
|
||||
let end_pos = searchpos(open)
|
||||
else
|
||||
let end_pos = searchpairpos(open, '', close)
|
||||
endif
|
||||
|
||||
let end_l = end_pos[0]
|
||||
let end_c = end_pos[1]
|
||||
|
||||
call setpos('.', start_pos)
|
||||
|
||||
if start_l == end_l && start_c == (end_c - 1)
|
||||
" We're in an empty set of delimiters. We'll append an "x"
|
||||
" character and select that so most Vim commands will do something
|
||||
" sane. v is gonna be weird, and so is y. Oh well.
|
||||
execute "normal! ax\<esc>\<left>"
|
||||
execute "normal! vi" . c
|
||||
elseif start_l == end_l && start_c == (end_c - 2)
|
||||
" We're on a set of delimiters that contain a single, non-newline
|
||||
" character. We can just select that and we're done.
|
||||
execute "normal! vi" . c
|
||||
else
|
||||
" Otherwise these delimiters contain something. But we're still not
|
||||
" sure Vim's gonna work, because if they contain nothing but
|
||||
" newlines Vim still does the wrong thing. So we'll manually select
|
||||
" the guts ourselves.
|
||||
let whichwrap = &whichwrap
|
||||
set whichwrap+=h,l
|
||||
|
||||
execute "normal! va" . c . "hol"
|
||||
|
||||
let &whichwrap = whichwrap
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user