" targets.vim Provides additional text objects
" Author: Christian Wellenbrock <christian.wellenbrock@gmail.com>
" License: MIT license
if exists("g:loaded_targets") || &cp || v:version < 700
finish
endif
let g:loaded_targets = '0.4.5' " version number
let s:save_cpoptions = &cpoptions
set cpo&vim
function! s:addMapping1(mapType, mapping, aiAI)
if a:aiAI !=# ' '
silent! execute a:mapType . 'noremap <silent> <unique>' . a:aiAI . a:mapping
endif
endfunction
function! s:addMapping2(mapType, mapping, aiAI, nlNL)
if a:aiAI !=# ' ' && a:nlNL !=# ' '
silent! execute a:mapType . 'noremap <silent> <unique>' . a:aiAI . a:nlNL . a:mapping
endif
endfunction
" pair text objects (multi line objects with single line seek)
" cursor │ .........
" line │ a ( bbbbbb ) ( ccccc ) ( ddddd ) ( eeeee ) ( ffffff ) g
" command │ ││└2Il)┘│││││└Il)┘│││││└─I)┘│││││└In)┘│││││└2In)┘│││
" │ │└─2il)─┘│││└─il)─┘│││└──i)─┘│││└─in)─┘│││└─2in)─┘││
" │ ├──2al)──┘│├──al)──┘│├───a)──┘│├──an)──┘│├──2an)──┘│
" │ └──2Al)───┘└──Al)───┘└───A)───┘└──An)───┘└──2An)───┘
" cursor │ .........
" line │ a ( b ( cccccc ) d ) ( e ( fffff ) g ) ( h ( iiiiii ) j ) k
" command │ │││ ││└2Il)┘││││││││││ ││└─I)┘││││││││││ ││└2In)┘│││││││
" │ │││ │└─2il)─┘│││││││││ │└──i)─┘│││││││││ │└─2in)─┘││││││
" │ │││ ├──2al)──┘││││││││ ├───a)──┘││││││││ ├──2an)──┘│││││
" │ │││ └──2Al)───┘│││││││ └───A)───┘│││││││ └──2An)───┘││││
" │ ││└─────Il)────┘│││││└────2I)────┘│││││└─────In)────┘│││
" │ │└──────il)─────┘│││└─────2i)─────┘│││└──────in)─────┘││
" │ ├───────al)──────┘│├──────2a)──────┘│├───────an)──────┘│
" │ └───────Al)───────┘└──────2A)───────┘└───────An)───────┘
function! s:createPairTextObjects(mapType)
for trigger in split(g:targets_pairs, '\zs')
if trigger ==# ' '
continue
endif
let triggerMap = trigger . " :<C-U>call targets#" . a:mapType . "('" . trigger
call s:addMapping1(a:mapType, triggerMap . "ci', v:count1)<CR>", s:i)
call s:addMapping1(a:mapType, triggerMap . "ca', v:count1)<CR>", s:a)
call s:addMapping1(a:mapType, triggerMap . "cI', v:count1)<CR>", s:I)
call s:addMapping1(a:mapType, triggerMap . "cA', v:count1)<CR>", s:A)
call s:addMapping2(a:mapType, triggerMap . "ni', v:count1)<CR>", s:i, s:n)
call s:addMapping2(a:mapType, triggerMap . "na', v:count1)<CR>", s:a, s:n)
call s:addMapping2(a:mapType, triggerMap . "nI', v:count1)<CR>", s:I, s:n)
call s:addMapping2(a:mapType, triggerMap . "nA', v:count1)<CR>", s:A, s:n)
call s:addMapping2(a:mapType, triggerMap . "li', v:count1)<CR>", s:i, s:l)
call s:addMapping2(a:mapType, triggerMap . "la', v:count1)<CR>", s:a, s:l)
call s:addMapping2(a:mapType, triggerMap . "lI', v:count1)<CR>", s:I, s:l)
call s:addMapping2(a:mapType, triggerMap . "lA', v:count1)<CR>", s:A, s:l)
endfor
endfunction
" tag text objects work on tags (similar to pair text objects)
function! s:createTagTextObjects(mapType)
let trigger = g:targets_tagTrigger
let triggerMap = trigger . " :<C-U>call targets#" . a:mapType . "('" . trigger
call s:addMapping1(a:mapType, triggerMap . "ci', v:count1)<CR>", s:i)
call s:addMapping1(a:mapType, triggerMap . "ca', v:count1)<CR>", s:a)
call s:addMapping1(a:mapType, triggerMap . "cI', v:count1)<CR>", s:I)
call s:addMapping1(a:mapType, triggerMap . "cA', v:count1)<CR>", s:A)
call s:addMapping2(a:mapType, triggerMap . "ni', v:count1)<CR>", s:i, s:n)
call s:addMapping2(a:mapType, triggerMap . "na', v:count1)<CR>", s:a, s:n)
call s:addMapping2(a:mapType, triggerMap . "nI', v:count1)<CR>", s:I, s:n)
call s:addMapping2(a:mapType, triggerMap . "nA', v:count1)<CR>", s:A, s:n)
call s:addMapping2(a:mapType, triggerMap . "li', v:count1)<CR>", s:i, s:l)
call s:addMapping2(a:mapType, triggerMap . "la', v:count1)<CR>", s:a, s:l)
call s:addMapping2(a:mapType, triggerMap . "lI', v:count1)<CR>", s:I, s:l)
call s:addMapping2(a:mapType, triggerMap . "lA', v:count1)<CR>", s:A, s:l)
endfunction
" quote text objects expand into quote (by counting quote signs)
" `aN'` is a shortcut for `2an'` to jump from within one quote into the
" next one, instead of the quote in between
" cursor │ ........
" line │ a ' bbbbb ' ccccc ' dddd ' eeeee ' fffff ' g
" command │ ││└IL'┘│││└Il'┘│││└I'┘│││└In'┘│││└IN'┘│││
" │ │└─iL'─┘│├─il'─┘│├─i'─┘│├─in'─┘│├─iN'─┘││
" │ ├──aL'──┤│ ├┼─a'──┤│ ├┼─aN'──┘│
" │ └──AL'──┼┘ ├┼─A'──┼┘ ├┼─AN'───┘
" │ ├──al'──┘│ ├──an'──┘│
" │ └──Al'───┘ └──An'───┘
" cursor │ .......... │ ...... │ ..........
" line │ a ' bbbb ' c '' │ ' a ' bbbb ' c ' │ '' b ' cccc ' d
" command │ ││└I'┘│││ │ ││└I'┘│││ │ ││└I'┘│││
" │ │└─i'─┘││ │ │└─i'─┘││ │ │└─i'─┘││
" │ ├──a'──┘│ │ ├──a'──┘│ │ ├──a'──┘│
" │ └──A'───┘ │ └──A'───┘ │ └──A'───┘
function! s:createQuoteTextObjects(mapType)
" quote text objects
for trigger in split(g:targets_quotes, '\zs')
if trigger ==# " "
continue
elseif trigger ==# "'"
let triggerMap = "' :<C-U>call targets#" . a:mapType . "('''"
else
let triggerMap = trigger . " :<C-U>call targets#" . a:mapType . "('" . trigger
endif
call s:addMapping1(a:mapType, triggerMap . "ci', v:count1)<CR>", s:i)
call s:addMapping1(a:mapType, triggerMap . "ca', v:count1)<CR>", s:a)
call s:addMapping1(a:mapType, triggerMap . "cI', v:count1)<CR>", s:I)
call s:addMapping1(a:mapType, triggerMap . "cA', v:count1)<CR>", s:A)
call s:addMapping2(a:mapType, triggerMap . "ni', v:count1)<CR>", s:i, s:n)
call s:addMapping2(a:mapType, triggerMap . "na', v:count1)<CR>", s:a, s:n)
call s:addMapping2(a:mapType, triggerMap . "nI', v:count1)<CR>", s:I, s:n)
call s:addMapping2(a:mapType, triggerMap . "nA', v:count1)<CR>", s:A, s:n)
call s:addMapping2(a:mapType, triggerMap . "li', v:count1)<CR>", s:i, s:l)
call s:addMapping2(a:mapType, triggerMap . "la', v:count1)<CR>", s:a, s:l)
call s:addMapping2(a:mapType, triggerMap . "lI', v:count1)<CR>", s:I, s:l)
call s:addMapping2(a:mapType, triggerMap . "lA', v:count1)<CR>", s:A, s:l)
endfor
endfunction
" separator text objects expand to the right
" cursor │ .............
" line │ a ' bbbbbbb ' c ' dddddd ' e ' fffffff ' g ~
" command │ ││└ Il' ┘│││ ││└ I' ┘│││ ││└ In' ┘│││
" │ │└─ il' ─┘││ │└─ i' ─┘││ │└─ in' ─┘││
" │ ├── al' ──┘│ ├── a' ──┘│ ├── an' ──┘│
" │ └── Al' ───┘ └── A' ───┘ └── An' ───┘
" cursor │ ......... │ ..........
" line │ a , bbbb , c , d │ a , b , cccc , d
" command │ ││└I,┘│ │ │ ││└I,┘│ │
" │ │└─i,─┤ │ │ │└─i,─┤ │
" │ ├──a,─┘ │ │ ├──a,─┘ │
" │ └──A,───┘ │ └──A,───┘
function! s:createSeparatorTextObjects(mapType)
" separator text objects
for trigger in split(g:targets_separators, '\zs')
if trigger ==# ' '
continue
elseif trigger ==# '|'
let trigger = '\|'
endif
let triggerMap = trigger . " :<C-U>call targets#" . a:mapType . "('" . trigger
call s:addMapping1(a:mapType, triggerMap . "ci', v:count1)<CR>", s:i)
call s:addMapping1(a:mapType, triggerMap . "ca', v:count1)<CR>", s:a)
call s:addMapping1(a:mapType, triggerMap . "cI', v:count1)<CR>", s:I)
call s:addMapping1(a:mapType, triggerMap . "cA', v:count1)<CR>", s:A)
call s:addMapping2(a:mapType, triggerMap . "ni', v:count1)<CR>", s:i, s:n)
call s:addMapping2(a:mapType, triggerMap . "na', v:count1)<CR>", s:a, s:n)
call s:addMapping2(a:mapType, triggerMap . "nI', v:count1)<CR>", s:I, s:n)
call s:addMapping2(a:mapType, triggerMap . "nA', v:count1)<CR>", s:A, s:n)
call s:addMapping2(a:mapType, triggerMap . "li', v:count1)<CR>", s:i, s:l)
call s:addMapping2(a:mapType, triggerMap . "la', v:count1)<CR>", s:a, s:l)
call s:addMapping2(a:mapType, triggerMap . "lI', v:count1)<CR>", s:I, s:l)
call s:addMapping2(a:mapType, triggerMap . "lA', v:count1)<CR>", s:A, s:l)
call s:addMapping2(a:mapType, triggerMap . "Ni', v:count1)<CR>", s:i, s:N)
call s:addMapping2(a:mapType, triggerMap . "Na', v:count1)<CR>", s:a, s:N)
call s:addMapping2(a:mapType, triggerMap . "NI', v:count1)<CR>", s:I, s:N)
call s:addMapping2(a:mapType, triggerMap . "NA', v:count1)<CR>", s:A, s:N)
call s:addMapping2(a:mapType, triggerMap . "Li', v:count1)<CR>", s:i, s:L)
call s:addMapping2(a:mapType, triggerMap . "La', v:count1)<CR>", s:a, s:L)
call s:addMapping2(a:mapType, triggerMap . "LI', v:count1)<CR>", s:I, s:L)
call s:addMapping2(a:mapType, triggerMap . "LA', v:count1)<CR>", s:A, s:L)
endfor
endfunction
" argument text objects expand to the right
" cursor │ .........
" line │ a ( bbbbbb , ccccccc , d ( eeeeee , fffffff ) , gggggg ) h
" command │ ││├2Ila┘│││└─Ila─┘││││ ││├─Ia─┘│││└─Ina─┘│││││└2Ina┘│ │
" │ │└┼2ila─┘│├──ila──┤│││ │└┼─ia──┘│├──ina──┤│││├─2ina─┤ │
" │ │ └2ala──┼┤ ││││ │ └─aa───┼┤ │││├┼─2ana─┘ │
" │ └──2Ala──┼┘ ││││ └───Aa───┼┘ │││└┼─2Ana───┘
" │ ├───ala──┘│││ ├───ana──┘││ │
" │ └───Ala───┼┤│ └───Ana───┼┤ │
" │ ││└─────2Ia────────────┘│ │
" │ │└──────2ia─────────────┤ │
" │ ├───────2aa─────────────┘ │
" │ └───────2Aa───────────────┘
function! s:createArgTextObjects(mapType)
let trigger = g:targets_argTrigger
let triggerMap = trigger . " :<C-U>call targets#" . a:mapType . "('" . trigger
call s:addMapping1(a:mapType, triggerMap . "ci', v:count1)<CR>", s:i)
call s:addMapping1(a:mapType, triggerMap . "ca', v:count1)<CR>", s:a)
call s:addMapping1(a:mapType, triggerMap . "cI', v:count1)<CR>", s:I)
call s:addMapping1(a:mapType, triggerMap . "cA', v:count1)<CR>", s:A)
call s:addMapping2(a:mapType, triggerMap . "ni', v:count1)<CR>", s:i, s:n)
call s:addMapping2(a:mapType, triggerMap . "na', v:count1)<CR>", s:a, s:n)
call s:addMapping2(a:mapType, triggerMap . "nI', v:count1)<CR>", s:I, s:n)
call s:addMapping2(a:mapType, triggerMap . "nA', v:count1)<CR>", s:A, s:n)
call s:addMapping2(a:mapType, triggerMap . "li', v:count1)<CR>", s:i, s:l)
call s:addMapping2(a:mapType, triggerMap . "la', v:count1)<CR>", s:a, s:l)
call s:addMapping2(a:mapType, triggerMap . "lI', v:count1)<CR>", s:I, s:l)
call s:addMapping2(a:mapType, triggerMap . "lA', v:count1)<CR>", s:A, s:l)
endfunction
" add expression mappings for `A` and `I` in visual mode #23 unless
" deactivated #49. Manually make mappings for older verions of vim #117.
function! s:addVisualMappings()
if v:version >= 704 || (v:version == 703 && has('patch338'))
silent! execute 'xnoremap <expr> <silent> <unique> ' . s:i . " targets#e('i')"
silent! execute 'xnoremap <expr> <silent> <unique> ' . s:a . " targets#e('a')"
silent! execute 'xnoremap <expr> <silent> <unique> ' . s:I . " targets#e('I')"
silent! execute 'xnoremap <expr> <silent> <unique> ' . s:A . " targets#e('A')"
else
call s:createPairTextObjects('x')
call s:createTagTextObjects('x')
call s:createQuoteTextObjects('x')
call s:createSeparatorTextObjects('x')
call s:createArgTextObjects('x')
endif
endfunction
function! s:loadSettings()
if !exists('g:targets_aiAI')
let g:targets_aiAI = 'aiAI'
endif
if !exists('g:targets_nlNL')
let g:targets_nlNL = 'nlNL'
endif
if !exists('g:targets_pairs')
let g:targets_pairs = '()b {}B [] <>'
endif
if !exists('g:targets_quotes')
let g:targets_quotes = '" '' `'
endif
if !exists('g:targets_separators')
let g:targets_separators = ', . ; : + - = ~ _ * # / \ | & $'
endif
if !exists('g:targets_tagTrigger')
let g:targets_tagTrigger = 't'
endif
if !exists('g:targets_argTrigger')
let g:targets_argTrigger = 'a'
endif
if !exists('g:targets_argOpening')
let g:targets_argOpening = '[([]'
endif
if !exists('g:targets_argClosing')
let g:targets_argClosing = '[])]'
endif
if !exists('g:targets_argSeparator')
let g:targets_argSeparator = ','
endif
if !exists('g:targets_seekRanges')
let g:targets_seekRanges = 'cr cb cB lc ac Ac lr rr ll lb ar ab lB Ar aB Ab AB rb al rB Al bb aa bB Aa BB AA'
endif
if !exists('g:targets_jumpRanges')
let g:targets_jumpRanges = 'bb bB BB aa Aa AA'
endif
let [s:a, s:i, s:A, s:I] = split(g:targets_aiAI, '\zs')
let [s:n, s:l, s:N, s:L] = split(g:targets_nlNL, '\zs')
endfunction
call s:loadSettings()
" create the text objects (current total count: 544)
" more specific ones first for #145
call s:createTagTextObjects('o')
call s:createArgTextObjects('o')
call s:createPairTextObjects('o')
call s:createQuoteTextObjects('o')
call s:createSeparatorTextObjects('o')
call s:addVisualMappings()
let &cpoptions = s:save_cpoptions
unlet s:save_cpoptions