diff --git a/editors/vim/README.md b/editors/vim/README.md index 9c0c5da..69e831e 100644 --- a/editors/vim/README.md +++ b/editors/vim/README.md @@ -1 +1,18 @@ -Nothing here yet. If you know vim, consider writing a module and creating a pull request. +A plugin for using dscanner with vim. + +Tested on Linux and Windows(see comment for windows) + +Installation and Configuration +============================== +Put the autoload and ftplugin folders in your vim runtime path. + +Compile dscanner and put it in your path, or set the global variable g:dscanner\_path to where you put dscanner. + +If you need to use an include path, use the global variable g:dscanner\_includePath as a list of those paths. + +Using on Windows +================ +Under Linux, Dscanner reads /etc/dmd.conf to get the default include paths. The equivalent file in Windows - 'sc.ini' - does not have a fixed location, so you need to configure the import paths manually. You need the \src\phobos and \src\druntime\import folders from where you installed dmd. For example, +``` +let g:dscanner_includePath=['C:\Program Files\dmd2\src\phobos','C:\Program Files\dmd2\src\druntime\import'] +``` diff --git a/editors/vim/autoload/dcomplete.vim b/editors/vim/autoload/dcomplete.vim new file mode 100644 index 0000000..7dfa70c --- /dev/null +++ b/editors/vim/autoload/dcomplete.vim @@ -0,0 +1,113 @@ +"The completion function +function! dcomplete#Complete(findstart,base) + if a:findstart + let prePos=searchpos('\W',"bn") + let preChar=getline(prePos[0])[prePos[1]-1] + if '.'==preChar + "Save the data for use in the dscanner call. + let b:dscanner_lastPos=prePos + let b:dscanner_type='.' + return prePos[1] + endif + "If we can't find a dot, we look for a paren. + let prePos=searchpos("(","bn",line('.')) + if prePos[0] + if getline('.')[prePos[1]:col('.')-2]=~'^\s*\w*$' + let b:dscanner_lastPos=prePos + let b:dscanner_type='(' + return prePos[1] + endif + endif + "If we can't find either, dscanner can't help us. + return -2 + else + "Run dscanner according to the preChar. + if b:dscanner_type=='.' + let scanResult=s:runDScanner('dotComplete') + else + let scanResult=s:runDScanner('parenComplete') + endif + "Split the result text to lines. + let resultLines=split(scanResult,"\n") + "If the last line is --------------, we have an error. + if resultLines[-1]=~'-\+' + return resultLines[-1] + end + + "Find the begining of the results. + while len(resultLines) + "Identify the type of result received + let b:dscanner_resultType=resultLines[0] + "Parse the result accoring to their type + if b:dscanner_resultType=='dotComplete' + return s:parsePairs(a:base,resultLines,'','') + elseif b:dscanner_resultType=='completions' + return s:parsePairs(a:base,resultLines,'',')') + elseif b:dscanner_resultType=='calltips' + return s:parseCalltips(a:base,resultLines) + endif + let resultLines=resultLines[1:] + endwhile + endif +endfunction +"Run dscanner +function! s:runDScanner(scanCommand) + if exists('g:dscanner_path') + let l:dscannerCommand=g:dscanner_path + else + let l:dscannerCommand='dscanner' + endif + + if exists('g:dscanner_includePath') + for l:includePath in g:dscanner_includePath + let l:dscannerCommand=l:dscannerCommand.' '.shellescape('-I'.l:includePath) + endfor + endif + + + let l:tmpFileName=tempname() + "Save the temp file in unix format for better reading of byte position. + let l:oldFileFormat=&fileformat + set fileformat=unix + let l:bytePosition=line2byte('.')+col('.')-2 + exec "write ".l:tmpFileName + let &fileformat=l:oldFileFormat + let scanResult=system(l:dscannerCommand.' --'.a:scanCommand.' '.l:bytePosition.' <'.shellescape(l:tmpFileName)) + call delete(l:tmpFileName) + return scanResult +endfunction + +"Parse simple pair results +function! s:parsePairs(base,resultLines,addBefore,addAfter) + let result=[] + for resultLine in a:resultLines[1:] + if len(resultLine) + let lineParts=split(resultLine) + if lineParts[0]=~'^'.a:base && 2==len(lineParts) && 1==len(lineParts[1]) + call add(result,{'word':a:addBefore.lineParts[0].a:addAfter,'kind':lineParts[1]}) + endif + end + endfor + return result +endfunction + +"Parse function calltips results +function! s:parseCalltips(base,resultLines) + let result=[a:base] + for resultLine in a:resultLines[1:] + if 0<=match(resultLine,".*(.*)") + let funcArgs=[] + for funcArg in split(resultLine[match(resultLine,'(')+1:-2],',\\n\\t') + let argParts=split(funcArg) + if 1