You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
4.5 KiB
VimL
181 lines
4.5 KiB
VimL
9 years ago
|
if !exists("g:go_textobj_enabled")
|
||
|
let g:go_textobj_enabled = 1
|
||
|
endif
|
||
|
|
||
|
if !exists("g:go_textobj_include_function_doc")
|
||
|
let g:go_textobj_include_function_doc = 1
|
||
|
endif
|
||
|
|
||
|
" ( ) motions
|
||
|
" { } motions
|
||
|
" s for sentence
|
||
|
" p for parapgrah
|
||
|
" < >
|
||
|
" t for tag
|
||
|
|
||
|
function! go#textobj#Function(mode)
|
||
|
let offset = go#util#OffsetCursor()
|
||
|
|
||
|
let fname = expand("%:p")
|
||
|
if &modified
|
||
|
" Write current unsaved buffer to a temp file and use the modified content
|
||
|
let l:tmpname = tempname()
|
||
|
call writefile(getline(1, '$'), l:tmpname)
|
||
|
let fname = l:tmpname
|
||
|
endif
|
||
|
|
||
|
let bin_path = go#path#CheckBinPath('motion')
|
||
|
if empty(bin_path)
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
let command = printf("%s -format vim -file %s -offset %s", bin_path, fname, offset)
|
||
|
let command .= " -mode enclosing"
|
||
|
|
||
|
if g:go_textobj_include_function_doc
|
||
|
let command .= " -parse-comments"
|
||
|
endif
|
||
|
|
||
|
let out = system(command)
|
||
|
if v:shell_error != 0
|
||
|
call go#util#EchoError(out)
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" if exists, delete it as we don't need it anymore
|
||
|
if exists("l:tmpname")
|
||
|
call delete(l:tmpname)
|
||
|
endif
|
||
|
|
||
|
" convert our string dict representation into native Vim dictionary type
|
||
|
let result = eval(out)
|
||
|
if type(result) != 4 || !has_key(result, 'fn')
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
let info = result.fn
|
||
|
|
||
|
if a:mode == 'a'
|
||
|
" anonymous functions doesn't have associated doc. Also check if the user
|
||
|
" want's to include doc comments for function declarations
|
||
|
if has_key(info, 'doc') && g:go_textobj_include_function_doc
|
||
|
call cursor(info.doc.line, info.doc.col)
|
||
|
else
|
||
|
call cursor(info.func.line, info.func.col)
|
||
|
endif
|
||
|
|
||
|
normal! v
|
||
|
call cursor(info.rbrace.line, info.rbrace.col)
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" rest is inner mode, a:mode == 'i'
|
||
|
|
||
|
" if the function is a one liner we need to select only that portion
|
||
|
if info.lbrace.line == info.rbrace.line
|
||
|
call cursor(info.lbrace.line, info.lbrace.col+1)
|
||
|
normal! v
|
||
|
call cursor(info.rbrace.line, info.rbrace.col-1)
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
call cursor(info.lbrace.line+1, 1)
|
||
|
normal! V
|
||
|
call cursor(info.rbrace.line-1, 1)
|
||
|
endfunction
|
||
|
|
||
|
function! go#textobj#FunctionJump(mode, direction)
|
||
|
" get count of the motion. This should be done before all the normal
|
||
|
" expressions below as those reset this value(because they have zero
|
||
|
" count!). We abstract -1 because the index starts from 0 in motion.
|
||
|
let l:cnt = v:count1 - 1
|
||
|
|
||
|
" set context mark so we can jump back with '' or ``
|
||
|
normal! m'
|
||
|
|
||
|
" select already previously selected visual content and continue from there.
|
||
|
" If it's the first time starts with the visual mode. This is needed so
|
||
|
" after selecting something in visual mode, every consecutive motion
|
||
|
" continues.
|
||
|
if a:mode == 'v'
|
||
|
normal! gv
|
||
|
endif
|
||
|
|
||
|
let offset = go#util#OffsetCursor()
|
||
|
|
||
|
let fname = expand("%:p")
|
||
|
if &modified
|
||
|
" Write current unsaved buffer to a temp file and use the modified content
|
||
|
let l:tmpname = tempname()
|
||
|
call writefile(getline(1, '$'), l:tmpname)
|
||
|
let fname = l:tmpname
|
||
|
endif
|
||
|
|
||
|
let bin_path = go#path#CheckBinPath('motion')
|
||
|
if empty(bin_path)
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
let command = printf("%s -format vim -file %s -offset %s", bin_path, fname, offset)
|
||
|
let command .= ' -shift ' . l:cnt
|
||
|
|
||
|
if a:direction == 'next'
|
||
|
let command .= ' -mode next'
|
||
|
else " 'prev'
|
||
|
let command .= ' -mode prev'
|
||
|
endif
|
||
|
|
||
|
if g:go_textobj_include_function_doc
|
||
|
let command .= " -parse-comments"
|
||
|
endif
|
||
|
|
||
|
let out = system(command)
|
||
|
if v:shell_error != 0
|
||
|
call go#util#EchoError(out)
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" if exists, delete it as we don't need it anymore
|
||
|
if exists("l:tmpname")
|
||
|
call delete(l:tmpname)
|
||
|
endif
|
||
|
|
||
|
" convert our string dict representation into native Vim dictionary type
|
||
|
let result = eval(out)
|
||
|
if type(result) != 4 || !has_key(result, 'fn')
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" we reached the end and there are no functions. The usual [[ or ]] jumps to
|
||
|
" the top or bottom, we'll do the same.
|
||
|
if type(result) == 4 && has_key(result, 'err') && result.err == "no functions found"
|
||
|
if a:direction == 'next'
|
||
|
keepjumps normal! G
|
||
|
else " 'prev'
|
||
|
keepjumps normal! gg
|
||
|
endif
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
let info = result.fn
|
||
|
|
||
|
" if we select something ,select all function
|
||
|
if a:mode == 'v' && a:direction == 'next'
|
||
|
keepjumps call cursor(info.rbrace.line, 1)
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
if a:mode == 'v' && a:direction == 'prev'
|
||
|
if has_key(info, 'doc') && g:go_textobj_include_function_doc
|
||
|
keepjumps call cursor(info.doc.line, 1)
|
||
|
else
|
||
|
keepjumps call cursor(info.func.line, 1)
|
||
|
endif
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
keepjumps call cursor(info.func.line, 1)
|
||
|
endfunction
|
||
|
|
||
|
" vim:ts=2:sw=2:et
|