diff --git a/server/Scion/Server/Protocol/Vim.hs b/server/Scion/Server/Protocol/Vim.hs index 0a2990f..741448e 100644 --- a/server/Scion/Server/Protocol/Vim.hs +++ b/server/Scion/Server/Protocol/Vim.hs @@ -26,7 +26,7 @@ import Scion.Configure (configureCabalProject) import Scion.Utils ( unqualifiedForModule ) import Scion.Session (preprocessPackage, currentCabalPackage, loadComponent, backgroundTypecheckFile, unload, setGHCVerbosity, addCmdLineFlags) -import FastString (fsLit) +import FastString (fsLit, unpackFS) import Control.Monad (forever, liftM) import Control.Exception.Base (Exception) @@ -291,26 +291,32 @@ instance ToVimType Bool where instance ToVimType CompilationResult where toVim cr = toVim [ ("compilationSucceeded", toVim (compilationSucceeded cr)), - ("compilationWarnings", toVim ([] :: [ErrMsg])), --(compilationWarnings cr)), - ("compilationErrors", toVim ([] :: [ErrMsg])), --(compilationErrors cr)), + ("compilationWarnings", toVim $ concatMap errMsgToVimList ([] :: [ErrMsg])), + ("compilationErrors", toVim $ concatMap errMsgToVimList ([] :: [ErrMsg])), ("compilationTime", toVim ( "TODO" {- (compilationTime cr-} )) ] -instance (ToVimType a) => ToVimType (Bag a) where - toVim = listToVim . bagToList -instance ToVimType ErrMsg where - toVim em = toVim [ - ("errMsgSpans", toVim (errMsgSpans em)), - ("errMsgContext", toVim (errMsgSpans em)), - ("errMsgShortDoc", toVim (errMsgSpans em)), - ("errMsgExtraInfo", toVim (errMsgSpans em)) - ] -instance ToVimType SrcSpan where - toVim ss = let start = srcSpanStart ss in toVim $ [ - ("file", (toVim . show) ( srcLocFile start)), - ("line", toVim ( srcLocLine start)), - ("col", toVim ( srcLocCol start)) - ] - -- TODO, what about span end ? do we need it +-- return list which can be passed to setqflist +errMsgToVimList :: ErrMsg -> [VimType] +errMsgToVimList em = + let (fst:moreLocations) = errMsgSpans em + loc :: SrcSpan -> [(VimType, VimType)] + loc em = + [ (toVim "filename", (toVim . unpackFS) ( (srcLocFile . srcSpanStart) em)) + , (toVim "lnum", toVim ( srcLocLine . srcSpanStart $ em)) + , (toVim "col", toVim ( srcLocCol . srcSpanStart $ em)) + ] + + -- ghc does print multiline messages. So add a text qf item for all + -- trailing lines to keep them readable + addText :: VimType -> [String] -> [VimType] + addText (VDict map') [msg] = [VDict $ M.insert (toVim "text") (toVim msg) map'] + addText (VDict map') (msg:msgs) = addText (VDict map') [msg] ++ map (\m -> toVim [(toVim "text", toVim m)]) msgs + -- addText _ _ = error "never executed" + in + -- first location and message + (addText (toVim $ loc fst) $ lines $ (O.showSDoc (errMsgShortDoc em)) ++ ("\n" ++ O.showSDoc (errMsgExtraInfo em))) + -- more error locations - when do they occur? + ++ map (toVim . loc) moreLocations instance ToVimType O.SDoc where toVim = toVim . O.showSDoc diff --git a/vim_runtime_path/autoload/haskellcomplete.vim b/vim_runtime_path/autoload/haskellcomplete.vim index 3b7b4b0..f2fbae7 100644 --- a/vim_runtime_path/autoload/haskellcomplete.vim +++ b/vim_runtime_path/autoload/haskellcomplete.vim @@ -1,6 +1,10 @@ -" haskellcomplete.vim - Omni Completion for haskell +" This file contains the code necessary to talk to the scion server +" -> haskellcomplete#EvalScion ) +" +" This implementation requires has('python') support +" +" You can look up some use cases in the ftplugin file. " -" This file talks to the scion server. You need python support " This code is based on the initial implementation found in shim by Benedikt Schmidt " The server side code can be found in src-scion-server/Scion/Server/ProtocolVim.hs @@ -81,14 +85,15 @@ class ScionServerConnectionStdinOut(ScionServerConnection): self.scion_o = p.stdout self.scion_i = p.stdin def receive(self): - let s = super.receive() + s = ScionServerConnection.receive(self) if s[:6] == "scion:": # ghc doesn't always use the ghc API to print statements.. so ignore all # lines not marked by "scion:" at the beginning # see README.markdown return s[6:] else: - self.receive() + # throw away non "scion:" line and try again + return self.receive() class ScionServerConnectionSocket(ScionServerConnection): """connects to the scion server by either TCP/IP or socketfile""" @@ -114,7 +119,7 @@ def connectscion(): global told_user_about_missing_configuration if 0 == told_user_about_missing_configuration: try: - print scionConnectionSetting + print "connecting to scion %s"%scionConnectionSetting.__str__() except NameError: vim.command("sp") b = vim.current.buffer @@ -143,7 +148,7 @@ def evalscion(str): try: server_connection.send(str) except: - vim.command('echoe "%s"'% ("(re) connecting to scion")) + vim.command('echom "%s"'% ("(re)connecting to scion")) connectscion() server_connection.send(str) return server_connection.receive() diff --git a/vim_runtime_path/ftplugin/haskell.vim b/vim_runtime_path/ftplugin/haskell.vim index ddc0cc6..700581b 100644 --- a/vim_runtime_path/ftplugin/haskell.vim +++ b/vim_runtime_path/ftplugin/haskell.vim @@ -1,35 +1,83 @@ -finish -" old shim stuff : -setlocal omnifunc=haskellcomplete#CompleteIdentifier -setlocal completefunc=haskellcomplete#CompleteModule -command! -nargs=1 GrepScope call haskellcomplete#GrepScope() -command! -nargs=1 FindModulesExporting echo haskellcomplete#FindModulesExporting() +if exists('g:dont_load_haskell_scion_interface_simple') + finish +endif -let g:haskellModuleImportBehaviour = 'interactive' " one of interactive, automatic +" r = scion result with error locations +" func : either setqflist or setloclist +fun! ScionResultToErrorList(action, func, r) + let compilationResult = has_key(a:r, 'compilationResult') ? a:r['compilationResult'] : a:r + let g:foo = compilationResult + let qflist = compilationResult['compilationErrors'] + compilationResult['compilationWarnings'] -if !exists('g:modulePreferenceCacheFile') - let g:modulePreferenceCacheFile = expand('$HOME').'/.vim/modulePreferenceCacheFile' -endif + " for debugging + let g:scion_qf_list = qflist + if has_key(a:r, 'inProject') + let inProj = "inProject : ". a:r['inProject'] + else + let inProj = "" + endif + if (has_key(a:r,'compilationSucceeded') && a:r['compilationSucceeded']) + \ || (!has_key(a:r, 'compilationSucceeded') && len(qflist) == 0) + return printf(a:action." success. ".inProj." compilationTime: %s", compilationResult['compilationTime']) + else + call call(a:func, [qflist]) + return printf(a:action." there are errors, ".inProj." compilationTime: %s", compilationResult['compilationTime']) + endif +endfun -if filereadable(g:modulePreferenceCacheFile) - let g:modulePreferences = eval(readfile(g:modulePreferences, 'b')) -else - let g:modulePreferences = { - \ 'Data.Map' : { 'q' : 'M' } - \ , 'Control.Monad' : { 'fitness' : 10 } +" very simple user interface to expose scion functionality +" I'll implement a better interface in tovl. +" (http://github.com/MarcWeber/theonevimlib) - \ } -endif +fun! s:BackgroundTypecheckFile(...) + " no file given defaults to current buffer + let file = a:0 > 0 ? a:1 : expand('%:p') + let r = haskellcomplete#EvalScion({'request' : 'cmdBackgroundTypecheckFile', 'file' : file}) + echo ScionResultToErrorList('file check', 'setqflist', r) +endf + +fun! s:OpenCabalProject(...) + let builddir = a:0 > 0 ? a:1 : "dist" + echo haskellcomplete#EvalScion( + \ {'request' : 'cmdOpenCabalProject', 'root_dir' : getcwd(), + \ 'dist_dir' : builddir, 'extra_args' : a:000[1:] } + \) +endf + +" ===== you don't need any project for these: ============= +command! -buffer ConnectionInfo + \ echo haskellcomplete#EvalScion({'request' : 'cmdConnectionInfo'}) + +" list supported languages +command! -buffer ListSupportedLanguages + \ echo haskellcomplete#EvalScion({'request' : 'cmdListSupportedLanguages'}) + +" list supported pragmas +command! -buffer ListSupportedPragmas + \ echo haskellcomplete#EvalScion({'request' : 'cmdListSupportedPragmas'}) + +" list supported flags +command! -buffer ListSupportedFlags + \ echo haskellcomplete#EvalScion({'request' : 'cmdListSupportedFlags'}) + +" ===== loading a cabal project: ============================ + +" assuming pwd is current cabal directory containing the .cabal file +" optional argument specifies the cabal build (dist) directory +command! -buffer -nargs=* -complete=file OpenCabalProject + \ call s:OpenCabalProject() -" returns 0 (= not importet) -" or { 'q' : -" , 'functions' : [ list of explicit imported functions ] } -function! ImportInfo(module) - let pos = -endfunction +" arg either "library" or "executable:name" +command! -buffer -nargs=1 LoadComponent + \ echo ScionResultToErrorList('load component finished: ','setqflist',haskellcomplete#EvalScion({'request' : 'cmdLoadComponent', 'component' : })) +" list exposed +command! -buffer ListExposedModules + \ echo haskellcomplete#EvalScion({'request' : 'cmdListExposedModules'}) +command! -buffer -nargs=* -complete=file BackgroundTypecheckFile + \ call s:BackgroundTypecheckFile() +command! -buffer ThingAtPoint + \ echo haskellcomplete#EvalScion({'request' : 'cmdThingAtPoint', 'file' : expand('%:p'), 'line' : line('.').'', 'col' : col('.').''}) -" needs g:modulePreferences, g:haskellModuleImportBehaviour -function! HaskellImportIdentifier(id) - let modules = haskellcomplete#FindModulesExporting(a:id) -endfunction +command! -buffer ListRdrNamesInScope + \ echo haskellcomplete#EvalScion({'request' : 'cmdListRdrNamesInScope'})