diff options
Diffstat (limited to 'ftplugin')
-rw-r--r-- | ftplugin/erlang.vim | 200 | ||||
-rw-r--r-- | ftplugin/erlang_refactor.vim | 295 |
2 files changed, 428 insertions, 67 deletions
diff --git a/ftplugin/erlang.vim b/ftplugin/erlang.vim index 49b64ebb..f75f47ae 100644 --- a/ftplugin/erlang.vim +++ b/ftplugin/erlang.vim @@ -1,85 +1,151 @@ " Vim ftplugin file -" Language: Erlang -" Author: Oscar Hellström <oscar@oscarh.net> -" Contributors: Ricardo Catalinas Jiménez <jimenezrick@gmail.com> -" Eduardo Lopez (http://github.com/tapichu) -" License: Vim license -" Version: 2012/11/25 - -if exists('b:did_ftplugin') +" Language: Erlang +" Maintainer: Oscar Hellström <oscar@oscarh.net> +" URL: http://personal.oscarh.net +" Contributor: Ricardo Catalinas Jiménez <jimenezrick@gmail.com> +" Version: 2010-09-03 +" ------------------------------------------------------------------------------ +" Usage: +" +" To enable folding put in your vimrc: +" set foldenable +" +" Folding will make only one fold for a complete function, even though it has +" more than one function head and body. +" +" To change this behaviour put in your vimrc file: +" let g:erlangFoldSplitFunction=1 +" +" ------------------------------------------------------------------------------ +" Plugin init +if exists("b:did_ftplugin") finish -else - let b:did_ftplugin = 1 endif -if exists('s:did_function_definitions') +" Don't load any other +let b:did_ftplugin=1 + +if exists('s:doneFunctionDefinitions') call s:SetErlangOptions() finish -else - let s:did_function_definitions = 1 -endif - -if !exists('g:erlang_keywordprg') - let g:erlang_keywordprg = 'erl -man' -endif - -if !exists('g:erlang_folding') - let g:erlang_folding = 0 endif -let s:erlang_fun_begin = '^\(\a\w*\|[''][^'']*['']\)(.*$' -let s:erlang_fun_end = '^[^%]*\.\s*\(%.*\)\?$' +let s:doneFunctionDefinitions=1 +" Local settings function s:SetErlangOptions() compiler erlang if version >= 700 - setlocal omnifunc=erlang_complete#Complete - endif - - if g:erlang_folding - setlocal foldmethod=expr - setlocal foldexpr=GetErlangFold(v:lnum) - setlocal foldtext=ErlangFoldText() - endif - - setlocal comments=:%%%,:%%,:% - setlocal commentstring=%%s - setlocal formatoptions+=ro - setlocal suffixesadd=.erl - let libs = substitute(system('which erl'), '/bin/erl', '/lib/erlang/lib/**/src/', '') - execute 'setlocal path+=' . libs - let &l:keywordprg = g:erlang_keywordprg -endfunction - -function GetErlangFold(lnum) - let lnum = a:lnum - let line = getline(lnum) - - if line =~ s:erlang_fun_end - return '<1' - endif - - if line =~ s:erlang_fun_begin && foldlevel(lnum - 1) == 1 - return '1' - endif - - if line =~ s:erlang_fun_begin - return '>1' + setlocal omnifunc=erlangcomplete#Complete endif - return '=' + setlocal foldmethod=expr + setlocal foldexpr=GetErlangFold(v:lnum) + setlocal foldtext=ErlangFoldText() endfunction -function ErlangFoldText() - let line = getline(v:foldstart) - let foldlen = v:foldend - v:foldstart + 1 - let lines = ' ' . foldlen . ' lines: ' . substitute(line, "[ \t]*", '', '') - if foldlen < 10 - let lines = ' ' . lines - endif - let retval = '+' . v:folddashes . lines - - return retval -endfunction +" Define folding functions +if !exists("*GetErlangFold") + " Folding params + let s:ErlangFunBegin = '^\a\w*(.*$' + let s:ErlangFunEnd = '^[^%]*\.\s*\(%.*\)\?$' + let s:ErlangBlankLine = '^\s*\(%.*\)\?$' + + " Auxiliary fold functions + function s:GetNextNonBlank(lnum) + let lnum = nextnonblank(a:lnum + 1) + let line = getline(lnum) + while line =~ s:ErlangBlankLine && 0 != lnum + let lnum = nextnonblank(lnum + 1) + let line = getline(lnum) + endwhile + return lnum + endfunction + + function s:GetFunName(str) + return matchstr(a:str, '^\a\w*(\@=') + endfunction + + function s:GetFunArgs(str, lnum) + let str = a:str + let lnum = a:lnum + while str !~ '->\s*\(%.*\)\?$' + let lnum = s:GetNextNonBlank(lnum) + if 0 == lnum " EOF + return "" + endif + let str .= getline(lnum) + endwhile + return matchstr(str, + \ '\(^(\s*\)\@<=.*\(\s*)\(\s\+when\s\+.*\)\?\s\+->\s*\(%.*\)\?$\)\@=') + endfunction + + function s:CountFunArgs(arguments) + let pos = 0 + let ac = 0 " arg count + let arguments = a:arguments + + " Change list / tuples into just one A(rgument) + let erlangTuple = '{\([A-Za-z_,|=\-\[\]]\|\s\)*}' + let erlangList = '\[\([A-Za-z_,|=\-{}]\|\s\)*\]' + + " FIXME: Use searchpair? + while arguments =~ erlangTuple + let arguments = substitute(arguments, erlangTuple, "A", "g") + endwhile + " FIXME: Use searchpair? + while arguments =~ erlangList + let arguments = substitute(arguments, erlangList, "A", "g") + endwhile + + let len = strlen(arguments) + while pos < len && pos > -1 + let ac += 1 + let pos = matchend(arguments, ',\s*', pos) + endwhile + return ac + endfunction + + " Main fold function + function GetErlangFold(lnum) + let lnum = a:lnum + let line = getline(lnum) + + if line =~ s:ErlangFunEnd + return '<1' + endif + + if line =~ s:ErlangFunBegin && foldlevel(lnum - 1) == 1 + if exists("g:erlangFoldSplitFunction") && g:erlangFoldSplitFunction + return '>1' + else + return '1' + endif + endif + + if line =~ s:ErlangFunBegin + return '>1' + endif + + return '=' + endfunction + + " Erlang fold description (foldtext function) + function ErlangFoldText() + let foldlen = v:foldend - v:foldstart + if 1 < foldlen + let lines = "lines" + else + let lines = "line" + endif + let line = getline(v:foldstart) + let name = s:GetFunName(line) + let arguments = s:GetFunArgs(strpart(line, strlen(name)), v:foldstart) + let argcount = s:CountFunArgs(arguments) + let retval = "+" . v:folddashes . " " . name . "/" . argcount + let retval .= " (" . foldlen . " " . lines . ")" + return retval + endfunction +endif call s:SetErlangOptions() diff --git a/ftplugin/erlang_refactor.vim b/ftplugin/erlang_refactor.vim new file mode 100644 index 00000000..f809db9b --- /dev/null +++ b/ftplugin/erlang_refactor.vim @@ -0,0 +1,295 @@ +" Erlang refactor file +" Language: Erlang +" Maintainer: Pawel 'kTT' Salata <rockplayer.pl@gmail.com> +" URL: http://ktototaki.info + +if exists("b:did_ftplugin_erlang") + finish +endif + +" Don't load any other +let b:did_ftplugin_erlang=1 + +if !exists('g:erlangRefactoring') || g:erlangRefactoring == 0 + finish +endif + +if !exists('g:erlangWranglerPath') + let g:erlangWranglerPath = '/usr/share/wrangler/' +endif + +if glob(g:erlangWranglerPath) == "" + call confirm("Wrong path to wrangler dir") + finish +endif + +autocmd VimLeavePre * call StopWranglerServer() + +let s:erlangServerName = "wrangler_vim" + +" Starting background erlang session with wrangler on +function! StartWranglerServer() + let wranglerEbinDir = g:erlangWranglerPath . "/ebin" + let command = "erl_call -s -sname " . s:erlangServerName . " -x 'erl -pa " . wranglerEbinDir . "'" + call system(command) + call s:send_rpc('application', 'start', '[wrangler_app]') +endfunction + +" Stopping erlang session +function! StopWranglerServer() + echo s:send_rpc('erlang', 'halt', '') +endfunction + +" Sending rpc call to erlang session +function! s:send_rpc(module, fun, args) + let command = "erl_call -sname " . s:erlangServerName . " -a '" . a:module . " " . a:fun . " " . a:args . "'" + let result = system(command) + if match(result, 'erl_call: failed to connect to node .*') != -1 + call StartWranglerServer() + return system(command) + endif + return result +endfunction + +function! ErlangUndo() + echo s:send_rpc("wrangler_undo_server", "undo", "[]") + :e! +endfunction + +function! s:trim(text) + return substitute(a:text, "^\\s\\+\\|\\s\\+$", "", "g") +endfunction + +function! s:get_msg(result, tuple_start) + let msg_begin = '{' . a:tuple_start . ',' + let matching_start = match(a:result, msg_begin) + if matching_start != -1 + return s:trim(matchstr(a:result, '[^}]*', matching_start + strlen(msg_begin))) + endif + return "" +endfunction + +" Check if there is an error in result +function! s:check_for_error(result) + let msg = s:get_msg(a:result, 'ok') + if msg != "" + return [0, msg] + endif + let msg = s:get_msg(a:result, 'warning') + if msg != "" + return [1, msg] + endif + let msg = s:get_msg(a:result, 'error') + if msg != "" + return [2, msg] + endif + return [-1, ""] +endfunction + +" Sending apply changes to file +function! s:send_confirm() + let choice = confirm("What do you want?", "&Preview\n&Confirm\nCa&ncel", 0) + if choice == 1 + echo "TODO: Display preview :)" + elseif choice == 2 + let module = 'wrangler_preview_server' + let fun = 'commit' + let args = '[]' + return s:send_rpc(module, fun, args) + else + let module = 'wrangler_preview_server' + let fun = 'abort' + let args = '[]' + return s:send_rpc(module, fun, args) + echo "Canceled" + endif +endfunction + +" Manually send confirm, for testing purpose only +function! SendConfirm() + echo s:send_confirm() +endfunction + +" Format and send function extracton call +function! s:call_extract(start_line, start_col, end_line, end_col, name) + let file = expand("%:p") + let module = 'wrangler' + let fun = 'fun_extraction' + let args = '["' . file . '", {' . a:start_line . ', ' . a:start_col . '}, {' . a:end_line . ', ' . a:end_col . '}, "' . a:name . '", ' . &sw . ']' + let result = s:send_rpc(module, fun, args) + let [error_code, msg] = s:check_for_error(result) + if error_code != 0 + call confirm(msg) + return 0 + endif + echo "This files will be changed: " . matchstr(msg, "[^]]*", 1) + echo s:send_confirm() + return 1 +endfunction + +function! ErlangExtractFunction(mode) range + silent w! + let name = inputdialog("New function name: ") + if name != "" + if a:mode == "v" + let start_pos = getpos("'<") + let start_line = start_pos[1] + let start_col = start_pos[2] + + let end_pos = getpos("'>") + let end_line = end_pos[1] + let end_col = end_pos[2] + elseif a:mode == "n" + let pos = getpos(".") + let start_line = pos[1] + let start_col = pos[2] + let end_line = pos[1] + let end_col = pos[2] + else + echo "Mode not supported." + return + endif + if s:call_extract(start_line, start_col, end_line, end_col, name) + let temp = &autoread + set autoread + :e + if temp == 0 + set noautoread + endif + endif + else + echo "Empty function name. Ignoring." + endif +endfunction +nmap <A-r>e :call ErlangExtractFunction("n")<ENTER> +vmap <A-r>e :call ErlangExtractFunction("v")<ENTER> + +function! s:call_rename(mode, line, col, name, search_path) + let file = expand("%:p") + let module = 'wrangler' + let fun = 'rename_' . a:mode + let args = '["' . file .'", ' + if a:mode != "mod" + let args = args . a:line . ', ' . a:col . ', ' + endif + let args = args . '"' . a:name . '", ["' . a:search_path . '"], ' . &sw . ']' + let result = s:send_rpc(module, fun, args) + let [error_code, msg] = s:check_for_error(result) + if error_code != 0 + call confirm(msg) + return 0 + endif + echo "This files will be changed: " . matchstr(msg, "[^]]*", 1) + echo s:send_confirm() + return 1 +endfunction + +function! ErlangRename(mode) + silent w! + if a:mode == "mod" + let name = inputdialog('Rename module to: ') + else + let name = inputdialog('Rename "' . expand("<cword>") . '" to: ') + endif + if name != "" + let search_path = expand("%:p:h") + "let search_path = inputdialog('Search path: ', expand("%:p:h")) + let pos = getpos(".") + let line = pos[1] + let col = pos[2] + let current_filename = expand("%") + let current_filepath = expand("%:p") + let new_filename = name . '.erl' + if s:call_rename(a:mode, line, col, name, search_path) + if a:mode == "mod" + execute ':bd ' . current_filename + execute ':e ' . new_filename + silent execute '!mv ' . current_filepath . ' ' . current_filepath . '.bak' + redraw! + else + let temp = &autoread + set autoread + :e + if temp == 0 + set noautoread + endif + endif + endif + else + echo "Empty name. Ignoring." + endif +endfunction + +function! ErlangRenameFunction() + call ErlangRename("fun") +endfunction +map <A-r>f :call ErlangRenameFunction()<ENTER> + +function! ErlangRenameVariable() + call ErlangRename("var") +endfunction +map <A-r>v :call ErlangRenameVariable()<ENTER> + +function! ErlangRenameModule() + call ErlangRename("mod") +endfunction +map <A-r>m :call ErlangRenameModule()<ENTER> + +function! ErlangRenameProcess() + call ErlangRename("process") +endfunction +map <A-r>p :call ErlangRenameProcess()<ENTER> + +function! s:call_tuple_fun_args(start_line, start_col, end_line, end_col, search_path) + let file = expand("%:p") + let module = 'wrangler' + let fun = 'tuple_funpar' + let args = '["' . file . '", {' . a:start_line . ', ' . a:start_col . '}, {' . a:end_line . ', ' . a:end_col . '}, ["' . a:search_path . '"], ' . &sw . ']' + let result = s:send_rpc(module, fun, args) + if s:check_for_error(result) + return 0 + endif + call s:send_confirm() + return 1 +endfunction + +function! ErlangTupleFunArgs(mode) + silent w! + let search_path = expand("%:p:h") + "let search_path = inputdialog('Search path: ', expand("%:p:h")) + if a:mode == "v" + let start_pos = getpos("'<") + let start_line = start_pos[1] + let start_col = start_pos[2] + + let end_pos = getpos("'>") + let end_line = end_pos[1] + let end_col = end_pos[2] + if s:call_tuple_fun_args(start_line, start_col, end_line, end_col, search_path) + let temp = &autoread + set autoread + :e + if temp == 0 + set noautoread + endif + endif + elseif a:mode == "n" + let pos = getpos(".") + let line = pos[1] + let col = pos[2] + if s:call_tuple_fun_args(line, col, line, col, search_path) + let temp = &autoread + set autoread + :e + if temp == 0 + set noautoread + endif + endif + else + echo "Mode not supported." + endif +endfunction +nmap <A-r>t :call ErlangTupleFunArgs("n")<ENTER> +vmap <A-r>t :call ErlangTupleFunArgs("v")<ENTER> + +" vim: set foldmethod=marker: |