Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Imported from static distribution of full Haskell mode.
- Loading branch information
0 parents
commit ecb311d
Showing
7 changed files
with
2,222 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
" | ||
" utility functions for haskellmode plugins | ||
" | ||
" (Claus Reinke; last modified: 22/06/2010) | ||
" | ||
" 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*\%({-#\s*SOURCE\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 = as=='' ? module : as | ||
let hidings = split(hiding[1:-2],',') | ||
let explicits = split(explicit[1:-2],',') | ||
let empty = {'lines':[],'hiding':hidings,'explicit':[],'modules':[]} | ||
let entry = has_key(imports[1],what) ? imports[1][what] : deepcopy(empty) | ||
let imports[1][what] = haskellmode#MergeImport(deepcopy(entry),i,hidings,explicits,module) | ||
if !(qualified=='qualified') | ||
let imports[0][what] = haskellmode#MergeImport(deepcopy(entry),i,hidings,explicits,module) | ||
endif | ||
else | ||
echoerr "haskellmode#GatherImports doesn't understand: ".import | ||
endif | ||
endif | ||
let i+=1 | ||
endwhile | ||
if !has_key(imports[1],'Prelude') | ||
let imports[0]['Prelude'] = {'lines':[],'hiding':[],'explicit':[],'modules':[]} | ||
let imports[1]['Prelude'] = {'lines':[],'hiding':[],'explicit':[],'modules':[]} | ||
endif | ||
return imports | ||
endfunction | ||
|
||
function! haskellmode#ListElem(list,elem) | ||
for e in a:list | if e==a:elem | return 1 | endif | endfor | ||
return 0 | ||
endfunction | ||
|
||
function! haskellmode#ListIntersect(list1,list2) | ||
let l = [] | ||
for e in a:list1 | if index(a:list2,e)!=-1 | let l += [e] | endif | endfor | ||
return l | ||
endfunction | ||
|
||
function! haskellmode#ListUnion(list1,list2) | ||
let l = [] | ||
for e in a:list2 | if index(a:list1,e)==-1 | let l += [e] | endif | endfor | ||
return a:list1 + l | ||
endfunction | ||
|
||
function! haskellmode#ListWithout(list1,list2) | ||
let l = [] | ||
for e in a:list1 | if index(a:list2,e)==-1 | let l += [e] | endif | endfor | ||
return l | ||
endfunction | ||
|
||
function! haskellmode#MergeImport(entry,line,hiding,explicit,module) | ||
let lines = a:entry['lines'] + [ a:line ] | ||
let hiding = a:explicit==[] ? haskellmode#ListIntersect(a:entry['hiding'], a:hiding) | ||
\ : haskellmode#ListWithout(a:entry['hiding'],a:explicit) | ||
let explicit = haskellmode#ListUnion(a:entry['explicit'], a:explicit) | ||
let modules = haskellmode#ListUnion(a:entry['modules'], [ a:module ]) | ||
return {'lines':lines,'hiding':hiding,'explicit':explicit,'modules':modules} | ||
endfunction | ||
|
||
" collect lines belonging to a single import statement; | ||
" return number of last line and collected import statement | ||
" (assume opening parenthesis, if any, is on the first line) | ||
function! haskellmode#GatherImport(lineno) | ||
let lineno = a:lineno | ||
let import = getline(lineno) | ||
if !(import=~'^import\s') | return [] | endif | ||
let open = strlen(substitute(import,'[^(]','','g')) | ||
let close = strlen(substitute(import,'[^)]','','g')) | ||
while open!=close | ||
let lineno += 1 | ||
let linecont = getline(lineno) | ||
let open += strlen(substitute(linecont,'[^(]','','g')) | ||
let close += strlen(substitute(linecont,'[^)]','','g')) | ||
let import .= linecont | ||
endwhile | ||
return [lineno,import] | ||
endfunction | ||
|
||
function! haskellmode#UrlEncode(string) | ||
let pat = '\([^[:alnum:]]\)' | ||
let code = '\=printf("%%%02X",char2nr(submatch(1)))' | ||
let url = substitute(a:string,pat,code,'g') | ||
return url | ||
endfunction | ||
|
||
" TODO: we could have buffer-local settings, at the expense of | ||
" reconfiguring for every new buffer.. do we want to? | ||
function! haskellmode#GHC() | ||
if (!exists("g:ghc") || !executable(g:ghc)) | ||
if !executable('ghc') | ||
echoerr s:scriptname.": can't find ghc. please set g:ghc, or extend $PATH" | ||
return 0 | ||
else | ||
let g:ghc = 'ghc' | ||
endif | ||
endif | ||
return 1 | ||
endfunction | ||
|
||
function! haskellmode#GHC_Version() | ||
if !exists("g:ghc_version") | ||
let g:ghc_version = substitute(system(g:ghc . ' --numeric-version'),'\n','','') | ||
endif | ||
return g:ghc_version | ||
endfunction | ||
|
||
function! haskellmode#GHC_VersionGE(target) | ||
let current = split(haskellmode#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 | ||
|
Oops, something went wrong.