PageRenderTime 53ms CodeModel.GetById 9ms RepoModel.GetById 1ms app.codeStats 1ms

/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
  1. " Vimball Archiver by Charles E. Campbell, Jr., Ph.D.
  2. UseVimball
  3. finish
  4. compiler/ghc.vim [[[1
  5. 479
  6. " Vim Compiler File
  7. " Compiler: GHC
  8. " Maintainer: Claus Reinke <claus.reinke@talk21.com>
  9. " Last Change: 30/04/2009
  10. "
  11. " part of haskell plugins: http://projects.haskell.org/haskellmode-vim
  12. " ------------------------------ paths & quickfix settings first
  13. "
  14. if exists("current_compiler") && current_compiler == "ghc"
  15. finish
  16. endif
  17. let current_compiler = "ghc"
  18. let s:scriptname = "ghc.vim"
  19. if (!exists("g:ghc") || !executable(g:ghc))
  20. if !executable('ghc')
  21. echoerr s:scriptname.": can't find ghc. please set g:ghc, or extend $PATH"
  22. finish
  23. else
  24. let g:ghc = 'ghc'
  25. endif
  26. endif
  27. let ghc_version = substitute(system(g:ghc . ' --numeric-version'),'\n','','')
  28. if (!exists("b:ghc_staticoptions"))
  29. let b:ghc_staticoptions = ''
  30. endif
  31. " set makeprg (for quickfix mode)
  32. execute 'setlocal makeprg=' . g:ghc . '\ ' . escape(b:ghc_staticoptions,' ') .'\ -e\ :q\ %'
  33. "execute 'setlocal makeprg=' . g:ghc .'\ -e\ :q\ %'
  34. "execute 'setlocal makeprg=' . g:ghc .'\ --make\ %'
  35. " quickfix mode:
  36. " fetch file/line-info from error message
  37. " TODO: how to distinguish multiline errors from warnings?
  38. " (both have the same header, and errors have no common id-tag)
  39. " how to get rid of first empty message in result list?
  40. setlocal errorformat=
  41. \%-Z\ %#,
  42. \%W%f:%l:%c:\ Warning:\ %m,
  43. \%E%f:%l:%c:\ %m,
  44. \%E%>%f:%l:%c:,
  45. \%+C\ \ %#%m,
  46. \%W%>%f:%l:%c:,
  47. \%+C\ \ %#%tarning:\ %m,
  48. " oh, wouldn't you guess it - ghc reports (partially) to stderr..
  49. setlocal shellpipe=2>
  50. " ------------------------- but ghc can do a lot more for us..
  51. "
  52. " allow map leader override
  53. if !exists("maplocalleader")
  54. let maplocalleader='_'
  55. endif
  56. " initialize map of identifiers to their types
  57. " associate type map updates to changedtick
  58. if !exists("b:ghc_types")
  59. let b:ghc_types = {}
  60. let b:my_changedtick = b:changedtick
  61. endif
  62. if exists("g:haskell_functions")
  63. finish
  64. endif
  65. let g:haskell_functions = "ghc"
  66. " avoid hit-enter prompts
  67. set cmdheight=3
  68. " edit static GHC options
  69. " TODO: add completion for options/packages?
  70. command! GHCStaticOptions call GHC_StaticOptions()
  71. function! GHC_StaticOptions()
  72. let b:ghc_staticoptions = input('GHC static options: ',b:ghc_staticoptions)
  73. execute 'setlocal makeprg=' . g:ghc . '\ ' . escape(b:ghc_staticoptions,' ') .'\ -e\ :q\ %'
  74. let b:my_changedtick -=1
  75. endfunction
  76. map <LocalLeader>T :call GHC_ShowType(1)<cr>
  77. map <LocalLeader>t :call GHC_ShowType(0)<cr>
  78. function! GHC_ShowType(addTypeDecl)
  79. let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),0)
  80. if namsym==[]
  81. redraw
  82. echo 'no name/symbol under cursor!'
  83. return 0
  84. endif
  85. let [_,symb,qual,unqual] = namsym
  86. let name = qual=='' ? unqual : qual.'.'.unqual
  87. let pname = ( symb ? '('.name.')' : name )
  88. call GHC_HaveTypes()
  89. if !has_key(b:ghc_types,name)
  90. redraw
  91. echo pname "type not known"
  92. else
  93. redraw
  94. for type in split(b:ghc_types[name],' -- ')
  95. echo pname "::" type
  96. if a:addTypeDecl
  97. call append( line(".")-1, pname . " :: " . type )
  98. endif
  99. endfor
  100. endif
  101. endfunction
  102. " show type of identifier under mouse pointer in balloon
  103. if has("balloon_eval")
  104. set ballooneval
  105. set balloondelay=600
  106. set balloonexpr=GHC_TypeBalloon()
  107. function! GHC_TypeBalloon()
  108. if exists("b:current_compiler") && b:current_compiler=="ghc"
  109. let [line] = getbufline(v:beval_bufnr,v:beval_lnum)
  110. let namsym = haskellmode#GetNameSymbol(line,v:beval_col,0)
  111. if namsym==[]
  112. return ''
  113. endif
  114. let [start,symb,qual,unqual] = namsym
  115. let name = qual=='' ? unqual : qual.'.'.unqual
  116. let pname = name " ( symb ? '('.name.')' : name )
  117. silent call GHC_HaveTypes()
  118. if has("balloon_multiline")
  119. return (has_key(b:ghc_types,pname) ? split(b:ghc_types[pname],' -- ') : '')
  120. else
  121. return (has_key(b:ghc_types,pname) ? b:ghc_types[pname] : '')
  122. endif
  123. else
  124. return ''
  125. endif
  126. endfunction
  127. endif
  128. map <LocalLeader>si :call GHC_ShowInfo()<cr>
  129. function! GHC_ShowInfo()
  130. let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),0)
  131. if namsym==[]
  132. redraw
  133. echo 'no name/symbol under cursor!'
  134. return 0
  135. endif
  136. let [_,symb,qual,unqual] = namsym
  137. let name = qual=='' ? unqual : (qual.'.'.unqual)
  138. let output = GHC_Info(name)
  139. pclose | new
  140. setlocal previewwindow
  141. setlocal buftype=nofile
  142. setlocal noswapfile
  143. put =output
  144. wincmd w
  145. "redraw
  146. "echo output
  147. endfunction
  148. " fill the type map, unless nothing has changed since the last attempt
  149. function! GHC_HaveTypes()
  150. if b:ghc_types == {} && (b:my_changedtick != b:changedtick)
  151. let b:my_changedtick = b:changedtick
  152. return GHC_BrowseAll()
  153. endif
  154. endfunction
  155. " update b:ghc_types after successful make
  156. au QuickFixCmdPost make if GHC_CountErrors()==0 | silent call GHC_BrowseAll() | endif
  157. " count only error entries in quickfix list, ignoring warnings
  158. function! GHC_CountErrors()
  159. let c=0
  160. for e in getqflist() | if e.type=='E' && e.text !~ "^[ \n]*Warning:" | let c+=1 | endif | endfor
  161. return c
  162. endfunction
  163. command! GHCReload call GHC_BrowseAll()
  164. function! GHC_BrowseAll()
  165. " let imports = haskellmode#GatherImports()
  166. " let modules = keys(imports[0]) + keys(imports[1])
  167. let imports = {} " no need for them at the moment
  168. let current = GHC_NameCurrent()
  169. let module = current==[] ? 'Main' : current[0]
  170. if GHC_VersionGE([6,8,1])
  171. return GHC_BrowseBangStar(module)
  172. else
  173. return GHC_BrowseMultiple(imports,['*'.module])
  174. endif
  175. endfunction
  176. function! GHC_VersionGE(target)
  177. let current = split(g:ghc_version, '\.' )
  178. let target = a:target
  179. for i in current
  180. if ((target==[]) || (i>target[0]))
  181. return 1
  182. elseif (i==target[0])
  183. let target = target[1:]
  184. else
  185. return 0
  186. endif
  187. endfor
  188. return 1
  189. endfunction
  190. function! GHC_NameCurrent()
  191. let last = line("$")
  192. let l = 1
  193. while l<last
  194. let ml = matchlist( getline(l), '^module\s*\([^ (]*\)')
  195. if ml != []
  196. let [_,module;x] = ml
  197. return [module]
  198. endif
  199. let l += 1
  200. endwhile
  201. redraw
  202. echo "cannot find module header for file " . expand("%")
  203. return []
  204. endfunction
  205. function! GHC_BrowseBangStar(module)
  206. redraw
  207. echo "browsing module " a:module
  208. let command = ":browse! *" . a:module
  209. let orig_shellredir = &shellredir
  210. let &shellredir = ">" " ignore error/warning messages, only output or lack of it
  211. let output = system(g:ghc . ' ' . b:ghc_staticoptions . ' -v0 --interactive ' . expand("%") , command )
  212. let &shellredir = orig_shellredir
  213. return GHC_ProcessBang(a:module,output)
  214. endfunction
  215. function! GHC_BrowseMultiple(imports,modules)
  216. redraw
  217. echo "browsing modules " a:modules
  218. let command = ":browse " . join( a:modules, " \n :browse ")
  219. let command = substitute(command,'\(:browse \(\S*\)\)','putStrLn "-- \2" \n \1','g')
  220. let output = system(g:ghc . ' ' . b:ghc_staticoptions . ' -v0 --interactive ' . expand("%") , command )
  221. return GHC_Process(a:imports,output)
  222. endfunction
  223. function! GHC_Info(what)
  224. " call GHC_HaveTypes()
  225. let output = system(g:ghc . ' ' . b:ghc_staticoptions . ' -v0 --interactive ' . expand("%"), ":i ". a:what)
  226. return output
  227. endfunction
  228. function! GHC_ProcessBang(module,output)
  229. let module = a:module
  230. let b = a:output
  231. let linePat = '^\(.\{-}\)\n\(.*\)'
  232. let contPat = '\s\+\(.\{-}\)\n\(.*\)'
  233. let typePat = '^\(\)\(\S*\)\s*::\(.*\)'
  234. let commentPat = '^-- \(\S*\)'
  235. let definedPat = '^-- defined locally'
  236. let importedPat = '^-- imported via \(.*\)'
  237. if !(b=~commentPat)
  238. echo s:scriptname.": GHCi reports errors (try :make?)"
  239. return 0
  240. endif
  241. let b:ghc_types = {}
  242. let ml = matchlist( b , linePat )
  243. while ml != []
  244. let [_,l,rest;x] = ml
  245. let mlDecl = matchlist( l, typePat )
  246. if mlDecl != []
  247. let [_,indent,id,type;x] = mlDecl
  248. let ml2 = matchlist( rest , '^'.indent.contPat )
  249. while ml2 != []
  250. let [_,c,rest;x] = ml2
  251. let type .= c
  252. let ml2 = matchlist( rest , '^'.indent.contPat )
  253. endwhile
  254. let id = substitute( id, '^(\(.*\))$', '\1', '')
  255. let type = substitute( type, '\s\+', " ", "g" )
  256. " using :browse! *<current>, we get both unqualified and qualified ids
  257. let qualified = (id =~ '\.') && (id =~ '[A-Z]')
  258. let b:ghc_types[id] = type
  259. if !qualified
  260. for qual in qualifiers
  261. let b:ghc_types[qual.'.'.id] = type
  262. endfor
  263. endif
  264. else
  265. let mlImported = matchlist( l, importedPat )
  266. let mlDefined = matchlist( l, definedPat )
  267. if mlImported != []
  268. let [_,modules;x] = mlImported
  269. let qualifiers = split( modules, ', ' )
  270. elseif mlDefined != []
  271. let qualifiers = [module]
  272. endif
  273. endif
  274. let ml = matchlist( rest , linePat )
  275. endwhile
  276. return 1
  277. endfunction
  278. function! GHC_Process(imports,output)
  279. let b = a:output
  280. let imports = a:imports
  281. let linePat = '^\(.\{-}\)\n\(.*\)'
  282. let contPat = '\s\+\(.\{-}\)\n\(.*\)'
  283. let typePat = '^\(\s*\)\(\S*\)\s*::\(.*\)'
  284. let modPat = '^-- \(\S*\)'
  285. " add '-- defined locally' and '-- imported via ..'
  286. if !(b=~modPat)
  287. echo s:scriptname.": GHCi reports errors (try :make?)"
  288. return 0
  289. endif
  290. let b:ghc_types = {}
  291. let ml = matchlist( b , linePat )
  292. while ml != []
  293. let [_,l,rest;x] = ml
  294. let mlDecl = matchlist( l, typePat )
  295. if mlDecl != []
  296. let [_,indent,id,type;x] = mlDecl
  297. let ml2 = matchlist( rest , '^'.indent.contPat )
  298. while ml2 != []
  299. let [_,c,rest;x] = ml2
  300. let type .= c
  301. let ml2 = matchlist( rest , '^'.indent.contPat )
  302. endwhile
  303. let id = substitute(id, '^(\(.*\))$', '\1', '')
  304. let type = substitute( type, '\s\+', " ", "g" )
  305. " using :browse *<current>, we get both unqualified and qualified ids
  306. if current_module " || has_key(imports[0],module)
  307. if has_key(b:ghc_types,id) && !(matchstr(b:ghc_types[id],escape(type,'[].'))==type)
  308. let b:ghc_types[id] .= ' -- '.type
  309. else
  310. let b:ghc_types[id] = type
  311. endif
  312. endif
  313. if 0 " has_key(imports[1],module)
  314. let qualid = module.'.'.id
  315. let b:ghc_types[qualid] = type
  316. endif
  317. else
  318. let mlMod = matchlist( l, modPat )
  319. if mlMod != []
  320. let [_,module;x] = mlMod
  321. let current_module = module[0]=='*'
  322. let module = current_module ? module[1:] : module
  323. endif
  324. endif
  325. let ml = matchlist( rest , linePat )
  326. endwhile
  327. return 1
  328. endfunction
  329. let s:ghc_templates = ["module _ () where","class _ where","class _ => _ where","instance _ where","instance _ => _ where","type family _","type instance _ = ","data _ = ","newtype _ = ","type _ = "]
  330. " use ghci :browse index for insert mode omnicompletion (CTRL-X CTRL-O)
  331. function! GHC_CompleteImports(findstart, base)
  332. if a:findstart
  333. let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),-1) " insert-mode: we're 1 beyond the text
  334. if namsym==[]
  335. redraw
  336. echo 'no name/symbol under cursor!'
  337. return -1
  338. endif
  339. let [start,symb,qual,unqual] = namsym
  340. return (start-1)
  341. else " find keys matching with "a:base"
  342. let res = []
  343. let l = len(a:base)-1
  344. call GHC_HaveTypes()
  345. for key in keys(b:ghc_types)
  346. if key[0 : l]==a:base
  347. let res += [{"word":key,"menu":":: ".b:ghc_types[key],"dup":1}]
  348. endif
  349. endfor
  350. return res
  351. endif
  352. endfunction
  353. set omnifunc=GHC_CompleteImports
  354. "
  355. " Vim's default completeopt is menu,preview
  356. " you probably want at least menu, or you won't see alternatives listed
  357. " setlocal completeopt+=menu
  358. " menuone is useful, but other haskellmode menus will try to follow your choice here in future
  359. " setlocal completeopt+=menuone
  360. " longest sounds useful, but doesn't seem to do what it says, and interferes with CTRL-E
  361. " setlocal completeopt-=longest
  362. map <LocalLeader>ct :call GHC_CreateTagfile()<cr>
  363. function! GHC_CreateTagfile()
  364. redraw
  365. echo "creating tags file"
  366. let output = system(g:ghc . ' ' . b:ghc_staticoptions . ' -e ":ctags" ' . expand("%"))
  367. " for ghcs older than 6.6, you would need to call another program
  368. " here, such as hasktags
  369. echo output
  370. endfunction
  371. command! -nargs=1 GHCi redraw | echo system(g:ghc. ' ' . b:ghc_staticoptions .' '.expand("%").' -e "'.escape(<f-args>,'"').'"')
  372. " use :make 'not in scope' errors to explicitly list imported ids
  373. " cursor needs to be on import line, in correctly loadable module
  374. map <LocalLeader>ie :call GHC_MkImportsExplicit()<cr>
  375. function! GHC_MkImportsExplicit()
  376. let save_cursor = getpos(".")
  377. let line = getline('.')
  378. let lineno = line('.')
  379. let ml = matchlist(line,'^import\(\s*qualified\)\?\s*\([^( ]\+\)')
  380. if ml!=[]
  381. let [_,q,mod;x] = ml
  382. silent make
  383. if getqflist()==[]
  384. if line=~"import[^(]*Prelude"
  385. call setline(lineno,substitute(line,"(.*","","").'()')
  386. else
  387. call setline(lineno,'-- '.line)
  388. endif
  389. silent write
  390. silent make
  391. let qflist = getqflist()
  392. call setline(lineno,line)
  393. silent write
  394. let ids = {}
  395. for d in qflist
  396. let ml = matchlist(d.text,'Not in scope: \([^`]*\)`\([^'']*\)''')
  397. if ml!=[]
  398. let [_,what,qid;x] = ml
  399. let id = ( qid =~ "^[A-Z]" ? substitute(qid,'.*\.\([^.]*\)$','\1','') : qid )
  400. let pid = ( id =~ "[a-zA-Z0-9_']\\+" ? id : '('.id.')' )
  401. if what =~ "data"
  402. call GHC_HaveTypes()
  403. if has_key(b:ghc_types,id)
  404. let pid = substitute(b:ghc_types[id],'^.*->\s*\(\S*\).*$','\1','').'('.pid.')'
  405. else
  406. let pid = '???('.pid.')'
  407. endif
  408. endif
  409. let ids[pid] = 1
  410. endif
  411. endfor
  412. call setline(lineno,'import'.q.' '.mod.'('.join(keys(ids),',').')')
  413. else
  414. copen
  415. endif
  416. endif
  417. call setpos('.', save_cursor)
  418. endfunction
  419. if GHC_VersionGE([6,8,2])
  420. let opts = filter(split(substitute(system(g:ghc . ' -v0 --interactive', ':set'), ' ', '','g'), '\n'), 'v:val =~ "-f"')
  421. else
  422. let opts = ["-fglasgow-exts","-fallow-undecidable-instances","-fallow-overlapping-instances","-fno-monomorphism-restriction","-fno-mono-pat-binds","-fno-cse","-fbang-patterns","-funbox-strict-fields"]
  423. endif
  424. amenu ]OPTIONS_GHC.- :echo '-'<cr>
  425. aunmenu ]OPTIONS_GHC
  426. for o in opts
  427. exe 'amenu ]OPTIONS_GHC.'.o.' :call append(0,"{-# OPTIONS_GHC '.o.' #-}")<cr>'
  428. endfor
  429. if has("gui_running")
  430. map <LocalLeader>opt :popup ]OPTIONS_GHC<cr>
  431. else
  432. map <LocalLeader>opt :emenu ]OPTIONS_GHC.
  433. endif
  434. amenu ]LANGUAGES_GHC.- :echo '-'<cr>
  435. aunmenu ]LANGUAGES_GHC
  436. if GHC_VersionGE([6,8])
  437. let ghc_supported_languages = split(system(g:ghc . ' --supported-languages'),'\n')
  438. for l in ghc_supported_languages
  439. exe 'amenu ]LANGUAGES_GHC.'.l.' :call append(0,"{-# LANGUAGE '.l.' #-}")<cr>'
  440. endfor
  441. if has("gui_running")
  442. map <LocalLeader>lang :popup ]LANGUAGES_GHC<cr>
  443. else
  444. map <LocalLeader>lang :emenu ]LANGUAGES_GHC.
  445. endif
  446. endif
  447. ftplugin/haskell.vim [[[1
  448. 14
  449. "
  450. " general Haskell source settings
  451. " (shared functions are in autoload/haskellmode.vim)
  452. "
  453. " (Claus Reinke, last modified: 28/04/2009)
  454. "
  455. " part of haskell plugins: http://projects.haskell.org/haskellmode-vim
  456. " please send patches to <claus.reinke@talk21.com>
  457. " try gf on import line, or ctrl-x ctrl-i, or [I, [i, ..
  458. setlocal include=^import\\s*\\(qualified\\)\\?\\s*
  459. setlocal includeexpr=substitute(v:fname,'\\.','/','g').'.'
  460. setlocal suffixesadd=hs,lhs,hsc
  461. ftplugin/haskell_doc.vim [[[1
  462. 837
  463. "
  464. " use haddock docs and index files
  465. " show documentation, complete & qualify identifiers
  466. "
  467. " (Claus Reinke; last modified: 30/04/2009)
  468. "
  469. " part of haskell plugins: http://projects.haskell.org/haskellmode-vim
  470. " please send patches to <claus.reinke@talk21.com>
  471. " :Doc <name> and :IDoc <name> open haddocks for <name> in opera
  472. "
  473. " :Doc needs qualified name (default Prelude) and package (default base)
  474. " :IDoc needs unqualified name, looks up possible links in g:haddock_index
  475. "
  476. " :DocIndex populates g:haddock_index from haddock's index files
  477. " :ExportDocIndex saves g:haddock_index to cache file
  478. " :ImportDocIndex reloads g:haddock_index from cache file
  479. "
  480. " all the following use the haddock index (g:haddock_index)
  481. "
  482. " _? opens haddocks for unqualified name under cursor,
  483. " suggesting alternative full qualifications in popup menu
  484. "
  485. " _. fully qualifies unqualified name under cursor,
  486. " suggesting alternative full qualifications in popup menu
  487. "
  488. " _i add import <module>(<name>) statement for unqualified <name> under cursor,
  489. " _im add import <module> statement for unqualified <name> under cursor,
  490. " suggesting alternative full qualifications in popup menu
  491. " (this currently adds one statement per call, instead of
  492. " merging into existing import statements, but it's a start;-)
  493. "
  494. " CTRL-X CTRL-U (user-defined insert mode completion)
  495. " suggests completions of unqualified names in popup menu
  496. let s:scriptname = "haskell_doc.vim"
  497. " script parameters
  498. " g:haddock_browser *mandatory* which browser to call
  499. " g:haddock_browser_callformat [optional] how to call browser
  500. " g:haddock_indexfiledir [optional] where to put 'haddock_index.vim'
  501. " g:haddock_docdir [optional] where to find html docs
  502. " g:ghc [optional] which ghc to call
  503. " g:ghc_pkg [optional] which ghc_pkg to call
  504. " been here before?
  505. if exists("g:haddock_index")
  506. finish
  507. endif
  508. " initialise nested dictionary, to be populated
  509. " - from haddock index files via :DocIndex
  510. " - from previous cached version via :ImportDocIndex
  511. let g:haddock_index = {}
  512. " initialise dictionary, mapping modules with haddocks to their packages,
  513. " populated via MkHaddockModuleIndex() or HaveModuleIndex()
  514. let g:haddock_moduleindex = {}
  515. " program to open urls, please set this in your vimrc
  516. "examples (for windows):
  517. "let g:haddock_browser = "C:/Program Files/Opera/Opera.exe"
  518. "let g:haddock_browser = "C:/Program Files/Mozilla Firefox/firefox.exe"
  519. "let g:haddock_browser = "C:/Program Files/Internet Explorer/IEXPLORE.exe"
  520. if !exists("g:haddock_browser")
  521. echoerr s:scriptname." WARNING: please set g:haddock_browser!"
  522. endif
  523. if (!exists("g:ghc") || !executable(g:ghc))
  524. if !executable('ghc')
  525. echoerr s:scriptname." can't find ghc. please set g:ghc, or extend $PATH"
  526. finish
  527. else
  528. let g:ghc = 'ghc'
  529. endif
  530. endif
  531. if (!exists("g:ghc_pkg") || !executable(g:ghc_pkg))
  532. let g:ghc_pkg = substitute(g:ghc,'\(.*\)ghc','\1ghc-pkg','')
  533. endif
  534. if exists("g:haddock_docdir") && isdirectory(g:haddock_docdir)
  535. let s:docdir = g:haddock_docdir
  536. elseif executable(g:ghc_pkg)
  537. " try to figure out location of html docs
  538. " first choice: where the base docs are (from the first base listed)
  539. let [field;x] = split(system(g:ghc_pkg . ' field base haddock-html'),'\n')
  540. let field = substitute(field,'haddock-html: \(.*\)libraries.base','\1','')
  541. let field = substitute(field,'\\','/','g')
  542. let alternate = substitute(field,'html','doc/html','')
  543. if isdirectory(field)
  544. let s:docdir = field
  545. elseif isdirectory(alternate)
  546. let s:docdir = alternate
  547. endif
  548. else
  549. echoerr s:scriptname." can't find ghc-pkg (set g:ghc_pkg ?)."
  550. endif
  551. " second choice: try some known suspects for windows/unix
  552. if !exists('s:docdir') || !isdirectory(s:docdir)
  553. let s:ghc_libdir = substitute(system(g:ghc . ' --print-libdir'),'\n','','')
  554. let location1a = s:ghc_libdir . '/doc/html/'
  555. let location1b = s:ghc_libdir . '/doc/'
  556. let s:ghc_version = substitute(system(g:ghc . ' --numeric-version'),'\n','','')
  557. let location2 = '/usr/share/doc/ghc-' . s:ghc_version . '/html/'
  558. if isdirectory(location1a)
  559. let s:docdir = location1a
  560. elseif isdirectory(location1b)
  561. let s:docdir = location1b
  562. elseif isdirectory(location2)
  563. let s:docdir = location2
  564. else " give up
  565. echoerr s:scriptname." can't find locaton of html documentation (set g:haddock_docdir)."
  566. finish
  567. endif
  568. endif
  569. " todo: can we turn s:docdir into a list of paths, and
  570. " include docs for third-party libs as well?
  571. let s:libraries = s:docdir . 'libraries/'
  572. let s:guide = s:docdir . 'users_guide/'
  573. let s:index = 'index.html'
  574. if exists("g:haddock_indexfiledir") && filewritable(g:haddock_indexfiledir)
  575. let s:haddock_indexfiledir = g:haddock_indexfiledir
  576. elseif filewritable(s:libraries)
  577. let s:haddock_indexfiledir = s:libraries
  578. elseif filewritable($HOME)
  579. let s:haddock_indexfiledir = $HOME.'/'
  580. else "give up
  581. echoerr s:scriptname." can't locate index file. please set g:haddock_indexfiledir"
  582. finish
  583. endif
  584. let s:haddock_indexfile = s:haddock_indexfiledir . 'haddock_index.vim'
  585. " different browser setups require different call formats;
  586. " you might want to call the browser synchronously or
  587. " asynchronously, and the latter is os-dependent;
  588. "
  589. " by default, the browser is started in the background when on
  590. " windows or if running in a gui, and in the foreground otherwise
  591. " (eg, console-mode for remote sessions, with text-mode browsers).
  592. "
  593. " you can override these defaults in your vimrc, via a format
  594. " string including 2 %s parameters (the first being the browser
  595. " to call, the second being the url).
  596. if !exists("g:haddock_browser_callformat")
  597. if has("win32") || has("win64")
  598. let g:haddock_browser_callformat = 'start %s "%s"'
  599. else
  600. if has("gui_running")
  601. let g:haddock_browser_callformat = '%s %s '.printf(&shellredir,'/dev/null').' &'
  602. else
  603. let g:haddock_browser_callformat = '%s %s'
  604. endif
  605. endif
  606. endif
  607. " allow map leader override
  608. if !exists("maplocalleader")
  609. let maplocalleader='_'
  610. endif
  611. command! DocSettings call DocSettings()
  612. function! DocSettings()
  613. 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"]
  614. if exists(v)
  615. echo v '=' eval(v)
  616. else
  617. echo v '='
  618. endif
  619. endfor
  620. endfunction
  621. function! DocBrowser(url)
  622. "echomsg "DocBrowser(".url.")"
  623. if (!exists("g:haddock_browser") || !executable(g:haddock_browser))
  624. echoerr s:scriptname." can't find documentation browser. please set g:haddock_browser"
  625. return
  626. endif
  627. " start browser to open url, according to specified format
  628. let url = a:url=~'^\(file://\|http://\)' ? a:url : 'file://'.a:url
  629. silent exe '!'.printf(g:haddock_browser_callformat,g:haddock_browser,escape(url,'#%'))
  630. endfunction
  631. "Doc/Doct are an old interface for documentation lookup
  632. "(that is the reason they are not documented!-)
  633. "
  634. "These uses are still fine at the moment, and are the reason
  635. "that this command still exists at all
  636. "
  637. " :Doc -top
  638. " :Doc -libs
  639. " :Doc -guide
  640. "
  641. "These uses may or may not work, and shouldn't be relied on anymore
  642. "(usually, you want _?/_?1/_?2 or :MDoc; there is also :IDoc)
  643. "
  644. " :Doc length
  645. " :Doc Control.Monad.when
  646. " :Doc Data.List.
  647. " :Doc Control.Monad.State.runState mtl
  648. command! -nargs=+ Doc call Doc('v',<f-args>)
  649. command! -nargs=+ Doct call Doc('t',<f-args>)
  650. function! Doc(kind,qualname,...)
  651. let suffix = '.html'
  652. let relative = '#'.a:kind.'%3A'
  653. if a:qualname=="-top"
  654. call DocBrowser(s:docdir . s:index)
  655. return
  656. elseif a:qualname=="-libs"
  657. call DocBrowser(s:libraries . s:index)
  658. return
  659. elseif a:qualname=="-guide"
  660. call DocBrowser(s:guide . s:index)
  661. return
  662. endif
  663. if a:0==0 " no package specified
  664. let package = 'base/'
  665. else
  666. let package = a:1 . '/'
  667. endif
  668. if match(a:qualname,'\.')==-1 " unqualified name
  669. let [qual,name] = [['Prelude'],a:qualname]
  670. let file = join(qual,'-') . suffix . relative . name
  671. elseif a:qualname[-1:]=='.' " module qualifier only
  672. let parts = split(a:qualname,'\.')
  673. let quallen = len(parts)-1
  674. let [qual,name] = [parts[0:quallen],parts[-1]]
  675. let file = join(qual,'-') . suffix
  676. else " qualified name
  677. let parts = split(a:qualname,'\.')
  678. let quallen = len(parts)-2
  679. let [qual,name] = [parts[0:quallen],parts[-1]]
  680. let file = join(qual,'-') . suffix . relative . name
  681. endif
  682. let path = s:libraries . package . file
  683. call DocBrowser(path)
  684. endfunction
  685. " TODO: add commandline completion for :IDoc
  686. " switch to :emenu instead of inputlist?
  687. " indexed variant of Doc, looking up links in g:haddock_index
  688. " usage:
  689. " 1. :IDoc length
  690. " 2. click on one of the choices, or select by number (starting from 0)
  691. command! -nargs=+ IDoc call IDoc(<f-args>)
  692. function! IDoc(name,...)
  693. let choices = HaddockIndexLookup(a:name)
  694. if choices=={} | return | endif
  695. if a:0==0
  696. let keylist = map(deepcopy(keys(choices)),'substitute(v:val,"\\[.\\]","","")')
  697. let choice = inputlist(keylist)
  698. else
  699. let choice = a:1
  700. endif
  701. let path = values(choices)[choice] " assumes same order for keys/values..
  702. call DocBrowser(path)
  703. endfunction
  704. let s:flagref = s:guide . 'flag-reference.html'
  705. if filereadable(s:flagref)
  706. " extract the generated fragment ids for the
  707. " flag reference sections
  708. let s:headerPat = '.\{-}<h3 class="title"><a name="\([^"]*\)"><\/a>\([^<]*\)<\/h3>\(.*\)'
  709. let s:flagheaders = []
  710. let s:flagheaderids = {}
  711. let s:contents = join(readfile(s:flagref))
  712. let s:ml = matchlist(s:contents,s:headerPat)
  713. while s:ml!=[]
  714. let [_,s:id,s:title,s:r;s:x] = s:ml
  715. let s:flagheaders = add(s:flagheaders, s:title)
  716. let s:flagheaderids[s:title] = s:id
  717. let s:ml = matchlist(s:r,s:headerPat)
  718. endwhile
  719. command! -nargs=1 -complete=customlist,CompleteFlagHeaders FlagReference call FlagReference(<f-args>)
  720. function! FlagReference(section)
  721. let relativeUrl = a:section==""||!exists("s:flagheaderids['".a:section."']") ?
  722. \ "" : "#".s:flagheaderids[a:section]
  723. call DocBrowser(s:flagref.relativeUrl)
  724. endfunction
  725. function! CompleteFlagHeaders(al,cl,cp)
  726. let s:choices = s:flagheaders
  727. return CompleteAux(a:al,a:cl,a:cp)
  728. endfunction
  729. endif
  730. command! -nargs=1 -complete=customlist,CompleteHaddockModules MDoc call MDoc(<f-args>)
  731. function! MDoc(module)
  732. let suffix = '.html'
  733. call HaveModuleIndex()
  734. if !has_key(g:haddock_moduleindex,a:module)
  735. echoerr a:module 'not found in haddock module index'
  736. return
  737. endif
  738. let package = g:haddock_moduleindex[a:module]['package']
  739. let file = substitute(a:module,'\.','-','g') . suffix
  740. " let path = s:libraries . package . '/' . file
  741. let path = g:haddock_moduleindex[a:module]['html']
  742. call DocBrowser(path)
  743. endfunction
  744. function! CompleteHaddockModules(al,cl,cp)
  745. call HaveModuleIndex()
  746. let s:choices = keys(g:haddock_moduleindex)
  747. return CompleteAux(a:al,a:cl,a:cp)
  748. endfunction
  749. " create a dictionary g:haddock_index, containing the haddoc index
  750. command! DocIndex call DocIndex()
  751. function! DocIndex()
  752. let files = split(globpath(s:libraries,'doc-index*.html'),'\n')
  753. let g:haddock_index = {}
  754. call ProcessHaddockIndexes2(s:libraries,files)
  755. if GHC_VersionGE([6,8,2])
  756. if &shell =~ 'sh' " unix-type shell
  757. let s:addon_libraries = split(system(g:ghc_pkg . ' field \* haddock-html'),'\n')
  758. else " windows cmd.exe and the like
  759. let s:addon_libraries = split(system(g:ghc_pkg . ' field * haddock-html'),'\n')
  760. endif
  761. for addon in s:addon_libraries
  762. let ml = matchlist(addon,'haddock-html: \("\)\?\(file:///\)\?\([^"]*\)\("\)\?')
  763. if ml!=[]
  764. let [_,quote,file,addon_path;x] = ml
  765. let addon_path = substitute(addon_path,'\(\\\\\|\\\)','/','g')
  766. let addon_files = split(globpath(addon_path,'doc-index*.html'),'\n')
  767. call ProcessHaddockIndexes2(addon_path,addon_files)
  768. endif
  769. endfor
  770. endif
  771. return 1
  772. endfunction
  773. function! ProcessHaddockIndexes(location,files)
  774. let entryPat= '.\{-}"indexentry"[^>]*>\([^<]*\)<\(\%([^=]\{-}TD CLASS="\%(indexentry\)\@!.\{-}</TD\)*\)[^=]\{-}\(\%(="indexentry\|TABLE\).*\)'
  775. let linkPat = '.\{-}HREF="\([^"]*\)".>\([^<]*\)<\(.*\)'
  776. redraw
  777. echo 'populating g:haddock_index from haddock index files in ' a:location
  778. for f in a:files
  779. echo f[len(a:location):]
  780. let contents = join(readfile(f))
  781. let ml = matchlist(contents,entryPat)
  782. while ml!=[]
  783. let [_,entry,links,r;x] = ml
  784. "echo entry links
  785. let ml2 = matchlist(links,linkPat)
  786. let link = {}
  787. while ml2!=[]
  788. let [_,l,m,links;x] = ml2
  789. "echo l m
  790. let link[m] = a:location . '/' . l
  791. let ml2 = matchlist(links,linkPat)
  792. endwhile
  793. let g:haddock_index[DeHTML(entry)] = deepcopy(link)
  794. "echo entry g:haddock_index[entry]
  795. let ml = matchlist(r,entryPat)
  796. endwhile
  797. endfor
  798. endfunction
  799. " concatenating all lines is too slow for a big file, process lines directly
  800. function! ProcessHaddockIndexes2(location,files)
  801. let entryPat= '^>\([^<]*\)</'
  802. let linkPat = '.\{-}A HREF="\([^"]*\)"'
  803. let kindPat = '#\(.\)'
  804. " redraw
  805. echo 'populating g:haddock_index from haddock index files in ' a:location
  806. for f in a:files
  807. echo f[len(a:location):]
  808. let isEntry = 0
  809. let isLink = ''
  810. let link = {}
  811. let entry = ''
  812. for line in readfile(f)
  813. if line=~'CLASS="indexentry'
  814. if (link!={}) && (entry!='')
  815. if has_key(g:haddock_index,DeHTML(entry))
  816. let dict = extend(g:haddock_index[DeHTML(entry)],deepcopy(link))
  817. else
  818. let dict = deepcopy(link)
  819. endif
  820. let g:haddock_index[DeHTML(entry)] = dict
  821. let link = {}
  822. let entry = ''
  823. endif
  824. let isEntry=1
  825. continue
  826. endif
  827. if isEntry==1
  828. let ml = matchlist(line,entryPat)
  829. if ml!=[] | let [_,entry;x] = ml | let isEntry=0 | continue | endif
  830. endif
  831. if entry!=''
  832. let ml = matchlist(line,linkPat)
  833. if ml!=[] | let [_,isLink;x]=ml | continue | endif
  834. endif
  835. if isLink!=''
  836. let ml = matchlist(line,entryPat)
  837. if ml!=[]
  838. let [_,module;x] = ml
  839. let [_,kind;x] = matchlist(isLink,kindPat)
  840. let last = a:location[strlen(a:location)-1]
  841. let link[module."[".kind."]"] = a:location . (last=='/'?'':'/') . isLink
  842. let isLink=''
  843. continue
  844. endif
  845. endif
  846. endfor
  847. if link!={}
  848. if has_key(g:haddock_index,DeHTML(entry))
  849. let dict = extend(g:haddock_index[DeHTML(entry)],deepcopy(link))
  850. else
  851. let dict = deepcopy(link)
  852. endif
  853. let g:haddock_index[DeHTML(entry)] = dict
  854. endif
  855. endfor
  856. endfunction
  857. command! ExportDocIndex call ExportDocIndex()
  858. function! ExportDocIndex()
  859. call HaveIndex()
  860. let entries = []
  861. for key in keys(g:haddock_index)
  862. let entries += [key,string(g:haddock_index[key])]
  863. endfor
  864. call writefile(entries,s:haddock_indexfile)
  865. redir end
  866. endfunction
  867. command! ImportDocIndex call ImportDocIndex()
  868. function! ImportDocIndex()
  869. if filereadable(s:haddock_indexfile)
  870. let lines = readfile(s:haddock_indexfile)
  871. let i=0
  872. while i<len(lines)
  873. let [key,dict] = [lines[i],lines[i+1]]
  874. sandbox let g:haddock_index[key] = eval(dict)
  875. let i+=2
  876. endwhile
  877. return 1
  878. else
  879. return 0
  880. endif
  881. endfunction
  882. function! HaveIndex()
  883. return (g:haddock_index!={} || ImportDocIndex() || DocIndex() )
  884. endfunction
  885. function! MkHaddockModuleIndex()
  886. let g:haddock_moduleindex = {}
  887. call HaveIndex()
  888. for key in keys(g:haddock_index)
  889. let dict = g:haddock_index[key]
  890. for module in keys(dict)
  891. let html = dict[module]
  892. let html = substitute(html ,'#.*$','','')
  893. let module = substitute(module,'\[.\]','','')
  894. let ml = matchlist(html,'libraries/\([^\/]*\)\/')
  895. if ml!=[]
  896. let [_,package;x] = ml
  897. let g:haddock_moduleindex[module] = {'package':package,'html':html}
  898. endif
  899. let ml = matchlist(html,'/\([^\/]*\)\/html/[A-Z]')
  900. if ml!=[]
  901. let [_,package;x] = ml
  902. let g:haddock_moduleindex[module] = {'package':package,'html':html}
  903. endif
  904. endfor
  905. endfor
  906. endfunction
  907. function! HaveModuleIndex()
  908. return (g:haddock_moduleindex!={} || MkHaddockModuleIndex() )
  909. endfunction
  910. " decode HTML symbol encodings (are these all we need?)
  911. function! DeHTML(entry)
  912. let res = a:entry
  913. let decode = { '&lt;': '<', '&gt;': '>', '&amp;': '\\&' }
  914. for enc in keys(decode)
  915. exe 'let res = substitute(res,"'.enc.'","'.decode[enc].'","g")'
  916. endfor
  917. return res
  918. endfunction
  919. " find haddocks for word under cursor
  920. " also lists possible definition sites
  921. " - needs to work for both qualified and unqualified items
  922. " - for 'import qualified M as A', consider M.item as source of A.item
  923. " - offer sources from both type [t] and value [v] namespaces
  924. " - for unqualified items, list all possible sites
  925. " - for qualified items, list imported sites only
  926. " keep track of keys with and without namespace tags:
  927. " the former are needed for lookup, the latter for matching against source
  928. map <LocalLeader>? :call Haddock()<cr>
  929. function! Haddock()
  930. amenu ]Popup.- :echo '-'<cr>
  931. aunmenu ]Popup
  932. let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),0)
  933. if namsym==[]
  934. redraw
  935. echo 'no name/symbol under cursor!'
  936. return 0
  937. endif
  938. let [start,symb,qual,unqual] = namsym
  939. let imports = haskellmode#GatherImports()
  940. let asm = has_key(imports[1],qual) ? imports[1][qual]['modules'] : []
  941. let name = unqual
  942. let dict = HaddockIndexLookup(name)
  943. if dict=={} | return | endif
  944. " for qualified items, narrow results to possible imports that provide qualifier
  945. let filteredKeys = filter(copy(keys(dict))
  946. \ ,'match(asm,substitute(v:val,''\[.\]'','''',''''))!=-1')
  947. let keys = (qual!='') ? filteredKeys : keys(dict)
  948. if (keys==[]) && (qual!='')
  949. echoerr qual.'.'.unqual.' not found in imports'
  950. return 0
  951. endif
  952. " use 'setlocal completeopt+=menuone' if you always want to see menus before
  953. " anything happens (I do, but many users don't..)
  954. if len(keys)==1 && (&completeopt!~'menuone')
  955. call DocBrowser(dict[keys[0]])
  956. elseif has("gui_running")
  957. for key in keys
  958. exe 'amenu ]Popup.'.escape(key,'\.').' :call DocBrowser('''.dict[key].''')<cr>'
  959. endfor
  960. popup ]Popup
  961. else
  962. let s:choices = keys
  963. let key = input('browse docs for '.name.' in: ','','customlist,CompleteAux')
  964. if key!=''
  965. call DocBrowser(dict[key])
  966. endif
  967. endif
  968. endfunction
  969. if !exists("g:haskell_search_engines")
  970. let g:haskell_search_engines =
  971. \ {'hoogle':'http://www.haskell.org/hoogle/?hoogle=%s'
  972. \ ,'hayoo!':'http://holumbus.fh-wedel.de/hayoo/hayoo.html?query=%s'
  973. \ }
  974. endif
  975. map <LocalLeader>?? :let es=g:haskell_search_engines
  976. \ \|echo "g:haskell_search_engines"
  977. \ \|for e in keys(es)
  978. \ \|echo e.' : '.es[e]
  979. \ \|endfor<cr>
  980. map <LocalLeader>?1 :call HaskellSearchEngine('hoogle')<cr>
  981. map <LocalLeader>?2 :call HaskellSearchEngine('hayoo!')<cr>
  982. " query one of the Haskell search engines for the thing under cursor
  983. " - unqualified symbols need to be url-escaped
  984. " - qualified ids need to be fed as separate qualifier and id for
  985. " both hoogle (doesn't handle qualified symbols) and hayoo! (no qualified
  986. " ids at all)
  987. " - qualified ids referring to import-qualified-as qualifiers need to be
  988. " translated to the multi-module searches over the list of original modules
  989. function! HaskellSearchEngine(engine)
  990. amenu ]Popup.- :echo '-'<cr>
  991. aunmenu ]Popup
  992. let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),0)
  993. if namsym==[]
  994. redraw
  995. echo 'no name/symbol under cursor!'
  996. return 0
  997. endif
  998. let [start,symb,qual,unqual] = namsym
  999. let imports = haskellmode#GatherImports()
  1000. let asm = has_key(imports[1],qual) ? imports[1][qual]['modules'] : []
  1001. let unqual = haskellmode#UrlEncode(unqual)
  1002. if a:engine=='hoogle'
  1003. let name = asm!=[] ? unqual.'+'.join(map(copy(asm),'"%2B".v:val'),'+')
  1004. \ : qual!='' ? unqual.'+'.haskellmode#UrlEncode('+').qual
  1005. \ : unqual
  1006. elseif a:engine=='hayoo!'
  1007. let name = asm!=[] ? unqual.'+module:('.join(copy(asm),' OR ').')'
  1008. \ : qual!='' ? unqual.'+module:'.qual
  1009. \ : unqual
  1010. else
  1011. let name = qual=="" ? unqual : qual.".".unqual
  1012. endif
  1013. if has_key(g:haskell_search_engines,a:engine)
  1014. call DocBrowser(printf(g:haskell_search_engines[a:engine],name))
  1015. else
  1016. echoerr "unknown search engine: ".a:engine
  1017. endif
  1018. endfunction
  1019. " used to pass on choices to CompleteAux
  1020. let s:choices=[]
  1021. " if there's no gui, use commandline completion instead of :popup
  1022. " completion function CompleteAux suggests completions for a:al, wrt to s:choices
  1023. function! CompleteAux(al,cl,cp)
  1024. "echomsg '|'.a:al.'|'.a:cl.'|'.a:cp.'|'
  1025. let res = []
  1026. let l = len(a:al)-1
  1027. for r in s:choices
  1028. if l==-1 || r[0 : l]==a:al
  1029. let res += [r]
  1030. endif
  1031. endfor
  1032. return res
  1033. endfunction
  1034. " CamelCase shorthand matching:
  1035. " favour upper-case letters and module qualifier separators (.) for disambiguation
  1036. function! CamelCase(shorthand,string)
  1037. let s1 = a:shorthand
  1038. let s2 = a:string
  1039. let notFirst = 0 " don't elide before first pattern letter
  1040. while ((s1!="")&&(s2!=""))
  1041. let head1 = s1[0]
  1042. let head2 = s2[0]
  1043. let elide = notFirst && ( ((head1=~'[A-Z]') && (head2!~'[A-Z.]'))
  1044. \ ||((head1=='.') && (head2!='.')) )
  1045. if elide
  1046. let s2=s2[1:]
  1047. elseif (head1==head2)
  1048. let s1=s1[1:]
  1049. let s2=s2[1:]
  1050. else
  1051. return 0
  1052. endif
  1053. let notFirst = (head1!='.')||(head2!='.') " treat separators as new beginnings
  1054. endwhile
  1055. return (s1=="")
  1056. endfunction
  1057. " use haddock name index for insert mode completion (CTRL-X CTRL-U)
  1058. function! CompleteHaddock(findstart, base)
  1059. if a:findstart
  1060. let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),-1) " insert-mode: we're 1 beyond the text
  1061. if namsym==[]
  1062. redraw
  1063. echo 'no name/symbol under cursor!'
  1064. return -1
  1065. endif
  1066. let [start,symb,qual,unqual] = namsym
  1067. return (start-1)
  1068. else " find keys matching with "a:base"
  1069. let res = []
  1070. let l = len(a:base)-1
  1071. let qual = a:base =~ '^[A-Z][a-zA-Z0-9_'']*\(\.[A-Z][a-zA-Z0-9_'']*\)*\(\.[a-zA-Z0-9_'']*\)\?$'
  1072. call HaveIndex()
  1073. for key in keys(g:haddock_index)
  1074. let keylist = map(deepcopy(keys(g:haddock_index[key])),'substitute(v:val,"\\[.\\]","","")')
  1075. if (key[0 : l]==a:base)
  1076. for m in keylist
  1077. let res += [{"word":key,"menu":m,"dup":1}]
  1078. endfor
  1079. elseif qual " this tends to be slower
  1080. for m in keylist
  1081. let word = m . '.' . key
  1082. if word[0 : l]==a:base
  1083. let res += [{"word":word,"menu":m,"dup":1}]
  1084. endif
  1085. endfor
  1086. endif
  1087. endfor
  1088. if res==[] " no prefix matches, try CamelCase shortcuts
  1089. for key in keys(g:haddock_index)
  1090. let keylist = map(deepcopy(keys(g:haddock_index[key])),'substitute(v:val,"\\[.\\]","","")')
  1091. if CamelCase(a:base,key)
  1092. for m in keylist
  1093. let res += [{"word":key,"menu":m,"dup":1}]
  1094. endfor
  1095. elseif qual " this tends to be slower
  1096. for m in keylist
  1097. let word = m . '.' . key
  1098. if CamelCase(a:base,word)
  1099. let res += [{"word":word,"menu":m,"dup":1}]
  1100. endif
  1101. endfor
  1102. endif
  1103. endfor
  1104. endif
  1105. return res
  1106. endif
  1107. endfunction
  1108. setlocal completefunc=CompleteHaddock
  1109. "
  1110. " Vim's default completeopt is menu,preview
  1111. " you probably want at least menu, or you won't see alternatives listed
  1112. " setlocal completeopt+=menu
  1113. " menuone is useful, but other haskellmode menus will try to follow your choice here in future
  1114. " setlocal completeopt+=menuone
  1115. " longest sounds useful, but doesn't seem to do what it says, and interferes with CTRL-E
  1116. " setlocal completeopt-=longest
  1117. " fully qualify an unqualified name
  1118. " TODO: - standardise commandline versions of menus
  1119. map <LocalLeader>. :call Qualify()<cr>
  1120. function! Qualify()
  1121. amenu ]Popup.- :echo '-'<cr>
  1122. aunmenu ]Popup
  1123. let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),0)
  1124. if namsym==[]
  1125. redraw
  1126. echo 'no name/symbol under cursor!'
  1127. return 0
  1128. endif
  1129. let [start,symb,qual,unqual] = namsym
  1130. if qual!='' " TODO: should we support re-qualification?
  1131. redraw
  1132. echo 'already qualified'
  1133. return 0
  1134. endif
  1135. let name = unqual
  1136. let line = line('.')
  1137. let prefix = (start<=1 ? '' : getline(line)[0:start-2] )
  1138. let dict = HaddockIndexLookup(name)
  1139. if dict=={} | return | endif
  1140. let keylist = map(deepcopy(keys(dict)),'substitute(v:val,"\\[.\\]","","")')
  1141. let imports = haskellmode#GatherImports()
  1142. let qualifiedImports = []
  1143. for qualifiedImport in keys(imports[1])
  1144. let c=0
  1145. for module in imports[1][qualifiedImport]['modules']
  1146. if haskellmode#ListElem(keylist,module) | let c+=1 | endif
  1147. endfor
  1148. if c>0 | let qualifiedImports=[qualifiedImport]+qualifiedImports | endif
  1149. endfor
  1150. "let asm = has_key(imports[1],qual) ? imports[1][qual]['modules'] : []
  1151. let keylist = filter(copy(keylist),'index(qualifiedImports,v:val)==-1')
  1152. if has("gui_running")
  1153. " amenu ]Popup.-imported- :
  1154. for key in qualifiedImports
  1155. let lhs=escape(prefix.name,'/.|\')
  1156. let rhs=escape(prefix.key.'.'.name,'/&|\')
  1157. exe 'amenu ]Popup.'.escape(key,'\.').' :'.line.'s/'.lhs.'/'.rhs.'/<cr>:noh<cr>'
  1158. endfor
  1159. amenu ]Popup.-not\ imported- :
  1160. for key in keylist
  1161. let lhs=escape(prefix.name,'/.|\')
  1162. let rhs=escape(prefix.key.'.'.name,'/&|\')
  1163. exe 'amenu ]Popup.'.escape(key,'\.').' :'.line.'s/'.lhs.'/'.rhs.'/<cr>:noh<cr>'
  1164. endfor
  1165. popup ]Popup
  1166. else
  1167. let s:choices = qualifiedImports+keylist
  1168. let key = input('qualify '.name.' with: ','','customlist,CompleteAux')
  1169. if key!=''
  1170. let lhs=escape(prefix.name,'/.\')
  1171. let rhs=escape(prefix.key.'.'.name,'/&\')
  1172. exe line.'s/'.lhs.'/'.rhs.'/'
  1173. noh
  1174. endif
  1175. endif
  1176. endfunction
  1177. " create (qualified) import for a (qualified) name
  1178. " TODO: refine search patterns, to avoid misinterpretation of
  1179. " oddities like import'Neither or not'module
  1180. map <LocalLeader>i :call Import(0,0)<cr>
  1181. map <LocalLeader>im :call Import(1,0)<cr>
  1182. map <LocalLeader>iq :call Import(0,1)<cr>
  1183. map <LocalLeader>iqm :call Import(1,1)<cr>
  1184. function! Import(module,qualified)
  1185. amenu ]Popup.- :echo '-'<cr>
  1186. aunmenu ]Popup
  1187. let namsym = haskellmode#GetNameSymbol(getline('.'),col('.'),0)
  1188. if namsym==[]
  1189. redraw
  1190. echo 'no name/symbol under cursor!'
  1191. return 0
  1192. endif
  1193. let [start,symb,qual,unqual] = namsym
  1194. let name = unqual
  1195. let pname = ( symb ? '('.name.')' : name )
  1196. let importlist = a:module ? '' : '('.pname.')'
  1197. let qualified = a:qualified ? 'qualified ' : ''
  1198. if qual!=''
  1199. exe 'call append(search(''\%1c\(\<import\>\|\<module\>\|{-# OPTIONS\|{-# LANGUAGE\)'',''nb''),''import '.qualified.qual.importlist.''')'
  1200. return
  1201. endif
  1202. let line = line('.')
  1203. let prefix = getline(line)[0:start-1]
  1204. let dict = HaddockIndexLookup(name)
  1205. if dict=={} | return | endif
  1206. let keylist = map(deepcopy(keys(dict)),'substitute(v:val,"\\[.\\]","","")')
  1207. if has("gui_running")
  1208. for key in keylist
  1209. " exe 'amenu ]Popup.'.escape(key,'\.').' :call append(search("\\%1c\\(import\\\\|module\\\\|{-# OPTIONS\\)","nb"),"import '.key.importlist.'")<cr>'
  1210. exe 'amenu ]Popup.'.escape(key,'\.').' :call append(search(''\%1c\(\<import\>\\|\<module\>\\|{-# OPTIONS\\|{-# LANGUAGE\)'',''nb''),''import '.qualified.key.escape(importlist,'|').''')<cr>'
  1211. endfor
  1212. popup ]Popup
  1213. else
  1214. let s:choices = keylist
  1215. let key = input('import '.name.' from: ','','customlist,CompleteAux')
  1216. if key!=''
  1217. exe 'call append(search(''\%1c\(\<import\>\|\<module\>\|{-# OPTIONS\|{-# LANGUAGE\)'',''nb''),''import '.qualified.key.importlist.''')'
  1218. endif
  1219. endif
  1220. endfunction
  1221. function! HaddockIndexLookup(name)
  1222. call HaveIndex()
  1223. if !has_key(g:haddock_index,a:name)
  1224. echoerr a:name 'not found in haddock index'
  1225. return {}
  1226. endif
  1227. return g:haddock_index[a:name]
  1228. endfunction
  1229. " copied from ghc.vim :-( should we move everything to using autoload instead?
  1230. " we query the ghc version here, as we don't otherwise need it..
  1231. function! GHC_VersionGE(target)
  1232. let s:ghc_version = substitute(system(g:ghc . ' --numeric-version'),'\n','','')
  1233. let current = split(g:ghc_version, '\.' )
  1234. let target = a:target
  1235. for i in current
  1236. if ((target==[]) || (i>target[0]))
  1237. return 1
  1238. elseif (i==target[0])
  1239. let target = target[1:]
  1240. else
  1241. return 0
  1242. endif
  1243. endfor
  1244. return 1
  1245. endfunction
  1246. ftplugin/haskell_hpaste.vim [[[1
  1247. 79
  1248. " rudimentary hpaste support for vim
  1249. " (using netrw for reading, wget for posting/annotating)
  1250. "
  1251. " claus reinke, last modified: 07/04/2009
  1252. "
  1253. " part of haskell plugins: http://projects.haskell.org/haskellmode-vim
  1254. " unless wget is in your PATH, you need to set g:wget
  1255. " before loading this script. windows users are out of
  1256. " luck, unless they have wget installed (such as the
  1257. " cygwin one looked for here), or adapt this script to
  1258. " whatever alternative they have at hand (perhaps using
  1259. " vim's perl/python bindings?)
  1260. if !exists("g:wget")
  1261. if executable("wget")
  1262. let g:wget = "!wget -q"
  1263. else
  1264. let g:wget = "!c:\\cygwin\\bin\\wget -q"
  1265. endif
  1266. endif
  1267. " read (recent) hpaste files
  1268. " show index in new buffer, where ,r will open current entry
  1269. " and ,p will annotate current entry with current buffer
  1270. command! HpasteIndex call HpasteIndex()
  1271. function! HpasteIndex()
  1272. new
  1273. read http://hpaste.org
  1274. %s/\_$\_.//g
  1275. %s/<tr[^>]*>//g
  1276. %s/<\/tr>/ /g
  1277. g/<\/table>/d
  1278. g/DOCTYPE/d
  1279. %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/
  1280. map <buffer> ,r 0yE:noh<cr>:call HpasteEditEntry('"')<cr>
  1281. endfunction
  1282. " load an existing entry for editing
  1283. command! -nargs=1 HpasteEditEntry call HpasteEditEntry(<f-args>)
  1284. function! HpasteEditEntry(entry)
  1285. new
  1286. exe 'Nread http://hpaste.org/fastcgi/hpaste.fcgi/raw?id='.a:entry
  1287. "exe 'map <buffer> ,p :call HpasteAnnotate('''.a:entry.''')<cr>'
  1288. endfunction
  1289. " " posting temporarily disabled -- needs someone to look into new
  1290. " " hpaste.org structure
  1291. " " annotate existing entry (only to be called via ,p in HpasteIndex)
  1292. " function! HpasteAnnotate(entry)
  1293. " let nick = input("nick? ")
  1294. " let title = input("title? ")
  1295. " if nick=='' || title==''
  1296. " echo "nick or title missing. aborting annotation"
  1297. " return
  1298. " endif
  1299. " call HpastePost('annotate/'.a:entry,nick,title)
  1300. " endfunction
  1301. "
  1302. " " post new hpaste entry
  1303. " " using 'wget --post-data' and url-encoded content
  1304. " command! HpastePostNew call HpastePost('new',<args>)
  1305. " function! HpastePost(mode,nick,title,...)
  1306. " let lines = getbufline("%",1,"$")
  1307. " let pat = '\([^[:alnum:]]\)'
  1308. " let code = '\=printf("%%%02X",char2nr(submatch(1)))'
  1309. " let lines = map(lines,'substitute(v:val."\r\n",'''.pat.''','''.code.''',''g'')')
  1310. "
  1311. " let url = 'http://hpaste.org/' . a:mode
  1312. " let nick = substitute(a:nick,pat,code,'g')
  1313. " let title = substitute(a:title,pat,code,'g')
  1314. " if a:0==0
  1315. " let announce = 'false'
  1316. " else
  1317. " let announce = a:1
  1318. " endif
  1319. " let cmd = g:wget.' --post-data="content='.join(lines,'').'&nick='.nick.'&title='.title.'&announce='.announce.'" '.url
  1320. " exe escape(cmd,'%')
  1321. " endfunction
  1322. autoload/haskellmode.vim [[[1
  1323. 155
  1324. "
  1325. " utility functions for haskellmode plugins
  1326. "
  1327. " (Claus Reinke; last modified: 23/04/2009)
  1328. "
  1329. " part of haskell plugins: http://projects.haskell.org/haskellmode-vim
  1330. " please send patches to <claus.reinke@talk21.com>
  1331. " find start/extent of name/symbol under cursor;
  1332. " return start, symbolic flag, qualifier, unqualified id
  1333. " (this is used in both haskell_doc.vim and in GHC.vim)
  1334. function! haskellmode#GetNameSymbol(line,col,off)
  1335. let name = "[a-zA-Z0-9_']"
  1336. let symbol = "[-!#$%&\*\+/<=>\?@\\^|~:.]"
  1337. "let [line] = getbufline(a:buf,a:lnum)
  1338. let line = a:line
  1339. " find the beginning of unqualified id or qualified id component
  1340. let start = (a:col - 1) + a:off
  1341. if line[start] =~ name
  1342. let pattern = name
  1343. elseif line[start] =~ symbol
  1344. let pattern = symbol
  1345. else
  1346. return []
  1347. endif
  1348. while start > 0 && line[start - 1] =~ pattern
  1349. let start -= 1
  1350. endwhile
  1351. let id = matchstr(line[start :],pattern.'*')
  1352. " call confirm(id)
  1353. " expand id to left and right, to get full id
  1354. let idPos = id[0] == '.' ? start+2 : start+1
  1355. let posA = match(line,'\<\(\([A-Z]'.name.'*\.\)\+\)\%'.idPos.'c')
  1356. let start = posA>-1 ? posA+1 : idPos
  1357. let posB = matchend(line,'\%'.idPos.'c\(\([A-Z]'.name.'*\.\)*\)\('.name.'\+\|'.symbol.'\+\)')
  1358. let end = posB>-1 ? posB : idPos
  1359. " special case: symbolic ids starting with .
  1360. if id[0]=='.' && posA==-1
  1361. let start = idPos-1
  1362. let end = posB==-1 ? start : end
  1363. endif
  1364. " classify full id and split into qualifier and unqualified id
  1365. let fullid = line[ (start>1 ? start-1 : 0) : (end-1) ]
  1366. let symbolic = fullid[-1:-1] =~ symbol " might also be incomplete qualified id ending in .
  1367. let qualPos = matchend(fullid, '\([A-Z]'.name.'*\.\)\+')
  1368. let qualifier = qualPos>-1 ? fullid[ 0 : (qualPos-2) ] : ''
  1369. let unqualId = qualPos>-1 ? fullid[ qualPos : -1 ] : fullid
  1370. " call confirm(start.'/'.end.'['.symbolic.']:'.qualifier.' '.unqualId)
  1371. return [start,symbolic,qualifier,unqualId]
  1372. endfunction
  1373. function! haskellmode#GatherImports()
  1374. let imports={0:{},1:{}}
  1375. let i=1
  1376. while i<=line('$')
  1377. let res = haskellmode#GatherImport(i)
  1378. if !empty(res)
  1379. let [i,import] = res
  1380. let prefixPat = '^import\s*\(qualified\)\?\s\+'
  1381. let modulePat = '\([A-Z][a-zA-Z0-9_''.]*\)'
  1382. let asPat = '\(\s\+as\s\+'.modulePat.'\)\?'
  1383. let hidingPat = '\(\s\+hiding\s*\((.*)\)\)\?'
  1384. let listPat = '\(\s*\((.*)\)\)\?'
  1385. let importPat = prefixPat.modulePat.asPat.hidingPat.listPat ".'\s*$'
  1386. let ml = matchlist(import,importPat)
  1387. if ml!=[]
  1388. let [_,qualified,module,_,as,_,hiding,_,explicit;x] = ml
  1389. let what = as=='' ? module : as
  1390. let hidings = split(hiding[1:-2],',')
  1391. let explicits = split(explicit[1:-2],',')
  1392. let empty = {'lines':[],'hiding':hidings,'explicit':[],'modules':[]}
  1393. let entry = has_key(imports[1],what) ? imports[1][what] : deepcopy(empty)
  1394. let imports[1][what] = haskellmode#MergeImport(deepcopy(entry),i,hidings,explicits,module)
  1395. if !(qualified=='qualified')
  1396. let imports[0][what] = haskellmode#MergeImport(deepcopy(entry),i,hidings,explicits,module)
  1397. endif
  1398. else
  1399. echoerr "haskellmode#GatherImports doesn't understand: ".import
  1400. endif
  1401. endif
  1402. let i+=1
  1403. endwhile
  1404. if !has_key(imports[1],'Prelude')
  1405. let imports[0]['Prelude'] = {'lines':[],'hiding':[],'explicit':[],'modules':[]}
  1406. let imports[1]['Prelude'] = {'lines':[],'hiding':[],'explicit':[],'modules':[]}
  1407. endif
  1408. return imports
  1409. endfunction
  1410. function! haskellmode#ListElem(list,elem)
  1411. for e in a:list | if e==a:elem | return 1 | endif | endfor
  1412. return 0
  1413. endfunction
  1414. function! haskellmode#ListIntersect(list1,list2)
  1415. let l = []
  1416. for e in a:list1 | if index(a:list2,e)!=-1 | let l += [e] | endif | endfor
  1417. return l
  1418. endfunction
  1419. function! haskellmode#ListUnion(list1,list2)
  1420. let l = []
  1421. for e in a:list2 | if index(a:list1,e)==-1 | let l += [e] | endif | endfor
  1422. return a:list1 + l
  1423. endfunction
  1424. function! haskellmode#ListWithout(list1,list2)
  1425. let l = []
  1426. for e in a:list1 | if index(a:list2,e)==-1 | let l += [e] | endif | endfor
  1427. return l
  1428. endfunction
  1429. function! haskellmode#MergeImport(entry,line,hiding,explicit,module)
  1430. let lines = a:entry['lines'] + [ a:line ]
  1431. let hiding = a:explicit==[] ? haskellmode#ListIntersect(a:entry['hiding'], a:hiding)
  1432. \ : haskellmode#ListWithout(a:entry['hiding'],a:explicit)
  1433. let explicit = haskellmode#ListUnion(a:entry['explicit'], a:explicit)
  1434. let modules = haskellmode#ListUnion(a:entry['modules'], [ a:module ])
  1435. return {'lines':lines,'hiding':hiding,'explicit':explicit,'modules':modules}
  1436. endfunction
  1437. " collect lines belonging to a single import statement;
  1438. " return number of last line and collected import statement
  1439. " (assume opening parenthesis, if any, is on the first line)
  1440. function! haskellmode#GatherImport(lineno)
  1441. let lineno = a:lineno
  1442. let import = getline(lineno)
  1443. if !(import=~'^import\s') | return [] | endif
  1444. let open = strlen(substitute(import,'[^(]','','g'))
  1445. let close = strlen(substitute(import,'[^)]','','g'))
  1446. while open!=close
  1447. let lineno += 1
  1448. let linecont = getline(lineno)
  1449. let open += strlen(substitute(linecont,'[^(]','','g'))
  1450. let close += strlen(substitute(linecont,'[^)]','','g'))
  1451. let import .= linecont
  1452. endwhile
  1453. return [lineno,import]
  1454. endfunction
  1455. function! haskellmode#UrlEncode(string)
  1456. let pat = '\([^[:alnum:]]\)'
  1457. let code = '\=printf("%%%02X",char2nr(submatch(1)))'
  1458. let url = substitute(a:string,pat,code,'g')
  1459. return url
  1460. endfunction
  1461. doc/haskellmode.txt [[[1
  1462. 456
  1463. *haskellmode.txt* Haskell Mode Plugins 23/04/2009
  1464. Authors:
  1465. Claus Reinke <claus.reinke@talk21.com> ~
  1466. Homepage:
  1467. http://projects.haskell.org/haskellmode-vim
  1468. CONTENTS *haskellmode*
  1469. 1. Overview |haskellmode-overview|
  1470. 1.1 Runtime Requirements |haskellmode-requirements|
  1471. 1.2 Quick Reference |haskellmode-quickref|
  1472. 2. Settings |haskellmode-settings|
  1473. 2.1 GHC and web browser |haskellmode-settings-main|
  1474. 2.2 Fine tuning - more configuration options |haskellmode-settings-fine|
  1475. 3. GHC Compiler Integration |haskellmode-compiler|
  1476. 4. Haddock Integration |haskellmode-haddock|
  1477. 4.1 Indexing |haskellmode-indexing|
  1478. 4.2 Lookup |haskellmode-lookup|
  1479. 4.3 Editing |haskellmode-editing|
  1480. 5. Hpaste Integration |haskellmode-hpaste|
  1481. 6. Additional Resources |haskellmode-resources|
  1482. ==============================================================================
  1483. *haskellmode-overview*
  1484. 1. Overview ~
  1485. The Haskell mode plugins provide advanced support for Haskell development
  1486. using GHC/GHCi on Windows and Unix-like systems. The functionality is
  1487. based on Haddock-generated library indices, on GHCi's interactive
  1488. commands, or on simply activating (some of) Vim's built-in program editing
  1489. support in Haskell-relevant fashion. These plugins live side-by-side with
  1490. the pre-defined |syntax-highlighting| support for |haskell| sources, and
  1491. any other Haskell-related plugins you might want to install (see
  1492. |haskellmode-resources|).
  1493. The Haskell mode plugins consist of three filetype plugins (haskell.vim,
  1494. haskell_doc.vim, haskell_hpaste.vim), which by Vim's |filetype| detection
  1495. mechanism will be auto-loaded whenever files with the extension '.hs' are
  1496. opened, and one compiler plugin (ghc.vim) which you will need to load from
  1497. your vimrc file (see |haskellmode-settings|).
  1498. *haskellmode-requirements*
  1499. 1.1 Runtime Requirements ~
  1500. The plugins require a recent installation of GHC/GHCi. The functionality
  1501. derived from Haddock-generated library indices also requires a local
  1502. installation of the Haddock documentation for GHC's libraries (if there is
  1503. no documentation package for your system, you can download a tar-ball from
  1504. haskell.org), as well as an HTML browser (see |haddock_browser|). If you
  1505. want to use the experimental hpaste interface, you will also need Wget.
  1506. * GHC/GHCi ~
  1507. Provides core functionality. http://www.haskell.org/ghc
  1508. * HTML library documentation files and indices generated by Haddock ~
  1509. These usually come with your GHC installation, possibly as a separate
  1510. package. If you cannot get them this way, you can download a tar-ball
  1511. matching your GHC version from http://www.haskell.org/ghc/docs/
  1512. * HTML browser with basic CSS support ~
  1513. For browsing Haddock docs.
  1514. * Wget ~
  1515. For interfacing with http://hpaste.org.
  1516. Wget is widely available for modern Unix-like operating systems. Several
  1517. ports also exist for Windows, including:
  1518. - Official GNU Wget (natively compiled for Win32)
  1519. http://www.gnu.org/software/wget/#downloading
  1520. - UnxUtils Wget (natively compiled for Win32, bundled with other ported
  1521. Unix utilities)
  1522. http://sourceforge.net/projects/unxutils/
  1523. - Cygwin Wget (emulated POSIX in Win32, must be run under Cygwin)
  1524. http://cygwin.com/packages/wget/
  1525. *haskellmode-quickref*
  1526. 1.2 Quick Reference ~
  1527. |:make| load into GHCi, show errors (|quickfix| |:copen|)
  1528. |_ct| create |tags| file
  1529. |_si| show info for id under cursor
  1530. |_t| show type for id under cursor
  1531. |_T| insert type declaration for id under cursor
  1532. |balloon| show type for id under mouse pointer
  1533. |_?| browse Haddock entry for id under cursor
  1534. |_?1| search Hoogle for id under cursor
  1535. |_?2| search Hayoo! for id under cursor
  1536. |:IDoc| {identifier} browse Haddock entry for unqualified {identifier}
  1537. |:MDoc| {module} browse Haddock entry for {module}
  1538. |:FlagReference| {s} browse Users Guide Flag Reference for section {s}
  1539. |_.| qualify unqualified id under cursor
  1540. |_i| add 'import <module>(<identifier>)' for id under cursor
  1541. |_im| add 'import <module>' for id under cursor
  1542. |_iq| add 'import qualified <module>(<identifier>)' for id under cursor
  1543. |_iqm| add 'import qualified <module>' for id under cursor
  1544. |_ie| make imports explit for import statement under cursor
  1545. |_opt| add OPTIONS_GHC pragma
  1546. |_lang| add LANGUAGE pragma
  1547. |i_CTRL-X_CTRL-O| insert-mode completion based on imported ids (|haskellmode-XO|)
  1548. |i_CTRL-X_CTRL-U| insert-mode completion based on documented ids (|haskellmode-XU|)
  1549. |i_CTRL-N| insert-mode completion based on imported sources
  1550. |:GHCi|{command/expr} run GHCi command/expr in current module
  1551. |:GHCStaticOptions| edit static GHC options for this buffer
  1552. |:DocSettings| show current Haddock-files-related plugin settings
  1553. |:DocIndex| populate Haddock index
  1554. |:ExportDocIndex| cache current Haddock index to a file
  1555. |:HpasteIndex| Read index of most recent entries from hpaste.org
  1556. |:HpastePostNew| Submit current buffer as a new hpaste
  1557. ==============================================================================
  1558. *haskellmode-settings*
  1559. 2. Settings ~
  1560. The plugins try to find their dependencies in standard locations, so if
  1561. you're lucky, you will only need to set |compiler| to ghc, and configure
  1562. the location of your favourite web browser. You will also want to make
  1563. sure that |filetype| detection and |syntax| highlighting are on. Given the
  1564. variety of things to guess, however, some dependencies might not be found
  1565. correctly, or the defaults might not be to your liking, in which case you
  1566. can do some more fine tuning. All of this configuration should happen in
  1567. your |vimrc|.
  1568. >
  1569. " enable syntax highlighting
  1570. syntax on
  1571. " enable filetype detection and plugin loading
  1572. filetype plugin on
  1573. <
  1574. *haskellmode-settings-main*
  1575. 2.1 GHC and web browser ~
  1576. *compiler-ghc* *ghc-compiler*
  1577. To use the features provided by the GHC |compiler| plugin, use the
  1578. following |autocommand| in your vimrc:
  1579. >
  1580. au BufEnter *.hs compiler ghc
  1581. <
  1582. *g:ghc*
  1583. If the compiler plugin can't locate your GHC binary, or if you have
  1584. several versions of GHC installed and have a preference as to which binary
  1585. is used, set |g:ghc|:
  1586. >
  1587. :let g:ghc="/usr/bin/ghc-6.6.1"
  1588. <
  1589. *g:haddock_browser*
  1590. The preferred HTML browser for viewing Haddock documentation can be set as
  1591. follows:
  1592. >
  1593. :let g:haddock_browser="/usr/bin/firefox"
  1594. <
  1595. *haskellmode-settings-fine*
  1596. 2.2 Fine tuning - more configuration options ~
  1597. Most of the fine tuning is likely to happen for the haskellmode_doc.vim
  1598. plugin, so you can check the current settings for this plugin via the
  1599. command |:DocSettings|. If all the settings reported there are to your
  1600. liking, you probably won't need to do any fine tuning.
  1601. *g:haddock_browser_callformat*
  1602. By default, the web browser|g:haddock_browser| will be started
  1603. asynchronously (in the background) on Windows or when vim is running in a
  1604. GUI, and synchronously (in the foreground) otherwise. These settings seem
  1605. to work fine if you are using a console mode browser (eg, when editing in
  1606. a remote session), or if you are starting a GUI browser that will launch
  1607. itself in the background. But if these settings do not work for you, you
  1608. can change the default browser launching behavior.
  1609. This is controlled by |g:haddock_browser_callformat|. It specifies a
  1610. format string which uses two '%s' parameters, the first representing the
  1611. path of the browser to launch, and the second is the documentation URL
  1612. (minus the protocol specifier, i.e. file://) passed to it by the Haddock
  1613. plugin. For instance, to launch a GUI browser on Unix-like systems and
  1614. force it to the background (see also |shellredir|):
  1615. >
  1616. :let g:haddock_browser_callformat = '%s file://%s '.printf(&shellredir,'/dev/null').' &'
  1617. <
  1618. *g:haddock_docdir*
  1619. Your system's installed Haddock documentation for GHC and its libraries
  1620. should be automatically detected. If the plugin can't locate them, you
  1621. must point |g:haddock_docdir| to the path containing the master index.html
  1622. file for the subdirectories 'libraries', 'Cabal', 'users_guide', etc.:
  1623. >
  1624. :let g:haddock_docdir="/usr/local/share/doc/ghc/html/"
  1625. <
  1626. *g:haddock_indexfiledir*
  1627. The information gathered from Haddock's index files will be stored in a
  1628. file called 'haddock_index.vim' in a directory derived from the Haddock
  1629. location, or in $HOME. To configure another directory for the index file,
  1630. use:
  1631. >
  1632. :let g:haddock_indexfiledir="~/.vim/"
  1633. <
  1634. *g:wget*
  1635. If you also want to try the experimental hpaste functionality, you might
  1636. you need to set |g:wget| before the |hpaste| plugin is loaded (unless wget
  1637. is in your PATH):
  1638. >
  1639. :let g:wget="C:\Program Files\wget\wget.exe"
  1640. <
  1641. Finally, the mappings actually use|<LocalLeader>|behind the scenes, so if
  1642. you have to, you can redefine|maplocalleader|to something other than '_'.
  1643. Just remember that the docs still refer to mappings starting with '_', to
  1644. avoid confusing the majority of users!-)
  1645. ==============================================================================
  1646. *haskellmode-compiler* *ghc*
  1647. 3. GHC Compiler Integration ~
  1648. The GHC |compiler| plugin sets the basic |errorformat| and |makeprg| to
  1649. enable |quickfix| mode using GHCi, and provides functionality for show
  1650. info (|_si|), show type (|_t| or mouse |balloon|), add type declaration
  1651. (|_T|), create tag file (|_ct|), and insert-mode completion
  1652. (|i_CTRL-X_CTRL-O|) based on GHCi browsing of the current and imported
  1653. modules.
  1654. To avoid frequent calls to GHCi, type information is cached in Vim. The
  1655. cache will be populated the first time a command depends on it, and will
  1656. be refreshed every time a |:make| goes through without generating errors
  1657. (if the |:make| does not succeed, the old types will remain available in
  1658. Vim). You can also unconditionally force reloading of type info using
  1659. |:GHCReload| (if GHCi cannot load your file, the type info will be empty).
  1660. In addition to the standard|quickfix| commands, the GHC compiler plugin
  1661. provides:
  1662. *:GHCReload*
  1663. :GHCReload Reload modules and unconditionally refresh cache of
  1664. type info. Usually, |:make| is prefered, as that will
  1665. refresh the cache only if GHCi reports no errors, and
  1666. show the errors otherwise.
  1667. *:GHCStaticOptions*
  1668. :GHCStaticOptions Edit the static GHC options for the current buffer.
  1669. Useful for adding hidden packages (-package ghc).
  1670. *:GHCi*
  1671. :GHCi {command/expr} Run GHCi commands/expressions in the current module.
  1672. *_ct*
  1673. _ct Create |tags| file for the current Haskell source
  1674. file. This uses GHCi's :ctags command, so it will work
  1675. recursively, but will only list tags for exported
  1676. entities.
  1677. *_opt*
  1678. _opt Shows a menu of frequently used GHC compiler options
  1679. (selecting an entry adds the option as a pragma to the
  1680. start of the file). Uses popup menu (GUI) or :emenu
  1681. and command-line completion (CLI).
  1682. *_lang*
  1683. _lang Shows a menu of the LANGUAGE options supported by GHC
  1684. (selecting an entry adds the language as a pragma to
  1685. the start of the file). Uses popup menu (GUI) or
  1686. :emenu and command-line completion (CLI).
  1687. *_si*
  1688. _si Show extended information for the name under the
  1689. cursor. Uses GHCi's :info command. Output appears in
  1690. |preview-window| (when done, close with |:pclose|).
  1691. *_t*
  1692. _t Show type for the name under the cursor. Uses cached
  1693. info from GHCi's :browse command.
  1694. *_T*
  1695. _T Insert type declaration for the name under the cursor.
  1696. Uses cached info from GHCi's :browse command.
  1697. *haskellmode-XO* *haskellmode-omni-completion*
  1698. CTRL-X CTRL-O Standard insert-mode omni-completion based on the
  1699. cached type info from GHCi browsing current and
  1700. imported modules. Only names from the current and from
  1701. imported modules are included (the completion menu
  1702. also show the type of each identifier).
  1703. ==============================================================================
  1704. *haskellmode-haddock* *haddock*
  1705. 4. Haddock Integration ~
  1706. Haskell mode integrates with Haddock-generated HTML documentation,
  1707. providing features such as navigating to the Haddock entry for the
  1708. identifier under the cursor (|_?|), completion for the identifier under
  1709. the cursor (|i_CTRL-X_CTRL-U|), and adding import statements (|_i| |_im|
  1710. |_iq| |_iqm|) or module qualifier (|_.|) for the identifier under the
  1711. cursor.
  1712. These commands operate on an internal Haddock index built from the
  1713. platform's installed Haddock documentation for GHC's libraries. Since
  1714. populating this index takes several seconds, it should be stored as a
  1715. file called 'haddock_index.vim' in the directory specified by
  1716. |g:haddock_indexfiledir|.
  1717. Some commands present a different interface (popup menu or command-line
  1718. completion) according to whether the current Vim instance is graphical or
  1719. console-based (actually: whether or not the GUI is running). Such
  1720. differences are marked below with the annotations (GUI) and (CLI),
  1721. respectively.
  1722. |:DocSettings| shows the settings for this plugin. If you are happy with
  1723. them, you can call |:ExportDocIndex| to populate and write out the
  1724. documentation index (should be called once for every new version of GHC).
  1725. *:DocSettings*
  1726. :DocSettings Show current Haddock-files-related plugin settings.
  1727. *haskellmode-indexing*
  1728. 4.1 Indexing ~
  1729. *:DocIndex*
  1730. :DocIndex Populate the Haddock index from the GHC library
  1731. documentation.
  1732. *:ExportDocIndex*
  1733. :ExportDocIndex Cache the current Haddock index to a file (populate
  1734. index first, if empty).
  1735. *haskellmode-lookup*
  1736. 4.2 Lookup ~
  1737. *_?*
  1738. _? Open the Haddock entry (in |haddock_browser|) for an
  1739. identifier under the cursor, selecting full
  1740. qualifications from a popup menu (GUI) or via
  1741. command-line completion (CLI), if the identifier is
  1742. not qualified.
  1743. *_?1*
  1744. _?1 Search Hoogle (using |haddock_browser|) for an
  1745. identifier under the cursor.
  1746. *_?2*
  1747. _?2 Search Hayoo! (using |haddock_browser|) for an
  1748. identifier under the cursor.
  1749. *:IDoc*
  1750. :IDoc {identifier} Open the Haddock entry for the unqualified
  1751. {identifier} in |haddock_browser|, suggesting possible
  1752. full qualifications.
  1753. *:MDoc*
  1754. :MDoc {module} Open the Haddock entry for {module} in
  1755. |haddock_browser| (with command-line completion for
  1756. the fully qualified module name).
  1757. *:FlagReference*
  1758. :FlagReference {s} Browse Users Guide Flag Reference for section {s}
  1759. (with command-line completion for section headers).
  1760. *haskellmode-editing*
  1761. 4.3 Editing ~
  1762. *_.*
  1763. _. Fully qualify the unqualified name under the cursor
  1764. selecting full qualifications from a popup menu (GUI)
  1765. or via command-line completion (CLI).
  1766. *_iq* *_i*
  1767. _i _iq Add 'import [qualified] <module>(<identifier>)'
  1768. statement for the identifier under the cursor,
  1769. selecting fully qualified modules from a popup menu
  1770. (GUI) or via command-line completion (CLI), if the
  1771. identifier is not qualified. This currently adds one
  1772. import statement per call instead of merging into
  1773. existing import statements.
  1774. *_iqm* *_im*
  1775. _im Add 'import [qualified] <module>' statement for the
  1776. identifier under the cursor, selecting fully qualified
  1777. modules from a popup menu (GUI) or via command-line
  1778. completion (CLI), if the identifier is not qualified.
  1779. This currently adds one import statement per call
  1780. instead of merging into existing import statements.
  1781. *_ie*
  1782. _ie On an 'import <module>' line, in a correctly loadable
  1783. module, temporarily comment out import and use :make
  1784. 'not in scope' errors to explicitly list imported
  1785. identifiers.
  1786. *haskellmode-XU* *haskellmode-user-completion*
  1787. CTRL-X CTRL-U User-defined insert mode name completion based on all
  1788. names known to the Haddock index, including package
  1789. names. Completions are presented in a popup menu which
  1790. also displays the fully qualified module from which
  1791. each entry may be imported.
  1792. CamelCode shortcuts are supported, meaning that
  1793. lower-case letters can be elided, using only
  1794. upper-case letters and module qualifier separators (.)
  1795. for disambiguation:
  1796. pSL -> putStrLn
  1797. C.E.t -> Control.Exception.t
  1798. C.M.MP -> Control.Monad.MonadPlus
  1799. To reduce unwanted matches, the first letter of such
  1800. shortcuts and the first letter after each '.' have to
  1801. match directly.
  1802. ==============================================================================
  1803. *haskellmode-hpaste* *hpaste*
  1804. 5. Hpaste Integration ~
  1805. This experimental feature allows browsing and posting to
  1806. http://hpaste.org, a Web-based pastebin tailored for Haskell code.
  1807. *:HpasteIndex*
  1808. :HpasteIndex Read the most recent entries from hpaste.org. Show an
  1809. index of the entries in a new buffer, where ',r' will
  1810. open the current highlighted entry [and ',p' will
  1811. annotate it with the current buffer].
  1812. *:HpastePostNew*
  1813. :HpastePostNew Submit current buffer as a new hpaste entry.
  1814. [This, and ',p' above, are temporarily disabled,
  1815. needs update to new hpaste.org layout]
  1816. ==============================================================================
  1817. *haskellmode-resources*
  1818. 6. Additional Resources ~
  1819. An quick screencast tour through of these plugins is available at:
  1820. http://projects.haskell.org/haskellmode-vim/screencasts.html
  1821. Other Haskell-related Vim plugins can be found here:
  1822. http://www.haskell.org/haskellwiki/Libraries_and_tools/Program_development#Vim
  1823. Make sure to read about Vim's other program-editing features in its online
  1824. |user-manual|. Also have a look at Vim tips and plugins at www.vim.org -
  1825. two other plugins I tend to use when editing Haskell are AlignPlugin.vim
  1826. (to line up regexps for definitions, keywords, comments, etc. in
  1827. consecutive lines) and surround.vim (to surround text with quotes,
  1828. brackets, parentheses, comments, etc.).
  1829. ==============================================================================
  1830. vim:tw=78:ts=8:ft=help: