Created

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

Two useful text objects for coffeescript

View indent.vim
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
" See http://andrewradev.com/2012/04/03/manipulating-coffeescript-with-vim-part-1-text-objects/
" for details on the implementation
 
onoremap ii :<c-u>call <SID>IndentTextObject()<cr>
onoremap аi :<c-u>call <SID>IndentTextObject()<cr>
xnoremap ii :<c-u>call <SID>IndentTextObject()<cr>
xnoremap ai :<c-u>call <SID>IndentTextObject()<cr>
function! s:IndentTextObject()
let upper = s:UpperIndentLimit(line('.'))
let lower = s:LowerIndentLimit(line('.'))
call s:MarkVisual('V', upper, lower)
endfunction
 
onoremap if :<c-u>call <SID>FunctionTextObject('i')<cr>
onoremap af :<c-u>call <SID>FunctionTextObject('a')<cr>
xnoremap if :<c-u>call <SID>FunctionTextObject('i')<cr>
xnoremap af :<c-u>call <SID>FunctionTextObject('a')<cr>
function! s:FunctionTextObject(type)
let function_start = search('\((.\{-})\)\=\s*[-=]>$', 'Wbc')
if function_start <= 0
return
endif
 
let body_start = function_start + 1
if body_start > line('$') || indent(nextnonblank(body_start)) <= indent(function_start)
if a:type == 'a'
normal! vg_
endif
 
return
endif
 
let indent_limit = s:LowerIndentLimit(body_start)
 
if a:type == 'i'
let start = body_start
else
let start = function_start
endif
 
call s:MarkVisual('v', start, indent_limit)
endfunction
 
function! s:LowerIndentLimit(lineno)
let base_indent = indent(a:lineno)
let current_line = a:lineno
let next_line = nextnonblank(current_line + 1)
 
while current_line < line('$') && indent(next_line) >= base_indent
let current_line = next_line
let next_line = nextnonblank(current_line + 1)
endwhile
 
return current_line
endfunction
 
function! s:UpperIndentLimit(lineno)
let base_indent = indent(a:lineno)
let current_line = a:lineno
let prev_line = prevnonblank(current_line - 1)
 
while current_line > 0 && indent(prev_line) >= base_indent
let current_line = prev_line
let prev_line = prevnonblank(current_line - 1)
endwhile
 
return current_line
endfunction
 
function! s:MarkVisual(command, start_line, end_line)
if a:start_line != line('.')
exe a:start_line
endif
 
if a:end_line > a:start_line
exe 'normal! '.a:command.(a:end_line - a:start_line).'jg_'
else
exe 'normal! '.a:command.'g_'
endif
endfunction

Nice work. Are you familiar with https://github.com/kana/vim-textobj-indent ? Unless I'm missing something that plugin solves the same problem.

Owner

To me, the interesting thing about the gist is the implementation -- it's fairly simple to build something useful like this on your own (it's a part of a blog post, where I explain it in a lot more detail). For an actual, battle-tested indent text object, I'm pretty sure Kana's plugin works better :). The function object is something a bit different that might be useful, though.

Thanks for the explanation. I'll go reading the blog post ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.