Skip to content

Instantly share code, notes, and snippets.

@adscriven
Last active September 12, 2020 23:58
Show Gist options
  • Select an option

  • Save adscriven/7deb37e1a5a42759d6e6d703ecda9475 to your computer and use it in GitHub Desktop.

Select an option

Save adscriven/7deb37e1a5a42759d6e6d703ecda9475 to your computer and use it in GitHub Desktop.
" textobj-indent.vim -- ic, ac, ai, ii, aI indentation text objects.
" https://gist.githubusercontent.com/adscriven/7deb37e1a5a42759d6e6d703ecda9475
" SUMMARY
" This plugin defines the following mappings for Operator-pending mode
" and Visual mode.
" ic -- select contiguous lines (i.e. stopping at paragraph
" boundaries) of the same indentation.
" iC -- select contiguous lines (i.e. stopping at paragraph
" boundaries) of the same or greater indentation (big C selects
" more stuff).
" ac, aC -- same but includes trailing blank lines.
" ii -- select a linewise block of the same indentation as the cursor
" line.
" ai -- select a linewise block of the same indentation as the cursor
" line, plus a single preceding line with less indentation.
" aI -- select a linewise block of the same indentation as the cursor
" line, plus a single preceding line with less indentation, and
" a single succeeding line with less indentation.
" II -- The same as aI.
" REQUIREMENTS
" Vim 7.4
" INSTALLATION
" Chuck it in ~/.vim/plugin
" CONFIGURATION
" None. ai, ii, and aI Operator-pending and Visual mode mappings are
" defined by this plugin.
" FEATURES
" The defined text objects support registers, counts, and repeating in
" Visual mode. E.g.
" viiii
" v2ii
" >ii
" >2ii
" 2>ii ...move cursor... dot
" N.B. the ic and ac text objects do not take counts. I don't tend to
" use them in practice and it doesn't seem particularly useful here.
" TODO
" dot doesn't remember the count (use opfunc?).
" CREDITS
" chandergovind in r/vim for the idea for c and C.
fun! s:viscontindent(a_or_i, exact)
let v = winsaveview()
let cur = prevnonblank(line('.'))
let i = indent(cur)
exe cur
let first = line("'{") == 1 ? 0 : line("'{")
if a:exact
'{,g/^/ let first = indent(line('.')) != i ? line('.') : first
else
'{,g/^/ let first = indent(line('.')) < i ? line('.') : first
endif
let first += 1
let last = 0
if a:exact
,'}g/^/ let last = indent(line('.')) != i && !last ? line('.') : last
else
,'}g/^/ let last = indent(line('.')) < i && !last ? line('.') : last
endif
if a:a_or_i == 'a'
let last = nextnonblank(last)
endif
let last = last ? last - 1 : line('$')
call winrestview(v)
exe "norm!\<c-\>\<c-n>" . last . 'GV' . first . 'G'
endfun
ono <silent> ic :<c-u>call <SID>viscontindent("i", 1)<cr>
xno <silent> ic :<c-u>call <SID>viscontindent("i", 1)<cr>
ono <silent> ac :<c-u>call <SID>viscontindent("a", 1)<cr>
xno <silent> ac :<c-u>call <SID>viscontindent("a", 1)<cr>
ono <silent> iC :<c-u>call <SID>viscontindent("i", 0)<cr>
xno <silent> iC :<c-u>call <SID>viscontindent("i", 0)<cr>
ono <silent> aC :<c-u>call <SID>viscontindent("a", 0)<cr>
xno <silent> aC :<c-u>call <SID>viscontindent("a", 0)<cr>
fun! s:visindent(a_or_i, vis, n, prev)
let v = winsaveview()
let off = a:a_or_i == 'ii' ? 1 : 0
if a:prev
let cur = prevnonblank(a:prev - off)
elseif a:vis && visualmode() ==# 'V'
let cur = prevnonblank(line("'<"))
let p = prevnonblank(line("'<")-1)
let n = prevnonblank(line("'>")+1)
let i = indent(cur)
let cur = indent(p)>=i || indent(n)>=i ? cur : p
else
let cur = nextnonblank(line('.'))
endif
let i = indent(cur)
let [prev, next] = [cur, cur]
exe cur
1,g/^/ let prev = getline('.') != '' && indent(line('.')) < i
\ ? line('.')
\ : prev
,$g/^/ let next = getline('.') != '' && indent(line('.')) < i && next == cur
\ ? line('.')
\ : next
if a:a_or_i ==# 'ii'
let prev = nextnonblank(prev == cur ? 1 : prev + 1)
endif
if a:a_or_i ==# 'ai' && prev == cur
let prev = 1
endif
if a:a_or_i ==# 'aI'
if prev == cur
let prev = 1
endif
if next == cur
let next = line('$')
else
let next = nextnonblank(next + 1)
endif
endif
let next = prevnonblank(next == cur ? line('$') : next - 1)
call winrestview(v)
if a:n > 1
return s:visindent(a:a_or_i, a:vis, a:n - 1, prev)
else
return 'norm!' . next . 'GV' . prev . 'G'
endif
endfun
ono <expr> <silent> ai '<esc>"'.v:register.v:operator.
\ ':<c-u>exe <SID>visindent("ai", 0, v:prevcount, 0)<cr>'
xno <silent> ai :<c-u>exe <SID>visindent('ai', 1, v:count1, 0)<cr>
ono <expr> <silent> ii '<esc>"'.v:register.v:operator.
\ ':<c-u>exe <SID>visindent("ii", 0, v:prevcount, 0)<cr>'
xno <silent> ii :<c-u>exe <SID>visindent('ii', 1, v:count1, 0)<cr>
ono <expr> <silent> aI '<esc>"'.v:register.v:operator.
\ ':<c-u>exe <SID>visindent("aI", 0, v:prevcount, 0)<cr>'
xno <silent> aI :<c-u>exe <SID>visindent('aI', 1, v:count1, 0)<cr>
ono <expr> <silent> II '<esc>"'.v:register.v:operator.\
\ ':<c-u>exe <SID>visindent("aI", 0, v:prevcount, 0)<cr>'
xno <silent> II :<c-u>exe <SID>visindent('aI', 1, v:count1, 0)<cr>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment