/vim/haskellmode-20090430.vba
https://bitbucket.org/vertespain/config · Visual Basic · 2035 lines · 1829 code · 205 blank · 1 comment · 339 complexity · 43f70636eecf1e84667405319ffe8e58 MD5 · raw file
Large files are truncated click here to view the full file
- " Vimball Archiver by Charles E. Campbell, Jr., Ph.D.
- UseVimball
- finish
- compiler/ghc.vim [[[1
- 479
- " Vim Compiler File
- " Compiler: GHC
- " Maintainer: Claus Reinke <claus.reinke@talk21.com>
- " Last Change: 30/04/2009
- "
- " part of haskell plugins: http://projects.haskell.org/haskellmode-vim
- " ------------------------------ paths & quickfix settings first
- "
- if exists("current_compiler") && current_compiler == "ghc"
- finish
- endif
- let current_compiler = "ghc"
- let s:scriptname = "ghc.vim"
- if (!exists("g:ghc") || !executable(g:ghc))
- if !executable('ghc')
- echoerr s:scriptname.": can't find ghc. please set g:ghc, or extend $PATH"
- finish
- else
- let g:ghc = 'ghc'
- endif
- endif
- let ghc_version = substitute(system(g:ghc . ' --numeric-version'),'\n','','')
- if (!exists("b:ghc_staticoptions"))
- let b:ghc_staticoptions = ''
- endif
- " set makeprg (for quickfix mode)
- execute 'setlocal makeprg=' . g:ghc . '\ ' . escape(b:ghc_staticoptions,' ') .'\ -e\ :q\ %'
- "execute 'setlocal makeprg=' . g:ghc .'\ -e\ :q\ %'
- "execute 'setlocal makeprg=' . g:ghc .'\ --make\ %'
- " quickfix mode:
- " fetch file/line-info from error message
- " TODO: how to distinguish multiline errors from warnings?
- " (both have the same header, and errors have no common id-tag)
- " how to get rid of first empty message in result list?
- setlocal errorformat=
- \%-Z\ %#,
- \%W%f:%l:%c:\ Warning:\ %m,
- \%E%f:%l:%c:\ %m,
- \%E%>%f:%l:%c:,
- \%+C\ \ %#%m,
- \%W%>%f:%l:%c:,
- \%+C\ \ %#%tarning:\ %m,
- " oh, wouldn't you guess it - ghc reports (partially) to stderr..
- setlocal shellpipe=2>
- " ------------------------- but ghc can do a lot more for us..
- "
- " allow map leader override
- if !exists("maplocalleader")
- let maplocalleader='_'
- endif
- " initialize map of identifiers to their types
- " associate type map updates to changedtick
- if !exists("b:ghc_types")
- let b:ghc_types = {}
- let b:my_changedtick = b:changedtick
- endif
- if exists("g:haskell_functions")
- finish
- endif
- let g:haskell_functions = "ghc"
- " avoid hit-enter prompts
- set cmdheight=3
- " edit static GHC options
- " TODO: add completion for options/packages?
- command! GHCStaticOptions call GHC_StaticOptions()
- function! GHC_StaticOptions()
- let b:ghc_staticoptions = input('GHC static options: ',b:ghc_staticoptions)
- execute 'setlocal makeprg=' . g:ghc . '\ ' . escape(b:ghc_staticoptions,' ') .'\ -e\ :q\ %'
- let b:my_changedtick -=1
- endfunction
- map <LocalLeader>T :call GHC_ShowType(1)<cr>
- map <LocalLeader>t :call GHC_ShowType(0)<cr>
- function! GHC_ShowType(addTypeDecl)
- let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),0)
- if namsym==[]
- redraw
- echo 'no name/symbol under cursor!'
- return 0
- endif
- let [_,symb,qual,unqual] = namsym
- let name = qual=='' ? unqual : qual.'.'.unqual
- let pname = ( symb ? '('.name.')' : name )
- call GHC_HaveTypes()
- if !has_key(b:ghc_types,name)
- redraw
- echo pname "type not known"
- else
- redraw
- for type in split(b:ghc_types[name],' -- ')
- echo pname "::" type
- if a:addTypeDecl
- call append( line(".")-1, pname . " :: " . type )
- endif
- endfor
- endif
- endfunction
- " show type of identifier under mouse pointer in balloon
- if has("balloon_eval")
- set ballooneval
- set balloondelay=600
- set balloonexpr=GHC_TypeBalloon()
- function! GHC_TypeBalloon()
- if exists("b:current_compiler") && b:current_compiler=="ghc"
- let [line] = getbufline(v:beval_bufnr,v:beval_lnum)
- let namsym = haskellmode#GetNameSymbol(line,v:beval_col,0)
- if namsym==[]
- return ''
- endif
- let [start,symb,qual,unqual] = namsym
- let name = qual=='' ? unqual : qual.'.'.unqual
- let pname = name " ( symb ? '('.name.')' : name )
- silent call GHC_HaveTypes()
- if has("balloon_multiline")
- return (has_key(b:ghc_types,pname) ? split(b:ghc_types[pname],' -- ') : '')
- else
- return (has_key(b:ghc_types,pname) ? b:ghc_types[pname] : '')
- endif
- else
- return ''
- endif
- endfunction
- endif
- map <LocalLeader>si :call GHC_ShowInfo()<cr>
- function! GHC_ShowInfo()
- let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),0)
- if namsym==[]
- redraw
- echo 'no name/symbol under cursor!'
- return 0
- endif
- let [_,symb,qual,unqual] = namsym
- let name = qual=='' ? unqual : (qual.'.'.unqual)
- let output = GHC_Info(name)
- pclose | new
- setlocal previewwindow
- setlocal buftype=nofile
- setlocal noswapfile
- put =output
- wincmd w
- "redraw
- "echo output
- endfunction
- " fill the type map, unless nothing has changed since the last attempt
- function! GHC_HaveTypes()
- if b:ghc_types == {} && (b:my_changedtick != b:changedtick)
- let b:my_changedtick = b:changedtick
- return GHC_BrowseAll()
- endif
- endfunction
- " update b:ghc_types after successful make
- au QuickFixCmdPost make if GHC_CountErrors()==0 | silent call GHC_BrowseAll() | endif
- " count only error entries in quickfix list, ignoring warnings
- function! GHC_CountErrors()
- let c=0
- for e in getqflist() | if e.type=='E' && e.text !~ "^[ \n]*Warning:" | let c+=1 | endif | endfor
- return c
- endfunction
- command! GHCReload call GHC_BrowseAll()
- function! GHC_BrowseAll()
- " let imports = haskellmode#GatherImports()
- " let modules = keys(imports[0]) + keys(imports[1])
- let imports = {} " no need for them at the moment
- let current = GHC_NameCurrent()
- let module = current==[] ? 'Main' : current[0]
- if GHC_VersionGE([6,8,1])
- return GHC_BrowseBangStar(module)
- else
- return GHC_BrowseMultiple(imports,['*'.module])
- endif
- endfunction
- function! GHC_VersionGE(target)
- let current = split(g:ghc_version, '\.' )
- let target = a:target
- for i in current
- if ((target==[]) || (i>target[0]))
- return 1
- elseif (i==target[0])
- let target = target[1:]
- else
- return 0
- endif
- endfor
- return 1
- endfunction
- function! GHC_NameCurrent()
- let last = line("$")
- let l = 1
- while l<last
- let ml = matchlist( getline(l), '^module\s*\([^ (]*\)')
- if ml != []
- let [_,module;x] = ml
- return [module]
- endif
- let l += 1
- endwhile
- redraw
- echo "cannot find module header for file " . expand("%")
- return []
- endfunction
- function! GHC_BrowseBangStar(module)
- redraw
- echo "browsing module " a:module
- let command = ":browse! *" . a:module
- let orig_shellredir = &shellredir
- let &shellredir = ">" " ignore error/warning messages, only output or lack of it
- let output = system(g:ghc . ' ' . b:ghc_staticoptions . ' -v0 --interactive ' . expand("%") , command )
- let &shellredir = orig_shellredir
- return GHC_ProcessBang(a:module,output)
- endfunction
- function! GHC_BrowseMultiple(imports,modules)
- redraw
- echo "browsing modules " a:modules
- let command = ":browse " . join( a:modules, " \n :browse ")
- let command = substitute(command,'\(:browse \(\S*\)\)','putStrLn "-- \2" \n \1','g')
- let output = system(g:ghc . ' ' . b:ghc_staticoptions . ' -v0 --interactive ' . expand("%") , command )
- return GHC_Process(a:imports,output)
- endfunction
- function! GHC_Info(what)
- " call GHC_HaveTypes()
- let output = system(g:ghc . ' ' . b:ghc_staticoptions . ' -v0 --interactive ' . expand("%"), ":i ". a:what)
- return output
- endfunction
- function! GHC_ProcessBang(module,output)
- let module = a:module
- let b = a:output
- let linePat = '^\(.\{-}\)\n\(.*\)'
- let contPat = '\s\+\(.\{-}\)\n\(.*\)'
- let typePat = '^\(\)\(\S*\)\s*::\(.*\)'
- let commentPat = '^-- \(\S*\)'
- let definedPat = '^-- defined locally'
- let importedPat = '^-- imported via \(.*\)'
- if !(b=~commentPat)
- echo s:scriptname.": GHCi reports errors (try :make?)"
- return 0
- endif
- let b:ghc_types = {}
- let ml = matchlist( b , linePat )
- while ml != []
- let [_,l,rest;x] = ml
- let mlDecl = matchlist( l, typePat )
- if mlDecl != []
- let [_,indent,id,type;x] = mlDecl
- let ml2 = matchlist( rest , '^'.indent.contPat )
- while ml2 != []
- let [_,c,rest;x] = ml2
- let type .= c
- let ml2 = matchlist( rest , '^'.indent.contPat )
- endwhile
- let id = substitute( id, '^(\(.*\))$', '\1', '')
- let type = substitute( type, '\s\+', " ", "g" )
- " using :browse! *<current>, we get both unqualified and qualified ids
- let qualified = (id =~ '\.') && (id =~ '[A-Z]')
- let b:ghc_types[id] = type
- if !qualified
- for qual in qualifiers
- let b:ghc_types[qual.'.'.id] = type
- endfor
- endif
- else
- let mlImported = matchlist( l, importedPat )
- let mlDefined = matchlist( l, definedPat )
- if mlImported != []
- let [_,modules;x] = mlImported
- let qualifiers = split( modules, ', ' )
- elseif mlDefined != []
- let qualifiers = [module]
- endif
- endif
- let ml = matchlist( rest , linePat )
- endwhile
- return 1
- endfunction
- function! GHC_Process(imports,output)
- let b = a:output
- let imports = a:imports
- let linePat = '^\(.\{-}\)\n\(.*\)'
- let contPat = '\s\+\(.\{-}\)\n\(.*\)'
- let typePat = '^\(\s*\)\(\S*\)\s*::\(.*\)'
- let modPat = '^-- \(\S*\)'
- " add '-- defined locally' and '-- imported via ..'
- if !(b=~modPat)
- echo s:scriptname.": GHCi reports errors (try :make?)"
- return 0
- endif
- let b:ghc_types = {}
- let ml = matchlist( b , linePat )
- while ml != []
- let [_,l,rest;x] = ml
- let mlDecl = matchlist( l, typePat )
- if mlDecl != []
- let [_,indent,id,type;x] = mlDecl
- let ml2 = matchlist( rest , '^'.indent.contPat )
- while ml2 != []
- let [_,c,rest;x] = ml2
- let type .= c
- let ml2 = matchlist( rest , '^'.indent.contPat )
- endwhile
- let id = substitute(id, '^(\(.*\))$', '\1', '')
- let type = substitute( type, '\s\+', " ", "g" )
- " using :browse *<current>, we get both unqualified and qualified ids
- if current_module " || has_key(imports[0],module)
- if has_key(b:ghc_types,id) && !(matchstr(b:ghc_types[id],escape(type,'[].'))==type)
- let b:ghc_types[id] .= ' -- '.type
- else
- let b:ghc_types[id] = type
- endif
- endif
- if 0 " has_key(imports[1],module)
- let qualid = module.'.'.id
- let b:ghc_types[qualid] = type
- endif
- else
- let mlMod = matchlist( l, modPat )
- if mlMod != []
- let [_,module;x] = mlMod
- let current_module = module[0]=='*'
- let module = current_module ? module[1:] : module
- endif
- endif
- let ml = matchlist( rest , linePat )
- endwhile
- return 1
- endfunction
- let s:ghc_templates = ["module _ () where","class _ where","class _ => _ where","instance _ where","instance _ => _ where","type family _","type instance _ = ","data _ = ","newtype _ = ","type _ = "]
- " use ghci :browse index for insert mode omnicompletion (CTRL-X CTRL-O)
- function! GHC_CompleteImports(findstart, base)
- if a:findstart
- let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),-1) " insert-mode: we're 1 beyond the text
- if namsym==[]
- redraw
- echo 'no name/symbol under cursor!'
- return -1
- endif
- let [start,symb,qual,unqual] = namsym
- return (start-1)
- else " find keys matching with "a:base"
- let res = []
- let l = len(a:base)-1
- call GHC_HaveTypes()
- for key in keys(b:ghc_types)
- if key[0 : l]==a:base
- let res += [{"word":key,"menu":":: ".b:ghc_types[key],"dup":1}]
- endif
- endfor
- return res
- endif
- endfunction
- set omnifunc=GHC_CompleteImports
- "
- " Vim's default completeopt is menu,preview
- " you probably want at least menu, or you won't see alternatives listed
- " setlocal completeopt+=menu
- " menuone is useful, but other haskellmode menus will try to follow your choice here in future
- " setlocal completeopt+=menuone
- " longest sounds useful, but doesn't seem to do what it says, and interferes with CTRL-E
- " setlocal completeopt-=longest
- map <LocalLeader>ct :call GHC_CreateTagfile()<cr>
- function! GHC_CreateTagfile()
- redraw
- echo "creating tags file"
- let output = system(g:ghc . ' ' . b:ghc_staticoptions . ' -e ":ctags" ' . expand("%"))
- " for ghcs older than 6.6, you would need to call another program
- " here, such as hasktags
- echo output
- endfunction
- command! -nargs=1 GHCi redraw | echo system(g:ghc. ' ' . b:ghc_staticoptions .' '.expand("%").' -e "'.escape(<f-args>,'"').'"')
- " use :make 'not in scope' errors to explicitly list imported ids
- " cursor needs to be on import line, in correctly loadable module
- map <LocalLeader>ie :call GHC_MkImportsExplicit()<cr>
- function! GHC_MkImportsExplicit()
- let save_cursor = getpos(".")
- let line = getline('.')
- let lineno = line('.')
- let ml = matchlist(line,'^import\(\s*qualified\)\?\s*\([^( ]\+\)')
- if ml!=[]
- let [_,q,mod;x] = ml
- silent make
- if getqflist()==[]
- if line=~"import[^(]*Prelude"
- call setline(lineno,substitute(line,"(.*","","").'()')
- else
- call setline(lineno,'-- '.line)
- endif
- silent write
- silent make
- let qflist = getqflist()
- call setline(lineno,line)
- silent write
- let ids = {}
- for d in qflist
- let ml = matchlist(d.text,'Not in scope: \([^`]*\)`\([^'']*\)''')
- if ml!=[]
- let [_,what,qid;x] = ml
- let id = ( qid =~ "^[A-Z]" ? substitute(qid,'.*\.\([^.]*\)$','\1','') : qid )
- let pid = ( id =~ "[a-zA-Z0-9_']\\+" ? id : '('.id.')' )
- if what =~ "data"
- call GHC_HaveTypes()
- if has_key(b:ghc_types,id)
- let pid = substitute(b:ghc_types[id],'^.*->\s*\(\S*\).*$','\1','').'('.pid.')'
- else
- let pid = '???('.pid.')'
- endif
- endif
- let ids[pid] = 1
- endif
- endfor
- call setline(lineno,'import'.q.' '.mod.'('.join(keys(ids),',').')')
- else
- copen
- endif
- endif
- call setpos('.', save_cursor)
- endfunction
- if GHC_VersionGE([6,8,2])
- let opts = filter(split(substitute(system(g:ghc . ' -v0 --interactive', ':set'), ' ', '','g'), '\n'), 'v:val =~ "-f"')
- else
- let opts = ["-fglasgow-exts","-fallow-undecidable-instances","-fallow-overlapping-instances","-fno-monomorphism-restriction","-fno-mono-pat-binds","-fno-cse","-fbang-patterns","-funbox-strict-fields"]
- endif
- amenu ]OPTIONS_GHC.- :echo '-'<cr>
- aunmenu ]OPTIONS_GHC
- for o in opts
- exe 'amenu ]OPTIONS_GHC.'.o.' :call append(0,"{-# OPTIONS_GHC '.o.' #-}")<cr>'
- endfor
- if has("gui_running")
- map <LocalLeader>opt :popup ]OPTIONS_GHC<cr>
- else
- map <LocalLeader>opt :emenu ]OPTIONS_GHC.
- endif
- amenu ]LANGUAGES_GHC.- :echo '-'<cr>
- aunmenu ]LANGUAGES_GHC
- if GHC_VersionGE([6,8])
- let ghc_supported_languages = split(system(g:ghc . ' --supported-languages'),'\n')
- for l in ghc_supported_languages
- exe 'amenu ]LANGUAGES_GHC.'.l.' :call append(0,"{-# LANGUAGE '.l.' #-}")<cr>'
- endfor
- if has("gui_running")
- map <LocalLeader>lang :popup ]LANGUAGES_GHC<cr>
- else
- map <LocalLeader>lang :emenu ]LANGUAGES_GHC.
- endif
- endif
- ftplugin/haskell.vim [[[1
- 14
- "
- " general Haskell source settings
- " (shared functions are in autoload/haskellmode.vim)
- "
- " (Claus Reinke, last modified: 28/04/2009)
- "
- " part of haskell plugins: http://projects.haskell.org/haskellmode-vim
- " please send patches to <claus.reinke@talk21.com>
- " try gf on import line, or ctrl-x ctrl-i, or [I, [i, ..
- setlocal include=^import\\s*\\(qualified\\)\\?\\s*
- setlocal includeexpr=substitute(v:fname,'\\.','/','g').'.'
- setlocal suffixesadd=hs,lhs,hsc
- ftplugin/haskell_doc.vim [[[1
- 837
- "
- " use haddock docs and index files
- " show documentation, complete & qualify identifiers
- "
- " (Claus Reinke; last modified: 30/04/2009)
- "
- " part of haskell plugins: http://projects.haskell.org/haskellmode-vim
- " please send patches to <claus.reinke@talk21.com>
- " :Doc <name> and :IDoc <name> open haddocks for <name> in opera
- "
- " :Doc needs qualified name (default Prelude) and package (default base)
- " :IDoc needs unqualified name, looks up possible links in g:haddock_index
- "
- " :DocIndex populates g:haddock_index from haddock's index files
- " :ExportDocIndex saves g:haddock_index to cache file
- " :ImportDocIndex reloads g:haddock_index from cache file
- "
- " all the following use the haddock index (g:haddock_index)
- "
- " _? opens haddocks for unqualified name under cursor,
- " suggesting alternative full qualifications in popup menu
- "
- " _. fully qualifies unqualified name under cursor,
- " suggesting alternative full qualifications in popup menu
- "
- " _i add import <module>(<name>) statement for unqualified <name> under cursor,
- " _im add import <module> statement for unqualified <name> under cursor,
- " suggesting alternative full qualifications in popup menu
- " (this currently adds one statement per call, instead of
- " merging into existing import statements, but it's a start;-)
- "
- " CTRL-X CTRL-U (user-defined insert mode completion)
- " suggests completions of unqualified names in popup menu
- let s:scriptname = "haskell_doc.vim"
- " script parameters
- " g:haddock_browser *mandatory* which browser to call
- " g:haddock_browser_callformat [optional] how to call browser
- " g:haddock_indexfiledir [optional] where to put 'haddock_index.vim'
- " g:haddock_docdir [optional] where to find html docs
- " g:ghc [optional] which ghc to call
- " g:ghc_pkg [optional] which ghc_pkg to call
- " been here before?
- if exists("g:haddock_index")
- finish
- endif
- " initialise nested dictionary, to be populated
- " - from haddock index files via :DocIndex
- " - from previous cached version via :ImportDocIndex
- let g:haddock_index = {}
- " initialise dictionary, mapping modules with haddocks to their packages,
- " populated via MkHaddockModuleIndex() or HaveModuleIndex()
- let g:haddock_moduleindex = {}
- " program to open urls, please set this in your vimrc
- "examples (for windows):
- "let g:haddock_browser = "C:/Program Files/Opera/Opera.exe"
- "let g:haddock_browser = "C:/Program Files/Mozilla Firefox/firefox.exe"
- "let g:haddock_browser = "C:/Program Files/Internet Explorer/IEXPLORE.exe"
- if !exists("g:haddock_browser")
- echoerr s:scriptname." WARNING: please set g:haddock_browser!"
- endif
- if (!exists("g:ghc") || !executable(g:ghc))
- if !executable('ghc')
- echoerr s:scriptname." can't find ghc. please set g:ghc, or extend $PATH"
- finish
- else
- let g:ghc = 'ghc'
- endif
- endif
- if (!exists("g:ghc_pkg") || !executable(g:ghc_pkg))
- let g:ghc_pkg = substitute(g:ghc,'\(.*\)ghc','\1ghc-pkg','')
- endif
- if exists("g:haddock_docdir") && isdirectory(g:haddock_docdir)
- let s:docdir = g:haddock_docdir
- elseif executable(g:ghc_pkg)
- " try to figure out location of html docs
- " first choice: where the base docs are (from the first base listed)
- let [field;x] = split(system(g:ghc_pkg . ' field base haddock-html'),'\n')
- let field = substitute(field,'haddock-html: \(.*\)libraries.base','\1','')
- let field = substitute(field,'\\','/','g')
- let alternate = substitute(field,'html','doc/html','')
- if isdirectory(field)
- let s:docdir = field
- elseif isdirectory(alternate)
- let s:docdir = alternate
- endif
- else
- echoerr s:scriptname." can't find ghc-pkg (set g:ghc_pkg ?)."
- endif
- " second choice: try some known suspects for windows/unix
- if !exists('s:docdir') || !isdirectory(s:docdir)
- let s:ghc_libdir = substitute(system(g:ghc . ' --print-libdir'),'\n','','')
- let location1a = s:ghc_libdir . '/doc/html/'
- let location1b = s:ghc_libdir . '/doc/'
- let s:ghc_version = substitute(system(g:ghc . ' --numeric-version'),'\n','','')
- let location2 = '/usr/share/doc/ghc-' . s:ghc_version . '/html/'
- if isdirectory(location1a)
- let s:docdir = location1a
- elseif isdirectory(location1b)
- let s:docdir = location1b
- elseif isdirectory(location2)
- let s:docdir = location2
- else " give up
- echoerr s:scriptname." can't find locaton of html documentation (set g:haddock_docdir)."
- finish
- endif
- endif
- " todo: can we turn s:docdir into a list of paths, and
- " include docs for third-party libs as well?
- let s:libraries = s:docdir . 'libraries/'
- let s:guide = s:docdir . 'users_guide/'
- let s:index = 'index.html'
- if exists("g:haddock_indexfiledir") && filewritable(g:haddock_indexfiledir)
- let s:haddock_indexfiledir = g:haddock_indexfiledir
- elseif filewritable(s:libraries)
- let s:haddock_indexfiledir = s:libraries
- elseif filewritable($HOME)
- let s:haddock_indexfiledir = $HOME.'/'
- else "give up
- echoerr s:scriptname." can't locate index file. please set g:haddock_indexfiledir"
- finish
- endif
- let s:haddock_indexfile = s:haddock_indexfiledir . 'haddock_index.vim'
- " different browser setups require different call formats;
- " you might want to call the browser synchronously or
- " asynchronously, and the latter is os-dependent;
- "
- " by default, the browser is started in the background when on
- " windows or if running in a gui, and in the foreground otherwise
- " (eg, console-mode for remote sessions, with text-mode browsers).
- "
- " you can override these defaults in your vimrc, via a format
- " string including 2 %s parameters (the first being the browser
- " to call, the second being the url).
- if !exists("g:haddock_browser_callformat")
- if has("win32") || has("win64")
- let g:haddock_browser_callformat = 'start %s "%s"'
- else
- if has("gui_running")
- let g:haddock_browser_callformat = '%s %s '.printf(&shellredir,'/dev/null').' &'
- else
- let g:haddock_browser_callformat = '%s %s'
- endif
- endif
- endif
- " allow map leader override
- if !exists("maplocalleader")
- let maplocalleader='_'
- endif
- command! DocSettings call DocSettings()
- function! DocSettings()
- for v in ["g:haddock_browser","g:haddock_browser_callformat","g:haddock_docdir","g:haddock_indexfiledir","s:ghc_libdir","s:ghc_version","s:docdir","s:libraries","s:guide","s:haddock_indexfile"]
- if exists(v)
- echo v '=' eval(v)
- else
- echo v '='
- endif
- endfor
- endfunction
- function! DocBrowser(url)
- "echomsg "DocBrowser(".url.")"
- if (!exists("g:haddock_browser") || !executable(g:haddock_browser))
- echoerr s:scriptname." can't find documentation browser. please set g:haddock_browser"
- return
- endif
- " start browser to open url, according to specified format
- let url = a:url=~'^\(file://\|http://\)' ? a:url : 'file://'.a:url
- silent exe '!'.printf(g:haddock_browser_callformat,g:haddock_browser,escape(url,'#%'))
- endfunction
- "Doc/Doct are an old interface for documentation lookup
- "(that is the reason they are not documented!-)
- "
- "These uses are still fine at the moment, and are the reason
- "that this command still exists at all
- "
- " :Doc -top
- " :Doc -libs
- " :Doc -guide
- "
- "These uses may or may not work, and shouldn't be relied on anymore
- "(usually, you want _?/_?1/_?2 or :MDoc; there is also :IDoc)
- "
- " :Doc length
- " :Doc Control.Monad.when
- " :Doc Data.List.
- " :Doc Control.Monad.State.runState mtl
- command! -nargs=+ Doc call Doc('v',<f-args>)
- command! -nargs=+ Doct call Doc('t',<f-args>)
- function! Doc(kind,qualname,...)
- let suffix = '.html'
- let relative = '#'.a:kind.'%3A'
- if a:qualname=="-top"
- call DocBrowser(s:docdir . s:index)
- return
- elseif a:qualname=="-libs"
- call DocBrowser(s:libraries . s:index)
- return
- elseif a:qualname=="-guide"
- call DocBrowser(s:guide . s:index)
- return
- endif
- if a:0==0 " no package specified
- let package = 'base/'
- else
- let package = a:1 . '/'
- endif
- if match(a:qualname,'\.')==-1 " unqualified name
- let [qual,name] = [['Prelude'],a:qualname]
- let file = join(qual,'-') . suffix . relative . name
- elseif a:qualname[-1:]=='.' " module qualifier only
- let parts = split(a:qualname,'\.')
- let quallen = len(parts)-1
- let [qual,name] = [parts[0:quallen],parts[-1]]
- let file = join(qual,'-') . suffix
- else " qualified name
- let parts = split(a:qualname,'\.')
- let quallen = len(parts)-2
- let [qual,name] = [parts[0:quallen],parts[-1]]
- let file = join(qual,'-') . suffix . relative . name
- endif
- let path = s:libraries . package . file
- call DocBrowser(path)
- endfunction
- " TODO: add commandline completion for :IDoc
- " switch to :emenu instead of inputlist?
- " indexed variant of Doc, looking up links in g:haddock_index
- " usage:
- " 1. :IDoc length
- " 2. click on one of the choices, or select by number (starting from 0)
- command! -nargs=+ IDoc call IDoc(<f-args>)
- function! IDoc(name,...)
- let choices = HaddockIndexLookup(a:name)
- if choices=={} | return | endif
- if a:0==0
- let keylist = map(deepcopy(keys(choices)),'substitute(v:val,"\\[.\\]","","")')
- let choice = inputlist(keylist)
- else
- let choice = a:1
- endif
- let path = values(choices)[choice] " assumes same order for keys/values..
- call DocBrowser(path)
- endfunction
- let s:flagref = s:guide . 'flag-reference.html'
- if filereadable(s:flagref)
- " extract the generated fragment ids for the
- " flag reference sections
- let s:headerPat = '.\{-}<h3 class="title"><a name="\([^"]*\)"><\/a>\([^<]*\)<\/h3>\(.*\)'
- let s:flagheaders = []
- let s:flagheaderids = {}
- let s:contents = join(readfile(s:flagref))
- let s:ml = matchlist(s:contents,s:headerPat)
- while s:ml!=[]
- let [_,s:id,s:title,s:r;s:x] = s:ml
- let s:flagheaders = add(s:flagheaders, s:title)
- let s:flagheaderids[s:title] = s:id
- let s:ml = matchlist(s:r,s:headerPat)
- endwhile
- command! -nargs=1 -complete=customlist,CompleteFlagHeaders FlagReference call FlagReference(<f-args>)
- function! FlagReference(section)
- let relativeUrl = a:section==""||!exists("s:flagheaderids['".a:section."']") ?
- \ "" : "#".s:flagheaderids[a:section]
- call DocBrowser(s:flagref.relativeUrl)
- endfunction
- function! CompleteFlagHeaders(al,cl,cp)
- let s:choices = s:flagheaders
- return CompleteAux(a:al,a:cl,a:cp)
- endfunction
- endif
- command! -nargs=1 -complete=customlist,CompleteHaddockModules MDoc call MDoc(<f-args>)
- function! MDoc(module)
- let suffix = '.html'
- call HaveModuleIndex()
- if !has_key(g:haddock_moduleindex,a:module)
- echoerr a:module 'not found in haddock module index'
- return
- endif
- let package = g:haddock_moduleindex[a:module]['package']
- let file = substitute(a:module,'\.','-','g') . suffix
- " let path = s:libraries . package . '/' . file
- let path = g:haddock_moduleindex[a:module]['html']
- call DocBrowser(path)
- endfunction
- function! CompleteHaddockModules(al,cl,cp)
- call HaveModuleIndex()
- let s:choices = keys(g:haddock_moduleindex)
- return CompleteAux(a:al,a:cl,a:cp)
- endfunction
- " create a dictionary g:haddock_index, containing the haddoc index
- command! DocIndex call DocIndex()
- function! DocIndex()
- let files = split(globpath(s:libraries,'doc-index*.html'),'\n')
- let g:haddock_index = {}
- call ProcessHaddockIndexes2(s:libraries,files)
- if GHC_VersionGE([6,8,2])
- if &shell =~ 'sh' " unix-type shell
- let s:addon_libraries = split(system(g:ghc_pkg . ' field \* haddock-html'),'\n')
- else " windows cmd.exe and the like
- let s:addon_libraries = split(system(g:ghc_pkg . ' field * haddock-html'),'\n')
- endif
- for addon in s:addon_libraries
- let ml = matchlist(addon,'haddock-html: \("\)\?\(file:///\)\?\([^"]*\)\("\)\?')
- if ml!=[]
- let [_,quote,file,addon_path;x] = ml
- let addon_path = substitute(addon_path,'\(\\\\\|\\\)','/','g')
- let addon_files = split(globpath(addon_path,'doc-index*.html'),'\n')
- call ProcessHaddockIndexes2(addon_path,addon_files)
- endif
- endfor
- endif
- return 1
- endfunction
- function! ProcessHaddockIndexes(location,files)
- let entryPat= '.\{-}"indexentry"[^>]*>\([^<]*\)<\(\%([^=]\{-}TD CLASS="\%(indexentry\)\@!.\{-}</TD\)*\)[^=]\{-}\(\%(="indexentry\|TABLE\).*\)'
- let linkPat = '.\{-}HREF="\([^"]*\)".>\([^<]*\)<\(.*\)'
- redraw
- echo 'populating g:haddock_index from haddock index files in ' a:location
- for f in a:files
- echo f[len(a:location):]
- let contents = join(readfile(f))
- let ml = matchlist(contents,entryPat)
- while ml!=[]
- let [_,entry,links,r;x] = ml
- "echo entry links
- let ml2 = matchlist(links,linkPat)
- let link = {}
- while ml2!=[]
- let [_,l,m,links;x] = ml2
- "echo l m
- let link[m] = a:location . '/' . l
- let ml2 = matchlist(links,linkPat)
- endwhile
- let g:haddock_index[DeHTML(entry)] = deepcopy(link)
- "echo entry g:haddock_index[entry]
- let ml = matchlist(r,entryPat)
- endwhile
- endfor
- endfunction
- " concatenating all lines is too slow for a big file, process lines directly
- function! ProcessHaddockIndexes2(location,files)
- let entryPat= '^>\([^<]*\)</'
- let linkPat = '.\{-}A HREF="\([^"]*\)"'
- let kindPat = '#\(.\)'
- " redraw
- echo 'populating g:haddock_index from haddock index files in ' a:location
- for f in a:files
- echo f[len(a:location):]
- let isEntry = 0
- let isLink = ''
- let link = {}
- let entry = ''
- for line in readfile(f)
- if line=~'CLASS="indexentry'
- if (link!={}) && (entry!='')
- if has_key(g:haddock_index,DeHTML(entry))
- let dict = extend(g:haddock_index[DeHTML(entry)],deepcopy(link))
- else
- let dict = deepcopy(link)
- endif
- let g:haddock_index[DeHTML(entry)] = dict
- let link = {}
- let entry = ''
- endif
- let isEntry=1
- continue
- endif
- if isEntry==1
- let ml = matchlist(line,entryPat)
- if ml!=[] | let [_,entry;x] = ml | let isEntry=0 | continue | endif
- endif
- if entry!=''
- let ml = matchlist(line,linkPat)
- if ml!=[] | let [_,isLink;x]=ml | continue | endif
- endif
- if isLink!=''
- let ml = matchlist(line,entryPat)
- if ml!=[]
- let [_,module;x] = ml
- let [_,kind;x] = matchlist(isLink,kindPat)
- let last = a:location[strlen(a:location)-1]
- let link[module."[".kind."]"] = a:location . (last=='/'?'':'/') . isLink
- let isLink=''
- continue
- endif
- endif
- endfor
- if link!={}
- if has_key(g:haddock_index,DeHTML(entry))
- let dict = extend(g:haddock_index[DeHTML(entry)],deepcopy(link))
- else
- let dict = deepcopy(link)
- endif
- let g:haddock_index[DeHTML(entry)] = dict
- endif
- endfor
- endfunction
- command! ExportDocIndex call ExportDocIndex()
- function! ExportDocIndex()
- call HaveIndex()
- let entries = []
- for key in keys(g:haddock_index)
- let entries += [key,string(g:haddock_index[key])]
- endfor
- call writefile(entries,s:haddock_indexfile)
- redir end
- endfunction
- command! ImportDocIndex call ImportDocIndex()
- function! ImportDocIndex()
- if filereadable(s:haddock_indexfile)
- let lines = readfile(s:haddock_indexfile)
- let i=0
- while i<len(lines)
- let [key,dict] = [lines[i],lines[i+1]]
- sandbox let g:haddock_index[key] = eval(dict)
- let i+=2
- endwhile
- return 1
- else
- return 0
- endif
- endfunction
- function! HaveIndex()
- return (g:haddock_index!={} || ImportDocIndex() || DocIndex() )
- endfunction
- function! MkHaddockModuleIndex()
- let g:haddock_moduleindex = {}
- call HaveIndex()
- for key in keys(g:haddock_index)
- let dict = g:haddock_index[key]
- for module in keys(dict)
- let html = dict[module]
- let html = substitute(html ,'#.*$','','')
- let module = substitute(module,'\[.\]','','')
- let ml = matchlist(html,'libraries/\([^\/]*\)\/')
- if ml!=[]
- let [_,package;x] = ml
- let g:haddock_moduleindex[module] = {'package':package,'html':html}
- endif
- let ml = matchlist(html,'/\([^\/]*\)\/html/[A-Z]')
- if ml!=[]
- let [_,package;x] = ml
- let g:haddock_moduleindex[module] = {'package':package,'html':html}
- endif
- endfor
- endfor
- endfunction
- function! HaveModuleIndex()
- return (g:haddock_moduleindex!={} || MkHaddockModuleIndex() )
- endfunction
- " decode HTML symbol encodings (are these all we need?)
- function! DeHTML(entry)
- let res = a:entry
- let decode = { '<': '<', '>': '>', '&': '\\&' }
- for enc in keys(decode)
- exe 'let res = substitute(res,"'.enc.'","'.decode[enc].'","g")'
- endfor
- return res
- endfunction
- " find haddocks for word under cursor
- " also lists possible definition sites
- " - needs to work for both qualified and unqualified items
- " - for 'import qualified M as A', consider M.item as source of A.item
- " - offer sources from both type [t] and value [v] namespaces
- " - for unqualified items, list all possible sites
- " - for qualified items, list imported sites only
- " keep track of keys with and without namespace tags:
- " the former are needed for lookup, the latter for matching against source
- map <LocalLeader>? :call Haddock()<cr>
- function! Haddock()
- amenu ]Popup.- :echo '-'<cr>
- aunmenu ]Popup
- let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),0)
- if namsym==[]
- redraw
- echo 'no name/symbol under cursor!'
- return 0
- endif
- let [start,symb,qual,unqual] = namsym
- let imports = haskellmode#GatherImports()
- let asm = has_key(imports[1],qual) ? imports[1][qual]['modules'] : []
- let name = unqual
- let dict = HaddockIndexLookup(name)
- if dict=={} | return | endif
- " for qualified items, narrow results to possible imports that provide qualifier
- let filteredKeys = filter(copy(keys(dict))
- \ ,'match(asm,substitute(v:val,''\[.\]'','''',''''))!=-1')
- let keys = (qual!='') ? filteredKeys : keys(dict)
- if (keys==[]) && (qual!='')
- echoerr qual.'.'.unqual.' not found in imports'
- return 0
- endif
- " use 'setlocal completeopt+=menuone' if you always want to see menus before
- " anything happens (I do, but many users don't..)
- if len(keys)==1 && (&completeopt!~'menuone')
- call DocBrowser(dict[keys[0]])
- elseif has("gui_running")
- for key in keys
- exe 'amenu ]Popup.'.escape(key,'\.').' :call DocBrowser('''.dict[key].''')<cr>'
- endfor
- popup ]Popup
- else
- let s:choices = keys
- let key = input('browse docs for '.name.' in: ','','customlist,CompleteAux')
- if key!=''
- call DocBrowser(dict[key])
- endif
- endif
- endfunction
- if !exists("g:haskell_search_engines")
- let g:haskell_search_engines =
- \ {'hoogle':'http://www.haskell.org/hoogle/?hoogle=%s'
- \ ,'hayoo!':'http://holumbus.fh-wedel.de/hayoo/hayoo.html?query=%s'
- \ }
- endif
- map <LocalLeader>?? :let es=g:haskell_search_engines
- \ \|echo "g:haskell_search_engines"
- \ \|for e in keys(es)
- \ \|echo e.' : '.es[e]
- \ \|endfor<cr>
- map <LocalLeader>?1 :call HaskellSearchEngine('hoogle')<cr>
- map <LocalLeader>?2 :call HaskellSearchEngine('hayoo!')<cr>
- " query one of the Haskell search engines for the thing under cursor
- " - unqualified symbols need to be url-escaped
- " - qualified ids need to be fed as separate qualifier and id for
- " both hoogle (doesn't handle qualified symbols) and hayoo! (no qualified
- " ids at all)
- " - qualified ids referring to import-qualified-as qualifiers need to be
- " translated to the multi-module searches over the list of original modules
- function! HaskellSearchEngine(engine)
- amenu ]Popup.- :echo '-'<cr>
- aunmenu ]Popup
- let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),0)
- if namsym==[]
- redraw
- echo 'no name/symbol under cursor!'
- return 0
- endif
- let [start,symb,qual,unqual] = namsym
- let imports = haskellmode#GatherImports()
- let asm = has_key(imports[1],qual) ? imports[1][qual]['modules'] : []
- let unqual = haskellmode#UrlEncode(unqual)
- if a:engine=='hoogle'
- let name = asm!=[] ? unqual.'+'.join(map(copy(asm),'"%2B".v:val'),'+')
- \ : qual!='' ? unqual.'+'.haskellmode#UrlEncode('+').qual
- \ : unqual
- elseif a:engine=='hayoo!'
- let name = asm!=[] ? unqual.'+module:('.join(copy(asm),' OR ').')'
- \ : qual!='' ? unqual.'+module:'.qual
- \ : unqual
- else
- let name = qual=="" ? unqual : qual.".".unqual
- endif
- if has_key(g:haskell_search_engines,a:engine)
- call DocBrowser(printf(g:haskell_search_engines[a:engine],name))
- else
- echoerr "unknown search engine: ".a:engine
- endif
- endfunction
- " used to pass on choices to CompleteAux
- let s:choices=[]
- " if there's no gui, use commandline completion instead of :popup
- " completion function CompleteAux suggests completions for a:al, wrt to s:choices
- function! CompleteAux(al,cl,cp)
- "echomsg '|'.a:al.'|'.a:cl.'|'.a:cp.'|'
- let res = []
- let l = len(a:al)-1
- for r in s:choices
- if l==-1 || r[0 : l]==a:al
- let res += [r]
- endif
- endfor
- return res
- endfunction
- " CamelCase shorthand matching:
- " favour upper-case letters and module qualifier separators (.) for disambiguation
- function! CamelCase(shorthand,string)
- let s1 = a:shorthand
- let s2 = a:string
- let notFirst = 0 " don't elide before first pattern letter
- while ((s1!="")&&(s2!=""))
- let head1 = s1[0]
- let head2 = s2[0]
- let elide = notFirst && ( ((head1=~'[A-Z]') && (head2!~'[A-Z.]'))
- \ ||((head1=='.') && (head2!='.')) )
- if elide
- let s2=s2[1:]
- elseif (head1==head2)
- let s1=s1[1:]
- let s2=s2[1:]
- else
- return 0
- endif
- let notFirst = (head1!='.')||(head2!='.') " treat separators as new beginnings
- endwhile
- return (s1=="")
- endfunction
- " use haddock name index for insert mode completion (CTRL-X CTRL-U)
- function! CompleteHaddock(findstart, base)
- if a:findstart
- let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),-1) " insert-mode: we're 1 beyond the text
- if namsym==[]
- redraw
- echo 'no name/symbol under cursor!'
- return -1
- endif
- let [start,symb,qual,unqual] = namsym
- return (start-1)
- else " find keys matching with "a:base"
- let res = []
- let l = len(a:base)-1
- let qual = a:base =~ '^[A-Z][a-zA-Z0-9_'']*\(\.[A-Z][a-zA-Z0-9_'']*\)*\(\.[a-zA-Z0-9_'']*\)\?$'
- call HaveIndex()
- for key in keys(g:haddock_index)
- let keylist = map(deepcopy(keys(g:haddock_index[key])),'substitute(v:val,"\\[.\\]","","")')
- if (key[0 : l]==a:base)
- for m in keylist
- let res += [{"word":key,"menu":m,"dup":1}]
- endfor
- elseif qual " this tends to be slower
- for m in keylist
- let word = m . '.' . key
- if word[0 : l]==a:base
- let res += [{"word":word,"menu":m,"dup":1}]
- endif
- endfor
- endif
- endfor
- if res==[] " no prefix matches, try CamelCase shortcuts
- for key in keys(g:haddock_index)
- let keylist = map(deepcopy(keys(g:haddock_index[key])),'substitute(v:val,"\\[.\\]","","")')
- if CamelCase(a:base,key)
- for m in keylist
- let res += [{"word":key,"menu":m,"dup":1}]
- endfor
- elseif qual " this tends to be slower
- for m in keylist
- let word = m . '.' . key
- if CamelCase(a:base,word)
- let res += [{"word":word,"menu":m,"dup":1}]
- endif
- endfor
- endif
- endfor
- endif
- return res
- endif
- endfunction
- setlocal completefunc=CompleteHaddock
- "
- " Vim's default completeopt is menu,preview
- " you probably want at least menu, or you won't see alternatives listed
- " setlocal completeopt+=menu
- " menuone is useful, but other haskellmode menus will try to follow your choice here in future
- " setlocal completeopt+=menuone
- " longest sounds useful, but doesn't seem to do what it says, and interferes with CTRL-E
- " setlocal completeopt-=longest
- " fully qualify an unqualified name
- " TODO: - standardise commandline versions of menus
- map <LocalLeader>. :call Qualify()<cr>
- function! Qualify()
- amenu ]Popup.- :echo '-'<cr>
- aunmenu ]Popup
- let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),0)
- if namsym==[]
- redraw
- echo 'no name/symbol under cursor!'
- return 0
- endif
- let [start,symb,qual,unqual] = namsym
- if qual!='' " TODO: should we support re-qualification?
- redraw
- echo 'already qualified'
- return 0
- endif
- let name = unqual
- let line = line('.')
- let prefix = (start<=1 ? '' : getline(line)[0:start-2] )
- let dict = HaddockIndexLookup(name)
- if dict=={} | return | endif
- let keylist = map(deepcopy(keys(dict)),'substitute(v:val,"\\[.\\]","","")')
- let imports = haskellmode#GatherImports()
- let qualifiedImports = []
- for qualifiedImport in keys(imports[1])
- let c=0
- for module in imports[1][qualifiedImport]['modules']
- if haskellmode#ListElem(keylist,module) | let c+=1 | endif
- endfor
- if c>0 | let qualifiedImports=[qualifiedImport]+qualifiedImports | endif
- endfor
- "let asm = has_key(imports[1],qual) ? imports[1][qual]['modules'] : []
- let keylist = filter(copy(keylist),'index(qualifiedImports,v:val)==-1')
- if has("gui_running")
- " amenu ]Popup.-imported- :
- for key in qualifiedImports
- let lhs=escape(prefix.name,'/.|\')
- let rhs=escape(prefix.key.'.'.name,'/&|\')
- exe 'amenu ]Popup.'.escape(key,'\.').' :'.line.'s/'.lhs.'/'.rhs.'/<cr>:noh<cr>'
- endfor
- amenu ]Popup.-not\ imported- :
- for key in keylist
- let lhs=escape(prefix.name,'/.|\')
- let rhs=escape(prefix.key.'.'.name,'/&|\')
- exe 'amenu ]Popup.'.escape(key,'\.').' :'.line.'s/'.lhs.'/'.rhs.'/<cr>:noh<cr>'
- endfor
- popup ]Popup
- else
- let s:choices = qualifiedImports+keylist
- let key = input('qualify '.name.' with: ','','customlist,CompleteAux')
- if key!=''
- let lhs=escape(prefix.name,'/.\')
- let rhs=escape(prefix.key.'.'.name,'/&\')
- exe line.'s/'.lhs.'/'.rhs.'/'
- noh
- endif
- endif
- endfunction
- " create (qualified) import for a (qualified) name
- " TODO: refine search patterns, to avoid misinterpretation of
- " oddities like import'Neither or not'module
- map <LocalLeader>i :call Import(0,0)<cr>
- map <LocalLeader>im :call Import(1,0)<cr>
- map <LocalLeader>iq :call Import(0,1)<cr>
- map <LocalLeader>iqm :call Import(1,1)<cr>
- function! Import(module,qualified)
- amenu ]Popup.- :echo '-'<cr>
- aunmenu ]Popup
- let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),0)
- if namsym==[]
- redraw
- echo 'no name/symbol under cursor!'
- return 0
- endif
- let [start,symb,qual,unqual] = namsym
- let name = unqual
- let pname = ( symb ? '('.name.')' : name )
- let importlist = a:module ? '' : '('.pname.')'
- let qualified = a:qualified ? 'qualified ' : ''
- if qual!=''
- exe 'call append(search(''\%1c\(\<import\>\|\<module\>\|{-# OPTIONS\|{-# LANGUAGE\)'',''nb''),''import '.qualified.qual.importlist.''')'
- return
- endif
- let line = line('.')
- let prefix = getline(line)[0:start-1]
- let dict = HaddockIndexLookup(name)
- if dict=={} | return | endif
- let keylist = map(deepcopy(keys(dict)),'substitute(v:val,"\\[.\\]","","")')
- if has("gui_running")
- for key in keylist
- " exe 'amenu ]Popup.'.escape(key,'\.').' :call append(search("\\%1c\\(import\\\\|module\\\\|{-# OPTIONS\\)","nb"),"import '.key.importlist.'")<cr>'
- exe 'amenu ]Popup.'.escape(key,'\.').' :call append(search(''\%1c\(\<import\>\\|\<module\>\\|{-# OPTIONS\\|{-# LANGUAGE\)'',''nb''),''import '.qualified.key.escape(importlist,'|').''')<cr>'
- endfor
- popup ]Popup
- else
- let s:choices = keylist
- let key = input('import '.name.' from: ','','customlist,CompleteAux')
- if key!=''
- exe 'call append(search(''\%1c\(\<import\>\|\<module\>\|{-# OPTIONS\|{-# LANGUAGE\)'',''nb''),''import '.qualified.key.importlist.''')'
- endif
- endif
- endfunction
- function! HaddockIndexLookup(name)
- call HaveIndex()
- if !has_key(g:haddock_index,a:name)
- echoerr a:name 'not found in haddock index'
- return {}
- endif
- return g:haddock_index[a:name]
- endfunction
- " copied from ghc.vim :-( should we move everything to using autoload instead?
- " we query the ghc version here, as we don't otherwise need it..
- function! GHC_VersionGE(target)
- let s:ghc_version = substitute(system(g:ghc . ' --numeric-version'),'\n','','')
- let current = split(g:ghc_version, '\.' )
- let target = a:target
- for i in current
- if ((target==[]) || (i>target[0]))
- return 1
- elseif (i==target[0])
- let target = target[1:]
- else
- return 0
- endif
- endfor
- return 1
- endfunction
- ftplugin/haskell_hpaste.vim [[[1
- 79
- " rudimentary hpaste support for vim
- " (using netrw for reading, wget for posting/annotating)
- "
- " claus reinke, last modified: 07/04/2009
- "
- " part of haskell plugins: http://projects.haskell.org/haskellmode-vim
- " unless wget is in your PATH, you need to set g:wget
- " before loading this script. windows users are out of
- " luck, unless they have wget installed (such as the
- " cygwin one looked for here), or adapt this script to
- " whatever alternative they have at hand (perhaps using
- " vim's perl/python bindings?)
- if !exists("g:wget")
- if executable("wget")
- let g:wget = "!wget -q"
- else
- let g:wget = "!c:\\cygwin\\bin\\wget -q"
- endif
- endif
- " read (recent) hpaste files
- " show index in new buffer, where ,r will open current entry
- " and ,p will annotate current entry with current buffer
- command! HpasteIndex call HpasteIndex()
- function! HpasteIndex()
- new
- read http://hpaste.org
- %s/\_$\_.//g
- %s/<tr[^>]*>//g
- %s/<\/tr>/
/g
- g/<\/table>/d
- g/DOCTYPE/d
- %s/<td>\([^<]*\)<\/td><td><a href="\/fastcgi\/hpaste\.fcgi\/view?id=\([0-9]*\)">\([^<]*\)<\/a><\/td><td>\([^<]*\)<\/td><td>\([^<]*\)<\/td><td>\([^<]*\)<\/td>/\2 [\1] "\3" \4 \5 \6/
- map <buffer> ,r 0yE:noh<cr>:call HpasteEditEntry('"')<cr>
- endfunction
- " load an existing entry for editing
- command! -nargs=1 HpasteEditEntry call HpasteEditEntry(<f-args>)
- function! HpasteEditEntry(entry)
- new
- exe 'Nread http://hpaste.org/fastcgi/hpaste.fcgi/raw?id='.a:entry
- "exe 'map <buffer> ,p :call HpasteAnnotate('''.a:entry.''')<cr>'
- endfunction
- " " posting temporarily disabled -- needs someone to look into new
- " " hpaste.org structure
- " " annotate existing entry (only to be called via ,p in HpasteIndex)
- " function! HpasteAnnotate(entry)
- " let nick = input("nick? ")
- " let title = input("title? ")
- " if nick=='' || title==''
- " echo "nick or title missing. aborting annotation"
- " return
- " endif
- " call HpastePost('annotate/'.a:entry,nick,title)
- " endfunction
- "
- " " post new hpaste entry
- " " using 'wget --post-data' and url-encoded content
- " command! HpastePostNew call HpastePost('new',<args>)
- " function! HpastePost(mode,nick,title,...)
- " let lines = getbufline("%",1,"$")
- " let pat = '\([^[:alnum:]]\)'
- " let code = '\=printf("%%%02X",char2nr(submatch(1)))'
- " let lines = map(lines,'substitute(v:val."\r\n",'''.pat.''','''.code.''',''g'')')
- "
- " let url = 'http://hpaste.org/' . a:mode
- " let nick = substitute(a:nick,pat,code,'g')
- " let title = substitute(a:title,pat,code,'g')
- " if a:0==0
- " let announce = 'false'
- " else
- " let announce = a:1
- " endif
- " let cmd = g:wget.' --post-data="content='.join(lines,'').'&nick='.nick.'&title='.title.'&announce='.announce.'" '.url
- " exe escape(cmd,'%')
- " endfunction
- autoload/haskellmode.vim [[[1
- 155
- "
- " utility functions for haskellmode plugins
- "
- " (Claus Reinke; last modified: 23/04/2009)
- "
- " part of haskell plugins: http://projects.haskell.org/haskellmode-vim
- " please send patches to <claus.reinke@talk21.com>
- " find start/extent of name/symbol under cursor;
- " return start, symbolic flag, qualifier, unqualified id
- " (this is used in both haskell_doc.vim and in GHC.vim)
- function! haskellmode#GetNameSymbol(line,col,off)
- let name = "[a-zA-Z0-9_']"
- let symbol = "[-!#$%&\*\+/<=>\?@\\^|~:.]"
- "let [line] = getbufline(a:buf,a:lnum)
- let line = a:line
- " find the beginning of unqualified id or qualified id component
- let start = (a:col - 1) + a:off
- if line[start] =~ name
- let pattern = name
- elseif line[start] =~ symbol
- let pattern = symbol
- else
- return []
- endif
- while start > 0 && line[start - 1] =~ pattern
- let start -= 1
- endwhile
- let id = matchstr(line[start :],pattern.'*')
- " call confirm(id)
- " expand id to left and right, to get full id
- let idPos = id[0] == '.' ? start+2 : start+1
- let posA = match(line,'\<\(\([A-Z]'.name.'*\.\)\+\)\%'.idPos.'c')
- let start = posA>-1 ? posA+1 : idPos
- let posB = matchend(line,'\%'.idPos.'c\(\([A-Z]'.name.'*\.\)*\)\('.name.'\+\|'.symbol.'\+\)')
- let end = posB>-1 ? posB : idPos
- " special case: symbolic ids starting with .
- if id[0]=='.' && posA==-1
- let start = idPos-1
- let end = posB==-1 ? start : end
- endif
- " classify full id and split into qualifier and unqualified id
- let fullid = line[ (start>1 ? start-1 : 0) : (end-1) ]
- let symbolic = fullid[-1:-1] =~ symbol " might also be incomplete qualified id ending in .
- let qualPos = matchend(fullid, '\([A-Z]'.name.'*\.\)\+')
- let qualifier = qualPos>-1 ? fullid[ 0 : (qualPos-2) ] : ''
- let unqualId = qualPos>-1 ? fullid[ qualPos : -1 ] : fullid
- " call confirm(start.'/'.end.'['.symbolic.']:'.qualifier.' '.unqualId)
- return [start,symbolic,qualifier,unqualId]
- endfunction
- function! haskellmode#GatherImports()
- let imports={0:{},1:{}}
- let i=1
- while i<=line('$')
- let res = haskellmode#GatherImport(i)
- if !empty(res)
- let [i,import] = res
- let prefixPat = '^import\s*\(qualified\)\?\s\+'
- let modulePat = '\([A-Z][a-zA-Z0-9_''.]*\)'
- let asPat = '\(\s\+as\s\+'.modulePat.'\)\?'
- let hidingPat = '\(\s\+hiding\s*\((.*)\)\)\?'
- let listPat = '\(\s*\((.*)\)\)\?'
- let importPat = prefixPat.modulePat.asPat.hidingPat.listPat ".'\s*$'
- let ml = matchlist(import,importPat)
- if ml!=[]
- let [_,qualified,module,_,as,_,hiding,_,explicit;x] = ml
- let what…