From e23c6a18c82b71149a486fc8ee9cc15a25949655 Mon Sep 17 00:00:00 2001 From: Jez Ng Date: Thu, 24 Jul 2014 12:32:43 +0800 Subject: [PATCH 1/4] Add some support for ghc-modi. Right now only the 'type' and 'info' functions are supported. ghc-modi's `make` is still somewhat buggy. --- autoload/ghcmod.vim | 56 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/autoload/ghcmod.vim b/autoload/ghcmod.vim index e84a53b..cd57547 100644 --- a/autoload/ghcmod.vim +++ b/autoload/ghcmod.vim @@ -1,3 +1,9 @@ +if !exists("g:ghcmod_should_use_ghc_modi") + let g:ghcmod_should_use_ghc_modi = 1 +endif + +let s:use_modi = g:ghcmod_should_use_ghc_modi && executable('ghc-modi') == 1 + function! ghcmod#highlight_group() "{{{ return get(g:, 'ghcmod_type_highlight', 'Search') endfunction "}}} @@ -15,8 +21,12 @@ function! ghcmod#getHaskellIdentifier() "{{{ endfunction "}}} function! ghcmod#info(fexp, path, module) "{{{ - let l:cmd = ghcmod#build_command(['info', "-b \n", a:path, a:module, a:fexp]) - let l:output = ghcmod#system(l:cmd) + if s:use_modi + let l:output = join(s:modi_command(['info', a:path, a:fexp]), "\n") + else + let l:cmd = ghcmod#build_command(['info', "-b \n", a:path, a:module, a:fexp]) + let l:output = ghcmod#system(l:cmd) + endif " Remove trailing newlines to prevent empty lines let l:output = substitute(l:output, '\n*$', '', '') " Remove 'Dummy:0:0:Error:' prefix. @@ -24,8 +34,12 @@ function! ghcmod#info(fexp, path, module) "{{{ endfunction "}}} function! ghcmod#type(line, col, path, module) "{{{ - let l:cmd = ghcmod#build_command(['type', a:path, a:module, a:line, a:col]) - let l:output = ghcmod#system(l:cmd) + if s:use_modi + let l:output = join(s:modi_command(['type', a:path, a:line, a:col]), "\n") + else + let l:cmd = ghcmod#build_command(['type', a:path, a:module, a:line, a:col]) + let l:output = ghcmod#system(l:cmd) + endif let l:types = [] for l:line in split(l:output, '\n') let l:m = matchlist(l:line, '\(\d\+\) \(\d\+\) \(\d\+\) \(\d\+\) "\([^"]\+\)"') @@ -232,7 +246,11 @@ function! ghcmod#add_autogen_dir(path, cmd) "{{{ endfunction "}}} function! ghcmod#build_command(args) "{{{ - let l:cmd = ['ghc-mod'] + return s:build_command('ghc-mod', a:args) +endfunction "}}} + +function! s:build_command(cmd, args) "{{{ + let l:cmd = [a:cmd] let l:dist_top = s:find_basedir() . '/dist' let l:sandboxes = split(glob(l:dist_top . '/dist-*', 1), '\n') @@ -266,6 +284,34 @@ function! ghcmod#build_command(args) "{{{ return l:cmd endfunction "}}} +" Cache a handle to the ghc-modi process. +let s:ghc_modi_proc = {} + +function! s:modi_command(args) "{{{ + if s:ghc_modi_proc == {} + let l:ghcmodi_prog = s:build_command('ghc-modi', ['-b \n']) + lcd `=ghcmod#basedir()` + let s:ghc_modi_proc = vimproc#popen2(ghcmodi_prog) + lcd - + endif + + call s:ghc_modi_proc.stdin.write(join(a:args) . "\n") + + let l:res = [] + while 1 + for l:line in s:ghc_modi_proc.stdout.read_lines() + if l:line == "OK" + return l:res + elseif line =~ "^NG " + echoerr "ghc-modi terminated with message: " . join(l:res, "\n") + return '' + elseif len(line) > 0 + let l:res += [l:line] + endif + endfor + endwhile +endfunction "}}} + function! ghcmod#system(...) "{{{ lcd `=ghcmod#basedir()` let l:ret = call('vimproc#system', a:000) From 7df68b0337a347a88e3b3944f5b252afcb4b37c6 Mon Sep 17 00:00:00 2001 From: Jez Ng Date: Thu, 24 Jul 2014 23:39:48 +0800 Subject: [PATCH 2/4] Add ability to test the non-ghc-modi cases. --- test.sh | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/test.sh b/test.sh index d409fa3..4cfbfda 100755 --- a/test.sh +++ b/test.sh @@ -2,21 +2,39 @@ shopt -s nullglob +run_tests() { + for f in $1 + do + testname=${f#test/test_} + testname=${testname%.vim} + echo "Running $testname" + rm -f verbose.log + if vim -e -N -u NONE $2 -S test/before.vim -S "$f" < /dev/null; then + cat stdout.log + else + retval=$[retval + 1] + cat stdout.log + cat verbose.log + echo + fi + done +} + retval=0 -for f in test/test_*.vim -do - testname=${f#test/test_} - testname=${testname%.vim} - echo "Running $testname" - rm -f verbose.log - if vim -e -N -u NONE -S test/before.vim -S "$f" < /dev/null; then - cat stdout.log - else - retval=$[retval + 1] - cat stdout.log - cat verbose.log - echo - fi -done + +modonly_tests=(test/test_type.vim test/test_info.vim) + +run_tests "test/test_*.vim" + +# we cannot programmatically set this in our test case vimscripts as the +# variable is fixed once the script is loaded +echo "Setting ghcmod_should_use_ghc_modi=0" + +TMPFILE=`mktemp /tmp/test.XXXXXX` || exit 1 +echo "let g:ghcmod_should_use_ghc_modi=0" >> $TMPFILE + +run_tests "${modonly_tests[*]}" "-S $TMPFILE" + +rm -f $TMPFILE exit $retval From 5afa54b41c3f0954bcd2ff9bf11147f9a227a289 Mon Sep 17 00:00:00 2001 From: Jez Ng Date: Fri, 25 Jul 2014 00:17:08 +0800 Subject: [PATCH 3/4] Escape newlines properly. --- autoload/ghcmod.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autoload/ghcmod.vim b/autoload/ghcmod.vim index cd57547..a4c9ab0 100644 --- a/autoload/ghcmod.vim +++ b/autoload/ghcmod.vim @@ -289,7 +289,7 @@ let s:ghc_modi_proc = {} function! s:modi_command(args) "{{{ if s:ghc_modi_proc == {} - let l:ghcmodi_prog = s:build_command('ghc-modi', ['-b \n']) + let l:ghcmodi_prog = s:build_command('ghc-modi', ["-b \n"]) lcd `=ghcmod#basedir()` let s:ghc_modi_proc = vimproc#popen2(ghcmodi_prog) lcd - From 9f61c48245e1d530ff83f9d9f6518005937a36ef Mon Sep 17 00:00:00 2001 From: Jez Ng Date: Sat, 26 Jul 2014 00:27:05 +0800 Subject: [PATCH 4/4] Add ability to kill ghc-modi. --- after/ftplugin/haskell/ghcmod.vim | 4 +++- autoload/ghcmod.vim | 10 ++++++++++ autoload/ghcmod/command.vim | 12 ++++++++++++ test/test_type.vim | 6 ++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/after/ftplugin/haskell/ghcmod.vim b/after/ftplugin/haskell/ghcmod.vim index 27e04b8..ac4e4f9 100644 --- a/after/ftplugin/haskell/ghcmod.vim +++ b/after/ftplugin/haskell/ghcmod.vim @@ -57,6 +57,7 @@ command! -buffer -nargs=0 -bang GhcModCheckAsync call ghcmod#command#async_make( command! -buffer -nargs=0 -bang GhcModLintAsync call ghcmod#command#async_make('lint', 0) command! -buffer -nargs=0 -bang GhcModCheckAndLintAsync call ghcmod#command#check_and_lint_async(0) command! -buffer -nargs=0 -bang GhcModExpand call ghcmod#command#expand(0) +command! -buffer -nargs=0 -bang GhcModKillModi call ghcmod#command#kill_modi(0) let b:undo_ftplugin .= join(map([ \ 'GhcModType', \ 'GhcModTypeInsert', @@ -68,7 +69,8 @@ let b:undo_ftplugin .= join(map([ \ 'GhcModCheckAsync', \ 'GhcModLintAsync', \ 'GhcModCheckAndLintAsync', - \ 'GhcModExpand' + \ 'GhcModExpand', + \ 'GhcModKillModi' \ ], '"delcommand " . v:val'), ' | ') let b:undo_ftplugin .= ' | unlet b:did_ftplugin_ghcmod' diff --git a/autoload/ghcmod.vim b/autoload/ghcmod.vim index a4c9ab0..34a9f19 100644 --- a/autoload/ghcmod.vim +++ b/autoload/ghcmod.vim @@ -312,6 +312,16 @@ function! s:modi_command(args) "{{{ endwhile endfunction "}}} +function! ghcmod#kill_modi(sig) "{{{ + if s:ghc_modi_proc == {} + return + endif + let l:ret = s:ghc_modi_proc.kill(a:sig) + call s:ghc_modi_proc.waitpid() + let s:ghc_modi_proc = {} + return l:ret +endfunction "}}} + function! ghcmod#system(...) "{{{ lcd `=ghcmod#basedir()` let l:ret = call('vimproc#system', a:000) diff --git a/autoload/ghcmod/command.vim b/autoload/ghcmod/command.vim index 8a927f8..6c13de3 100644 --- a/autoload/ghcmod/command.vim +++ b/autoload/ghcmod/command.vim @@ -221,6 +221,18 @@ function! ghcmod#command#expand(force) "{{{ call s:open_quickfix() endfunction "}}} +function! ghcmod#command#kill_modi(force) "{{{ + if a:force + let l:sig = g:vimproc#SIGKILL + else + let l:sig = g:vimproc#SIGTERM + endif + let l:ret = ghcmod#kill_modi(l:sig) + if l:ret + echoerr vimproc#get_last_errmsg() + endif +endfunction "}}} + function! s:open_quickfix() "{{{ let l:func = get(g:, 'ghcmod_open_quickfix_function', '') if empty(l:func) diff --git a/test/test_type.vim b/test/test_type.vim index 02ab53b..89cf105 100644 --- a/test/test_type.vim +++ b/test/test_type.vim @@ -20,4 +20,10 @@ function! s:unit.test_type_compilation_failure() call self.assert.empty(l:types) endfunction +function! s:unit.test_kill_recovery() + call s:unit.test_type() + call ghcmod#kill_modi(9) + call s:unit.test_type() +endfunction + call s:unit.run()