diff options
Diffstat (limited to '.vim/autoload')
| -rw-r--r-- | .vim/autoload/omni/common/debug.vim | 32 | ||||
| -rw-r--r-- | .vim/autoload/omni/common/utils.vim | 67 | ||||
| -rw-r--r-- | .vim/autoload/omni/cpp/complete.vim | 569 | ||||
| -rw-r--r-- | .vim/autoload/omni/cpp/includes.vim | 126 | ||||
| -rw-r--r-- | .vim/autoload/omni/cpp/items.vim | 660 | ||||
| -rw-r--r-- | .vim/autoload/omni/cpp/maycomplete.vim | 82 | ||||
| -rw-r--r-- | .vim/autoload/omni/cpp/namespaces.vim | 838 | ||||
| -rw-r--r-- | .vim/autoload/omni/cpp/settings.vim | 96 | ||||
| -rw-r--r-- | .vim/autoload/omni/cpp/tokenizer.vim | 93 | ||||
| -rw-r--r-- | .vim/autoload/omni/cpp/utils.vim | 587 | 
10 files changed, 3150 insertions, 0 deletions
| diff --git a/.vim/autoload/omni/common/debug.vim b/.vim/autoload/omni/common/debug.vim new file mode 100644 index 0000000..eded649 --- /dev/null +++ b/.vim/autoload/omni/common/debug.vim @@ -0,0 +1,32 @@ +" Description: Omni completion debug functions +" Maintainer:  Vissale NEANG +" Last Change: 26 sept. 2007 + +let s:CACHE_DEBUG_TRACE = [] + +" Start debug, clear the debug file +function! omni#common#debug#Start() +    let s:CACHE_DEBUG_TRACE = [] +    call extend(s:CACHE_DEBUG_TRACE, ['============ Debug Start ============']) +    call writefile(s:CACHE_DEBUG_TRACE, "Omni.dbg") +endfunc + +" End debug, write to debug file +function! omni#common#debug#End() +    call extend(s:CACHE_DEBUG_TRACE, ["============= Debug End ============="]) +    call extend(s:CACHE_DEBUG_TRACE, [""]) +    call writefile(s:CACHE_DEBUG_TRACE, "Omni.dbg") +endfunc + +" Debug trace function +function! omni#common#debug#Trace(szFuncName, ...) +    let szTrace = a:szFuncName +    let paramNum = a:0 +    if paramNum>0 +        let szTrace .= ':' +    endif +    for i in range(paramNum) +        let szTrace = szTrace .' ('. string(eval('a:'.string(i+1))).')' +    endfor +    call extend(s:CACHE_DEBUG_TRACE, [szTrace]) +endfunc diff --git a/.vim/autoload/omni/common/utils.vim b/.vim/autoload/omni/common/utils.vim new file mode 100644 index 0000000..c880ad2 --- /dev/null +++ b/.vim/autoload/omni/common/utils.vim @@ -0,0 +1,67 @@ +" Description: Omni completion utils +" Maintainer:  Vissale NEANG +" Last Change: 26 sept. 2007 + +" For sort numbers in list +function! omni#common#utils#CompareNumber(i1, i2) +    let num1 = eval(a:i1) +    let num2 = eval(a:i2) +    return num1 == num2 ? 0 : num1 > num2 ? 1 : -1 +endfunc + +" TagList function calling the vim taglist() with try catch +" The only throwed exception is 'TagList:UserInterrupt' +" We also force the noignorecase option to avoid linear search when calling +" taglist() +function! omni#common#utils#TagList(szTagQuery) +    let result = [] +    let bUserIgnoreCase = &ignorecase +    " Forcing noignorecase search => binary search can be used in taglist() +    " if tags in the tag file are sorted +    if bUserIgnoreCase +        set noignorecase +    endif +    try +        let result = taglist(a:szTagQuery) +    catch /^Vim:Interrupt$/ +        " Restoring user's setting +        if bUserIgnoreCase +            set ignorecase +        endif +        throw 'TagList:UserInterrupt' +    catch +        "Note: it seems that ctags can generate corrupted files, in this case +        "taglist() will fail to read the tagfile and an exception from +        "has_add() is thrown +    endtry + +    " Restoring user's setting +    if bUserIgnoreCase +        set ignorecase +    endif +    return result +endfunc + +" Same as TagList but don't throw exception +function! omni#common#utils#TagListNoThrow(szTagQuery) +    let result = [] +    try +        let result = omni#common#utils#TagList(a:szTagQuery) +    catch +    endtry +    return result +endfunc + +" Get the word under the cursor +function! omni#common#utils#GetWordUnderCursor() +    let szLine = getline('.') +    let startPos = getpos('.')[2]-1 +    let startPos = (startPos < 0)? 0 : startPos +    if szLine[startPos] =~ '\w' +        let startPos = searchpos('\<\w\+', 'cbn', line('.'))[1] - 1 +    endif + +    let startPos = (startPos < 0)? 0 : startPos +    let szResult = matchstr(szLine, '\w\+', startPos) +    return szResult +endfunc diff --git a/.vim/autoload/omni/cpp/complete.vim b/.vim/autoload/omni/cpp/complete.vim new file mode 100644 index 0000000..a7e4edc --- /dev/null +++ b/.vim/autoload/omni/cpp/complete.vim @@ -0,0 +1,569 @@ +" Description: Omni completion script for cpp files +" Maintainer:  Vissale NEANG +" Last Change: 27 sept. 2007 + +if v:version < 700 +    echohl WarningMsg +    echomsg "omni#cpp#complete.vim: Please install vim 7.0 or higher for omni-completion" +    echohl None +    finish +endif + +call omni#cpp#settings#Init() +let s:OmniCpp_ShowScopeInAbbr = g:OmniCpp_ShowScopeInAbbr +let s:OmniCpp_ShowPrototypeInAbbr = g:OmniCpp_ShowPrototypeInAbbr +let s:OmniCpp_ShowAccess = g:OmniCpp_ShowAccess +let s:szCurrentWorkingDir = getcwd() + +" Cache data +let s:CACHE_TAG_POPUP_ITEMS = {} +let s:CACHE_TAG_FILES = {} +let s:CACHE_TAG_ENV = '' +let s:CACHE_OVERLOADED_FUNCTIONS = {} + +" Has preview window? +let s:hasPreviewWindow = match(&completeopt, 'preview')>=0 +let s:hasPreviewWindowOld = s:hasPreviewWindow + +" Popup item list +let s:popupItemResultList = [] + +" May complete indicator +let s:bMayComplete = 0 + +" Init mappings +function! omni#cpp#complete#Init() +    call omni#cpp#settings#Init() +    set omnifunc=omni#cpp#complete#Main +    inoremap <expr> <C-X><C-O> omni#cpp#maycomplete#Complete() +    inoremap <expr> . omni#cpp#maycomplete#Dot() +    inoremap <expr> > omni#cpp#maycomplete#Arrow() +    inoremap <expr> : omni#cpp#maycomplete#Scope() +endfunc + +" Find the start position of the completion +function! s:FindStartPositionOfCompletion() +    " Locate the start of the item, including ".", "->" and "[...]". +    let line = getline('.') +    let start = col('.') - 1 + +    let lastword = -1 +    while start > 0 +        if line[start - 1] =~ '\w' +            let start -= 1 +        elseif line[start - 1] =~ '\.' +            " Searching for dot '.' +            if lastword == -1 +                let lastword = start +            endif +            let start -= 1 +        elseif start > 1 && line[start - 2] == '-' && line[start - 1] == '>' +            " Searching for '->' +            if lastword == -1 +                let lastword = start +            endif +            let start -= 2 +        elseif start > 1 && line[start - 2] == ':' && line[start - 1] == ':' +            " Searching for '::' for namespaces and class +            if lastword == -1 +                let lastword = start +            endif +            let start -= 2 +        elseif line[start - 1] == ']' +            " Skip over [...]. +            let n = 0 +            let start -= 1 +            while start > 0 +                let start -= 1 +                if line[start] == '[' +                    if n == 0 +                        break +                    endif +                    let n -= 1 +                elseif line[start] == ']'  " nested [] +                    let n += 1 +                endif +            endwhile +        else +            break +        endif +    endwhile +    if lastword==-1 +        " For completion on the current scope +        let lastword = start +    endif +    return lastword +endfunc + +" Returns if szKey1.szKey2 is in the cache +" @return +"   - 0 = key not found +"   - 1 = szKey1.szKey2 found +"   - 2 = szKey1.[part of szKey2] found +function! s:IsCached(cache, szKey1, szKey2) +    " Searching key in the result cache +    let szResultKey = a:szKey1 . a:szKey2 +    let result = [0, szResultKey] +    if a:szKey2 != '' +        let szKey = a:szKey2 +        while len(szKey)>0 +            if has_key(a:cache, a:szKey1 . szKey) +                let result[1] = a:szKey1 . szKey +                if szKey != a:szKey2 +                    let result[0] = 2 +                else +                    let result[0] = 1 +                endif +                break +            endif +            let szKey = szKey[:-2] +        endwhile +    else +        if has_key(a:cache, szResultKey) +            let result[0] = 1 +        endif +    endif +    return result +endfunc + +" Extend a tag item to a popup item +function! s:ExtendTagItemToPopupItem(tagItem, szTypeName) +    let tagItem = a:tagItem + +    " Add the access +    let szItemMenu = '' +    let accessChar = {'public': '+','protected': '#','private': '-'} +    if g:OmniCpp_ShowAccess +        if has_key(tagItem, 'access') && has_key(accessChar, tagItem.access) +            let szItemMenu = szItemMenu.accessChar[tagItem.access] +        else +            let szItemMenu = szItemMenu." " +        endif +    endif + +    " Formating optional menu string we extract the scope information +    let szName = substitute(tagItem.name, '.*::', '', 'g') +    let szItemWord = szName +    let szAbbr = szName + +    if !g:OmniCpp_ShowScopeInAbbr +        let szScopeOfTag = omni#cpp#utils#ExtractScope(tagItem) +        let szItemMenu = szItemMenu.' '.szScopeOfTag[2:] +        let szItemMenu = substitute(szItemMenu, '\s\+$', '', 'g') +    else +        let szAbbr = tagItem.name +    endif +    if g:OmniCpp_ShowAccess +        let szItemMenu = substitute(szItemMenu, '^\s\+$', '', 'g') +    else +        let szItemMenu = substitute(szItemMenu, '\(^\s\+\)\|\(\s\+$\)', '', 'g') +    endif + +    " Formating information for the preview window +    if index(['f', 'p'], tagItem.kind[0])>=0 +        let szItemWord .= '(' +        if g:OmniCpp_ShowPrototypeInAbbr && has_key(tagItem, 'signature') +            let szAbbr .= tagItem.signature +        else +            let szAbbr .= '(' +        endif +    endif +    let szItemInfo = '' +    if s:hasPreviewWindow +        let szItemInfo = omni#cpp#utils#GetPreviewWindowStringFromTagItem(tagItem) +    endif + +    " If a function is a ctor we add a new key in the tagItem +    if index(['f', 'p'], tagItem.kind[0])>=0 +        if match(szName, '^\~') < 0 && a:szTypeName =~ '\C\<'.szName.'$' +            " It's a ctor +            let tagItem['ctor'] = 1 +        elseif has_key(tagItem, 'access') && tagItem.access == 'friend' +            " Friend function +            let tagItem['friendfunc'] = 1 +        endif +    endif + +    " Extending the tag item to a popup item +    let tagItem['word'] = szItemWord +    let tagItem['abbr'] = szAbbr +    let tagItem['menu'] = szItemMenu +    let tagItem['info'] = szItemInfo +    let tagItem['dup'] = (s:hasPreviewWindow && index(['f', 'p', 'm'], tagItem.kind[0])>=0) +    return tagItem +endfunc + +" Get tag popup item list +function! s:TagPopupList(szTypeName, szBase) +    let result = [] + +    " Searching key in the result cache +    let cacheResult = s:IsCached(s:CACHE_TAG_POPUP_ITEMS, a:szTypeName, a:szBase) + +    " Building the tag query, we don't forget dtors when a:szBase=='' +    if a:szTypeName!='' +        " Scope search +        let szTagQuery = '^' . a:szTypeName . '::' . a:szBase . '\~\?\w\+$' +    else +        " Global search +        let szTagQuery = '^' . a:szBase . '\w\+$' +    endif + +    " If the result is already in the cache we return it +    if cacheResult[0] +        let result = s:CACHE_TAG_POPUP_ITEMS[ cacheResult[1] ] +        if cacheResult[0] == 2 +            let result = filter(copy(result), 'v:val.name =~ szTagQuery' ) +        endif +        return result +    endif + +    try +        " Getting tags +        let result = omni#common#utils#TagList(szTagQuery) + +        " We extend tag items to popup items +        call map(result, 's:ExtendTagItemToPopupItem(v:val, a:szTypeName)') + +        " We store the result in a cache +        if cacheResult[1] != '' +            let s:CACHE_TAG_POPUP_ITEMS[ cacheResult[1] ] = result +        endif +    catch /^TagList:UserInterrupt$/ +    endtry + +    return result +endfunc + +" Find complete matches for a completion on the global scope +function! s:SearchGlobalMembers(szBase) +    if a:szBase != '' +        let tagPopupList = s:TagPopupList('', a:szBase) +        let tagPopupList = filter(copy(tagPopupList), g:omni#cpp#utils#szFilterGlobalScope) +        call extend(s:popupItemResultList, tagPopupList) +    endif +endfunc + +" Search class, struct, union members +" @param resolvedTagItem: a resolved tag item +" @param szBase: string base +" @return list of tag items extended to popup items +function! s:SearchMembers(resolvedTagItem, szBase) +    let result = [] +    if a:resolvedTagItem == {} +        return result +    endif + +    " Get type info without the starting '::' +    let szTagName = omni#cpp#utils#ExtractTypeInfoFromTag(a:resolvedTagItem)[2:] + +    " Unnamed type case. A tag item representing an unnamed type is a variable  +    " ('v') a member ('m') or a typedef ('t') +    if index(['v', 't', 'm'], a:resolvedTagItem.kind[0])>=0 && has_key(a:resolvedTagItem, 'typeref') +        " We remove the 'struct:' or 'class:' etc... +        let szTagName = substitute(a:resolvedTagItem.typeref, '^\w\+:', '', 'g') +    endif + +    return copy(s:TagPopupList(szTagName, a:szBase)) +endfunc + +" Return if the tag env has changed +function! s:HasTagEnvChanged() +    if s:CACHE_TAG_ENV == &tags +        return 0 +    else +        let s:CACHE_TAG_ENV = &tags +        return 1 +    endif +endfunc + +" Return if a tag file has changed in tagfiles() +function! s:HasATagFileOrTagEnvChanged() +    if s:HasTagEnvChanged() +        let s:CACHE_TAG_FILES = {} +        return 1 +    endif + +    let result = 0 +    for tagFile in tagfiles() +        if tagFile == "" +            continue +        endif + +        if has_key(s:CACHE_TAG_FILES, tagFile) +            let currentFiletime = getftime(tagFile) +            if currentFiletime > s:CACHE_TAG_FILES[tagFile] +                " The file has changed, updating the cache +                let s:CACHE_TAG_FILES[tagFile] = currentFiletime +                let result = 1 +            endif +        else +            " We store the time of the file +            let s:CACHE_TAG_FILES[tagFile] = getftime(tagFile) +            let result = 1 +        endif +    endfor +    return result +endfunc +" Initialization +call s:HasATagFileOrTagEnvChanged() + +" Filter same function signatures of base classes +function! s:FilterOverloadedFunctions(tagPopupList) +    let result = [] +    for tagPopupItem in a:tagPopupList +        if has_key(tagPopupItem, 'kind') && index(['f', 'p'], tagPopupItem.kind[0])>=0 && has_key(tagPopupItem, 'signature') +            if !has_key(s:CACHE_OVERLOADED_FUNCTIONS, tagPopupItem.word . tagPopupItem.signature) +                let s:CACHE_OVERLOADED_FUNCTIONS[tagPopupItem.word . tagPopupItem.signature] = 1 +                call extend(result, [tagPopupItem]) +            endif +        else +            call extend(result, [tagPopupItem]) +        endif +    endfor +    return result +endfunc + +" Access filter +function! s:GetAccessFilter(szFilter, szAccessFilter) +    let szFilter = a:szFilter +    if g:OmniCpp_DisplayMode == 0 +        if a:szAccessFilter == 'public' +            " We only get public members +            let szFilter .= "&& v:val.access == 'public'" +        elseif a:szAccessFilter == 'protected' +            " We get public and protected members +            let szFilter .= "&& v:val.access != 'private'" +        endif +    endif +    return szFilter +endfunc + +" Filter class members in the popup menu after a completion with -> or . +function! s:FilterClassMembers(tagPopupList, szAccessFilter) +    let szFilter = "(!has_key(v:val, 'friendfunc') && !has_key(v:val, 'ctor') && has_key(v:val, 'kind') && index(['m', 'p', 'f'], v:val.kind[0])>=0 && has_key(v:val, 'access'))" +    call filter(a:tagPopupList, s:GetAccessFilter(szFilter, a:szAccessFilter)) +    call extend(s:popupItemResultList, s:FilterOverloadedFunctions(a:tagPopupList)) +endfunc + +" Filter class scope members in the popup menu after a completion with :: +" We only display attribute and functions members that +" have an access information. We also display nested +" class, struct, union, and enums, typedefs +function! s:FilterClassScopeMembers(tagPopupList, szAccessFilter) +    let szFilter = "!has_key(v:val, 'friendfunc') && has_key(v:val, 'kind') && (index(['m', 'p', 'f'], v:val.kind[0])>=0 && has_key(v:val, 'access'))" +    let szFilter = s:GetAccessFilter(szFilter, a:szAccessFilter) +    let szFilter .= "|| index(['c','e','g','s','t','u'], v:val.kind[0])>=0" +    call filter(a:tagPopupList, szFilter) +    call extend(s:popupItemResultList, s:FilterOverloadedFunctions(a:tagPopupList)) +endfunc + +" Filter static class members in the popup menu +function! s:FilterStaticClassMembers(tagPopupList, szAccessFilter) +    let szFilter = "!has_key(v:val, 'friendfunc') && has_key(v:val, 'kind') && (index(['m', 'p', 'f'], v:val.kind[0])>=0 && has_key(v:val, 'access') && match(v:val.cmd, '\\Cstatic')!=-1)" +    let szFilter = s:GetAccessFilter(szFilter, a:szAccessFilter) +    let szFilter = szFilter . "|| index(['c','e','g','n','s','t','u','v'], v:val.kind[0])>=0" +    call filter(a:tagPopupList, szFilter) +    call extend(s:popupItemResultList, s:FilterOverloadedFunctions(a:tagPopupList)) +endfunc + +" Filter scope members in the popup menu +function! s:FilterNamespaceScopeMembers(tagPopupList) +    call extend(s:popupItemResultList, a:tagPopupList) +endfunc + +" Init data at the start of completion +function! s:InitComplete() +    " Reset the popup item list +    let s:popupItemResultList = [] +    let s:CACHE_OVERLOADED_FUNCTIONS = {} + +    " Reset includes cache when the current working directory has changed +    let szCurrentWorkingDir = getcwd() +    if s:szCurrentWorkingDir != szCurrentWorkingDir +        let s:szCurrentWorkingDir = szCurrentWorkingDir +        let g:omni#cpp#includes#CACHE_INCLUDES = {} +        let g:omni#cpp#includes#CACHE_FILE_TIME = {} +    endif + +    " Has preview window ? +    let s:hasPreviewWindow = match(&completeopt, 'preview')>=0 + +    let bResetCache = 0 + +    " Reset tag env or tag files dependent caches +    if s:HasATagFileOrTagEnvChanged() +        let bResetCache = 1 +    endif + +    if  (s:OmniCpp_ShowScopeInAbbr !=  g:OmniCpp_ShowScopeInAbbr) +        \|| (s:OmniCpp_ShowPrototypeInAbbr != g:OmniCpp_ShowPrototypeInAbbr) +        \|| (s:OmniCpp_ShowAccess != g:OmniCpp_ShowAccess) + +        let s:OmniCpp_ShowScopeInAbbr = g:OmniCpp_ShowScopeInAbbr +        let s:OmniCpp_ShowPrototypeInAbbr = g:OmniCpp_ShowPrototypeInAbbr +        let s:OmniCpp_ShowAccess = g:OmniCpp_ShowAccess +        let bResetCache = 1 +    endif + +    if s:hasPreviewWindow != s:hasPreviewWindowOld +        let s:hasPreviewWindowOld = s:hasPreviewWindow +        let bResetCache = 1 +    endif + +    if bResetCache +        let g:omni#cpp#namespaces#CacheResolve = {} +        let s:CACHE_TAG_POPUP_ITEMS = {} +        let g:omni#cpp#utils#CACHE_TAG_INHERITS = {} +        call garbagecollect() +    endif + +    " Check for updates +    for szIncludeName in keys(g:omni#cpp#includes#CACHE_INCLUDES) +        let fTime = getftime(szIncludeName) +        let bNeedUpdate = 0 +        if has_key(g:omni#cpp#includes#CACHE_FILE_TIME, szIncludeName) +            if fTime != g:omni#cpp#includes#CACHE_FILE_TIME[szIncludeName] +                let bNeedUpdate = 1 +            endif +        else +            let g:omni#cpp#includes#CACHE_FILE_TIME[szIncludeName] = fTime +            let bNeedUpdate = 1 +        endif +         +        if bNeedUpdate +            " We have to update include list and namespace map of this file +            call omni#cpp#includes#GetList(szIncludeName, 1) +            call omni#cpp#namespaces#GetMapFromBuffer(szIncludeName, 1) +        endif +    endfor + +    let s:bDoNotComplete = 0 +endfunc + + +" This function is used for the 'omnifunc' option. +function! omni#cpp#complete#Main(findstart, base) +    if a:findstart +        "call omni#common#debug#Start() + +        call s:InitComplete() + +        " Note: if s:bMayComplete==1 g:omni#cpp#items#data is build by MayComplete functions +        if !s:bMayComplete +            " If the cursor is in a comment we go out +            if omni#cpp#utils#IsCursorInCommentOrString() +                " Returning -1 is not enough we have to set a variable to let +                " the second call of omni#cpp#complete knows that the +                " cursor was in a comment +                " Why is there a second call when the first call returns -1 ? +                let s:bDoNotComplete = 1 +                return -1 +            endif + +            " We get items here (whend a:findstart==1) because GetItemsToComplete() +            " depends on the cursor position. +            " When a:findstart==0 the cursor position is modified +            let g:omni#cpp#items#data = omni#cpp#items#Get(omni#cpp#utils#TokenizeCurrentInstruction()) +        endif + +        " Get contexts stack +        let s:contextStack = omni#cpp#namespaces#GetContexts() + +        " Reinit of may complete indicator +        let s:bMayComplete = 0 +        return s:FindStartPositionOfCompletion() +    endif + +    " If the cursor is in a comment we return an empty result +    if s:bDoNotComplete +        let s:bDoNotComplete = 0 +        return [] +    endif + +    if len(g:omni#cpp#items#data)==0 +        " A) CURRENT_SCOPE_COMPLETION_MODE + +        " 1) Displaying data of each context +        let szAccessFilter = 'all' +        for szCurrentContext in s:contextStack +            if szCurrentContext == '::' +                continue +            endif + +            let resolvedTagItem = omni#cpp#utils#GetResolvedTagItem(s:contextStack, omni#cpp#utils#CreateTypeInfo(szCurrentContext)) +            if resolvedTagItem != {} +                " We don't search base classes because bases classes are +                " already in the context stack +                let tagPopupList = s:SearchMembers(resolvedTagItem, a:base) +                if index(['c','s'], resolvedTagItem.kind[0])>=0 +                    " It's a class or struct +                    call s:FilterClassScopeMembers(tagPopupList, szAccessFilter) +                    let szAccessFilter = 'protected' +                else +                    " It's a namespace or union, we display all members +                    call s:FilterNamespaceScopeMembers(tagPopupList) +                endif +            endif +        endfor + +        " 2) Displaying global scope members +        if g:OmniCpp_GlobalScopeSearch +            call s:SearchGlobalMembers(a:base) +        endif +    else +        let typeInfo = omni#cpp#items#ResolveItemsTypeInfo(s:contextStack, g:omni#cpp#items#data) + +        if typeInfo != {} +            if g:omni#cpp#items#data[-1].kind == 'itemScope' +                " B) SCOPE_COMPLETION_MODE +                if omni#cpp#utils#GetTypeInfoString(typeInfo)=='' +                    call s:SearchGlobalMembers(a:base) +                else +                    for resolvedTagItem in omni#cpp#utils#GetResolvedTags(s:contextStack, typeInfo) +                        let tagPopupList = s:SearchMembers(resolvedTagItem, a:base) +                        if index(['c','s'], resolvedTagItem.kind[0])>=0 +                            let szTypeInfo = omni#cpp#utils#ExtractTypeInfoFromTag(resolvedTagItem) +                            if g:OmniCpp_DisplayMode==0 +                                " We want to complete a class or struct +                                " If this class is a base class so we display all class members +                                if index(s:contextStack, szTypeInfo)<0 +                                    let szAccessFilter = 'public' +                                    call s:FilterStaticClassMembers(tagPopupList, szAccessFilter) +                                else +                                    let szAccessFilter = (s:contextStack[0] == szTypeInfo)? 'all' : 'protected' +                                    call s:FilterClassScopeMembers(tagPopupList, szAccessFilter) +                                endif +                            else +                                if index(s:contextStack, szTypeInfo)<0 +                                    let szAccessFilter = 'public' +                                else +                                    let szAccessFilter = (s:contextStack[0] == szTypeInfo)? 'all' : 'protected' +                                endif +                                call s:FilterClassScopeMembers(tagPopupList, szAccessFilter) +                            endif +                        else +                            " We want to complete a namespace +                            call s:FilterNamespaceScopeMembers(tagPopupList) +                        endif +                    endfor +                endif +            else +                " C) CLASS_MEMBERS_COMPLETION_MODE +                for resolvedTagItem in omni#cpp#utils#GetResolvedTags(s:contextStack, typeInfo) +                    let szTypeInfo = omni#cpp#utils#ExtractTypeInfoFromTag(resolvedTagItem) +                    if index(s:contextStack, szTypeInfo)<0 +                        let szAccessFilter = 'public' +                    else +                        let szAccessFilter = (s:contextStack[0] == szTypeInfo)? 'all' : 'protected' +                    endif +                    call s:FilterClassMembers(s:SearchMembers(resolvedTagItem, a:base), szAccessFilter) +                endfor +            endif +        endif +    endif + +    "call omni#common#debug#End() + +    return s:popupItemResultList +endfunc diff --git a/.vim/autoload/omni/cpp/includes.vim b/.vim/autoload/omni/cpp/includes.vim new file mode 100644 index 0000000..10a89bc --- /dev/null +++ b/.vim/autoload/omni/cpp/includes.vim @@ -0,0 +1,126 @@ +" Description: Omni completion script for cpp files +" Maintainer:  Vissale NEANG +" Last Change: 26 sept. 2007 + +let g:omni#cpp#includes#CACHE_INCLUDES = {} +let g:omni#cpp#includes#CACHE_FILE_TIME = {} + +let s:rePreprocIncludePart = '\C#\s*include\s*' +let s:reIncludeFilePart = '\(<\|"\)\(\f\|\s\)\+\(>\|"\)' +let s:rePreprocIncludeFile = s:rePreprocIncludePart . s:reIncludeFilePart + +" Get the include list of a file +function! omni#cpp#includes#GetList(...) +    if a:0 > 0 +        return s:GetIncludeListFromFile(a:1, (a:0 > 1)? a:2 : 0 ) +    else +        return s:GetIncludeListFromCurrentBuffer() +    endif +endfunc + +" Get the include list from the current buffer +function! s:GetIncludeListFromCurrentBuffer() +    let listIncludes = [] +    let originalPos = getpos('.') + +    call setpos('.', [0, 1, 1, 0]) +    let curPos = [1,1] +    let alreadyInclude = {} +    while curPos != [0,0] +        let curPos = searchpos('\C\(^'.s:rePreprocIncludeFile.'\)', 'W') +        if curPos != [0,0] +            let szLine = getline('.') +            let startPos = curPos[1] +            let endPos = matchend(szLine, s:reIncludeFilePart, startPos-1) +            if endPos!=-1 +                let szInclusion = szLine[startPos-1:endPos-1] +                let szIncludeFile = substitute(szInclusion, '\('.s:rePreprocIncludePart.'\)\|[<>""]', '', 'g') +                let szResolvedInclude = omni#cpp#utils#ResolveFilePath(szIncludeFile) + +                " Protection over self inclusion +                if szResolvedInclude != '' && szResolvedInclude != omni#cpp#utils#ResolveFilePath(getreg('%')) +                    let includePos = curPos +                    if !has_key(alreadyInclude, szResolvedInclude) +                        call extend(listIncludes, [{'pos' : includePos, 'include' : szResolvedInclude}]) +                        let alreadyInclude[szResolvedInclude] = 1 +                    endif +                endif +            endif +        endif +    endwhile + +    call setpos('.', originalPos) +    return listIncludes +endfunc + +" Get the include list from a file +function! s:GetIncludeListFromFile(szFilePath, bUpdate)  +    let listIncludes = [] +    if a:szFilePath == '' +        return listIncludes +    endif + +    if !a:bUpdate && has_key(g:omni#cpp#includes#CACHE_INCLUDES, a:szFilePath) +        return copy(g:omni#cpp#includes#CACHE_INCLUDES[a:szFilePath]) +    endif + +    let g:omni#cpp#includes#CACHE_FILE_TIME[a:szFilePath] = getftime(a:szFilePath) + +    let szFixedPath = escape(a:szFilePath, g:omni#cpp#utils#szEscapedCharacters) +    execute 'silent! lvimgrep /\C\(^'.s:rePreprocIncludeFile.'\)/gj '.szFixedPath + +    let listQuickFix = getloclist(0) +    let alreadyInclude = {} +    for qf in listQuickFix +        let szLine = qf.text +        let startPos = qf.col +        let endPos = matchend(szLine, s:reIncludeFilePart, startPos-1) +        if endPos!=-1 +            let szInclusion = szLine[startPos-1:endPos-1] +            let szIncludeFile = substitute(szInclusion, '\('.s:rePreprocIncludePart.'\)\|[<>""]', '', 'g') +            let szResolvedInclude = omni#cpp#utils#ResolveFilePath(szIncludeFile) +             +            " Protection over self inclusion +            if szResolvedInclude != '' && szResolvedInclude != a:szFilePath +                let includePos = [qf.lnum, qf.col] +                if !has_key(alreadyInclude, szResolvedInclude) +                    call extend(listIncludes, [{'pos' : includePos, 'include' : szResolvedInclude}]) +                    let alreadyInclude[szResolvedInclude] = 1 +                endif +            endif +        endif +    endfor + +    let g:omni#cpp#includes#CACHE_INCLUDES[a:szFilePath] = listIncludes + +    return copy(listIncludes) +endfunc + +" For debug purpose +function! omni#cpp#includes#Display() +    let szPathBuffer = omni#cpp#utils#ResolveFilePath(getreg('%')) +    call s:DisplayIncludeTree(szPathBuffer, 0) +endfunc + +" For debug purpose +function! s:DisplayIncludeTree(szFilePath, indent, ...) +    let includeGuard = {} +    if a:0 >0 +        let includeGuard = a:1 +    endif +    let szFilePath = omni#cpp#utils#ResolveFilePath(a:szFilePath) +    if has_key(includeGuard, szFilePath) +        return +    else +        let includeGuard[szFilePath] = 1 +    endif + +    let szIndent = repeat('    ', a:indent) +    echo szIndent . a:szFilePath +    let incList = omni#cpp#includes#GetList(a:szFilePath) +    for inc in incList +        call s:DisplayIncludeTree(inc.include, a:indent+1, includeGuard) +    endfor +endfunc + + diff --git a/.vim/autoload/omni/cpp/items.vim b/.vim/autoload/omni/cpp/items.vim new file mode 100644 index 0000000..b943ad4 --- /dev/null +++ b/.vim/autoload/omni/cpp/items.vim @@ -0,0 +1,660 @@ +" Description: Omni completion script for cpp files +" Maintainer:  Vissale NEANG +" Last Change: 26 sept. 2007 + +" Build the item list of an instruction +" An item is an instruction between a -> or . or ->* or .* +" We can sort an item in different kinds: +" eg: ((MyClass1*)(pObject))->_memberOfClass1.get()     ->show() +"     |        cast        |  |    member   | | method |  | method | +" @return a list of item +" an item is a dictionnary where keys are: +"   tokens = list of token +"   kind = itemVariable|itemCast|itemCppCast|itemTemplate|itemFunction|itemUnknown|itemThis|itemScope +function! omni#cpp#items#Get(tokens, ...) +    let bGetWordUnderCursor = (a:0>0)? a:1 : 0 + +    let result = [] +    let itemsDelimiters = ['->', '.', '->*', '.*'] + +    let tokens = reverse(omni#cpp#utils#BuildParenthesisGroups(a:tokens)) + +    " fsm states: +    "   0 = initial state +    "   TODO: add description of fsm states +    let state=(bGetWordUnderCursor)? 1 : 0 +    let item = {'tokens' : [], 'kind' : 'itemUnknown'} +    let parenGroup=-1 +    for token in tokens +        if state==0 +            if index(itemsDelimiters, token.value)>=0 +                let item = {'tokens' : [], 'kind' : 'itemUnknown'} +                let state = 1 +            elseif token.value=='::' +                let state = 9 +                let item.kind = 'itemScope' +                " Maybe end of tokens +            elseif token.kind =='cppOperatorPunctuator' +                " If it's a cppOperatorPunctuator and the current token is not +                " a itemsDelimiters or '::' we can exit +                let state=-1 +                break +            endif +        elseif state==1 +            call insert(item.tokens, token) +            if token.kind=='cppWord' +                " It's an attribute member or a variable +                let item.kind = 'itemVariable' +                let state = 2 +                " Maybe end of tokens +            elseif token.value=='this' +                let item.kind = 'itemThis' +                let state = 2 +                " Maybe end of tokens +            elseif token.value==')' +                let parenGroup = token.group +                let state = 3 +            elseif token.value==']' +                let parenGroup = token.group +                let state = 4 +            elseif token.kind == 'cppDigit' +                let state = -1 +                break +            endif +        elseif state==2 +            if index(itemsDelimiters, token.value)>=0 +                call insert(result, item) +                let item = {'tokens' : [], 'kind' : 'itemUnknown'} +                let state = 1 +            elseif token.value == '::' +                call insert(item.tokens, token) +                " We have to get namespace or classscope +                let state = 8 +                " Maybe end of tokens +            else +                call insert(result, item) +                let state=-1 +                break +            endif +        elseif state==3 +            call insert(item.tokens, token) +            if token.value=='(' && token.group == parenGroup +                let state = 5 +                " Maybe end of tokens +            endif +        elseif state==4 +            call insert(item.tokens, token) +            if token.value=='[' && token.group == parenGroup +                let state = 1 +            endif +        elseif state==5 +            if token.kind=='cppWord' +                " It's a function or method +                let item.kind = 'itemFunction' +                call insert(item.tokens, token) +                let state = 2 +                " Maybe end of tokens +            elseif token.value == '>' +                " Maybe a cpp cast or template +                let item.kind = 'itemTemplate' +                call insert(item.tokens, token) +                let parenGroup = token.group +                let state = 6 +            else +                " Perhaps it's a C cast eg: ((void*)(pData)) or a variable eg:(*pData) +                let item.kind = omni#cpp#utils#GetCastType(item.tokens) +                let state=-1 +                call insert(result, item) +                break +            endif +        elseif state==6 +            call insert(item.tokens, token) +            if token.value == '<' && token.group == parenGroup +                " Maybe a cpp cast or template +                let state = 7 +            endif +        elseif state==7 +            call insert(item.tokens, token) +            if token.kind=='cppKeyword' +                " It's a cpp cast +                let item.kind = omni#cpp#utils#GetCastType(item.tokens) +                let state=-1 +                call insert(result, item) +                break +            else +                " Template ? +                let state=-1 +                call insert(result, item) +                break +            endif +        elseif state==8 +            if token.kind=='cppWord' +                call insert(item.tokens, token) +                let state = 2 +                " Maybe end of tokens +            else +                let state=-1 +                call insert(result, item) +                break +            endif +        elseif state==9 +            if token.kind == 'cppWord' +                call insert(item.tokens, token) +                let state = 10 +                " Maybe end of tokens +            else +                let state=-1 +                call insert(result, item) +                break +            endif +        elseif state==10 +            if token.value == '::' +                call insert(item.tokens, token) +                let state = 9 +                " Maybe end of tokens +            else +                let state=-1 +                call insert(result, item) +                break +            endif +        endif +    endfor + +    if index([2, 5, 8, 9, 10], state)>=0 +        if state==5 +            let item.kind = omni#cpp#utils#GetCastType(item.tokens) +        endif +        call insert(result, item) +    endif + +    return result +endfunc + +" Resolve type information of items +" @param namespaces: list of namespaces used in the file +" @param szCurrentClassScope: the current class scope, only used for the first +" item to detect if this item is a class member (attribute, method) +" @param items: list of item, can be an empty list @see GetItemsToComplete +function! omni#cpp#items#ResolveItemsTypeInfo(contextStack, items) +    " Note: kind = itemVariable|cCast|cppCast|template|function|itemUnknown|this +    " For the first item, if it's a variable we try to detect the type of the +    " variable with the function searchdecl. If it fails, thanks to the +    " current class scope, we try to detect if the variable is an attribute +    " member. +    " If the kind of the item is a function, we have to first check if the +    " function is a method of the class, if it fails we try to get a match in +    " the global namespace. After that we get the returned type of the +    " function. +    " It the kind is a C cast or C++ cast, there is no problem, it's the +    " easiest case. We just extract the type of the cast. + +    let szCurrentContext = '' +    let typeInfo = {} +    " Note: We search the decl only for the first item +    let bSearchDecl = 1 +    for item in a:items +        let curItem = item +        if index(['itemVariable', 'itemFunction'], curItem.kind)>=0 +            " Note: a variable can be : MyNs::MyClass::_var or _var or (*pVar) +            " or _var[0][0] +            let szSymbol = s:GetSymbol(curItem.tokens) + +            " If we have MyNamespace::myVar +            " We add MyNamespace in the context stack set szSymbol to myVar +            if match(szSymbol, '::\w\+$') >= 0 +                let szCurrentContext = substitute(szSymbol, '::\w\+$', '', 'g') +                let szSymbol = matchstr(szSymbol, '\w\+$') +            endif +            let tmpContextStack = a:contextStack +            if szCurrentContext != '' +                let tmpContextStack = [szCurrentContext] + a:contextStack +            endif + +            if curItem.kind == 'itemVariable' +                let typeInfo = s:GetTypeInfoOfVariable(tmpContextStack, szSymbol, bSearchDecl) +            else +                let typeInfo = s:GetTypeInfoOfReturnedType(tmpContextStack, szSymbol) +            endif + +        elseif curItem.kind == 'itemThis' +            if len(a:contextStack) +                let typeInfo = omni#cpp#utils#CreateTypeInfo(substitute(a:contextStack[0], '^::', '', 'g')) +            endif +        elseif curItem.kind == 'itemCast' +            let typeInfo = omni#cpp#utils#CreateTypeInfo(s:ResolveCCast(curItem.tokens)) +        elseif curItem.kind == 'itemCppCast' +            let typeInfo = omni#cpp#utils#CreateTypeInfo(s:ResolveCppCast(curItem.tokens)) +        elseif curItem.kind == 'itemScope' +            let typeInfo = omni#cpp#utils#CreateTypeInfo(substitute(s:TokensToString(curItem.tokens), '\s', '', 'g')) +        endif + +        if omni#cpp#utils#IsTypeInfoValid(typeInfo) +            let szCurrentContext = omni#cpp#utils#GetTypeInfoString(typeInfo) +        endif +        let bSearchDecl = 0 +    endfor + +    return typeInfo +endfunc + +" Get symbol name +function! s:GetSymbol(tokens) +    let szSymbol = '' +    let state = 0 +    for token in a:tokens +        if state == 0 +            if token.value == '::' +                let szSymbol .= token.value +                let state = 1 +            elseif token.kind == 'cppWord' +                let szSymbol .= token.value +                let state = 2 +                " Maybe end of token +            endif +        elseif state == 1 +            if token.kind == 'cppWord' +                let szSymbol .= token.value +                let state = 2 +                " Maybe end of token +            else +                " Error +                break +            endif +        elseif state == 2 +            if token.value == '::' +                let szSymbol .= token.value +                let state = 1 +            else +                break +            endif +        endif +    endfor +    return szSymbol +endfunc + +" Search a declaration. +" eg: std::map +" can be empty +" Note: The returned type info can be a typedef +" The typedef resolution is done later +" @return +"   - a dictionnary where keys are +"       - type: the type of value same as type() +"       - value: the value +function! s:GetTypeInfoOfVariable(contextStack, szVariable, bSearchDecl) +    let result = {} + +    if a:bSearchDecl +        " Search type of declaration +        "let result = s:SearchTypeInfoOfDecl(a:szVariable) +        let result = s:SearchDecl(a:szVariable) +    endif + +    if result=={} +        let szFilter = "index(['m', 'v'], v:val.kind[0])>=0" +        let tagItem = s:ResolveSymbol(a:contextStack, a:szVariable, szFilter) +        if tagItem=={} +            return result +        endif + +        let szCmdWithoutVariable = substitute(omni#cpp#utils#ExtractCmdFromTagItem(tagItem), '\C\<'.a:szVariable.'\>.*', '', 'g') +        let tokens = omni#cpp#tokenizer#Tokenize(omni#cpp#utils#GetCodeFromLine(szCmdWithoutVariable)) +        let result = omni#cpp#utils#CreateTypeInfo(omni#cpp#utils#ExtractTypeInfoFromTokens(tokens)) +        " TODO: Namespace resolution for result + +        if result != {} && result.value=='' +            " result.value=='' +            " eg:  +            " struct +            " { +            " }gVariable; +            if has_key(tagItem, 'typeref') +                " Maybe the variable is a global var of an +                " unnamed class, struct or union. +                " eg: +                " 1) +                " struct +                " { +                " }gVariable; +                " In this case we need the tags (the patched version) +                " Note: We can have a named type like this: +                " 2) +                " class A +                " { +                " }gVariable; +                if s:IsUnnamedType(tagItem) +                    " It's an unnamed type we are in the case 1) +                    let result = omni#cpp#utils#CreateTypeInfo(tagItem) +                else +                    " It's not an unnamed type we are in the case 2) + +                    " eg: tagItem.typeref = 'struct:MY_STRUCT::MY_SUBSTRUCT' +                    let szTypeRef = substitute(tagItem.typeref, '^\w\+:', '', '') + +                    " eg: szTypeRef = 'MY_STRUCT::MY_SUBSTRUCT' +                    let result = omni#cpp#utils#CreateTypeInfo(szTypeRef) +                endif +            endif +        endif +    endif +    return result +endfunc + +" Get the type info string from the returned type of function +function! s:GetTypeInfoOfReturnedType(contextStack, szFunctionName) +    let result = {} + +    let szFilter = "index(['f', 'p'], v:val.kind[0])>=0" +    let tagItem = s:ResolveSymbol(a:contextStack, a:szFunctionName, szFilter) + +    if tagItem != {} +        let szCmdWithoutVariable = substitute(omni#cpp#utils#ExtractCmdFromTagItem(tagItem), '\C\<'.a:szFunctionName.'\>.*', '', 'g') +        let tokens = omni#cpp#tokenizer#Tokenize(omni#cpp#utils#GetCodeFromLine(szCmdWithoutVariable)) +        let result = omni#cpp#utils#CreateTypeInfo(omni#cpp#utils#ExtractTypeInfoFromTokens(tokens)) +        " TODO: Namespace resolution for result +        return result +    endif +    return result +endfunc + +" Resolve a symbol, return a tagItem +" Gets the first symbol found in the context stack +function! s:ResolveSymbol(contextStack, szSymbol, szTagFilter) +    let tagItem = {} +    for szCurrentContext in a:contextStack +        if szCurrentContext != '::' +            let szTagQuery = substitute(szCurrentContext, '^::', '', 'g').'::'.a:szSymbol +        else +            let szTagQuery = a:szSymbol +        endif + +        let tagList = omni#common#utils#TagListNoThrow('^'.szTagQuery.'$') +        call filter(tagList, a:szTagFilter) +        if len(tagList) +            let tagItem = tagList[0] +            break +        endif +    endfor +    return tagItem +endfunc + +" Return if the tag item represent an unnamed type +function! s:IsUnnamedType(tagItem) +    let bResult = 0 +    if has_key(a:tagItem, 'typeref') +        " Note: Thanks for __anon ! +        let bResult = match(a:tagItem.typeref, '\C\<__anon') >= 0 +    endif +    return bResult +endfunc + +" Search the declaration of a variable and return the type info +function! s:SearchTypeInfoOfDecl(szVariable) +    let szReVariable = '\C\<'.a:szVariable.'\>' + +    let originalPos = getpos('.') +    let origPos = originalPos[1:2] +    let curPos = origPos +    let stopPos = origPos +     +    while curPos !=[0,0] +        " We go to the start of the current scope +        let curPos = searchpairpos('{', '', '}', 'bW', g:omni#cpp#utils#expIgnoreComments) +        if curPos != [0,0] +            let matchPos = curPos +            " Now want to search our variable but we don't want to go in child +            " scope +            while matchPos != [0,0] +                let matchPos = searchpos('{\|'.szReVariable, 'W', stopPos[0]) +                if matchPos != [0,0] +                    " We ignore matches under comment +                    if omni#cpp#utils#IsCursorInCommentOrString() +                        continue +                    endif + +                    " Getting the current line +                    let szLine = getline('.') +                    if match(szLine, szReVariable)>=0 +                        " We found our variable +                        " Check if the current instruction is a decl instruction +                        let tokens = omni#cpp#utils#TokenizeCurrentInstruction() +                        let szTypeInfo = s:ExtractTypeInfoFromDecl(tokens) +                        if szTypeInfo != '' +                            call setpos('.', originalPos) +                            return omni#cpp#utils#CreateTypeInfo(szTypeInfo) +                        endif +                    else +                        " We found a child scope, we don't want to go in, thus +                        " we search for the end } of this child scope +                        let bracketEnd = searchpairpos('{', '', '}', 'nW', g:omni#cpp#utils#expIgnoreComments) +                        if bracketEnd == [0,0] +                            break +                        endif + +                        if bracketEnd[0] >= stopPos[0] +                            " The end of the scope is after our cursor we stop +                            " the search +                            break +                        else +                            " We move the cursor and continue to search our +                            " variable +                            call setpos('.', [0, bracketEnd[0], bracketEnd[1], 0]) +                        endif +                    endif +                endif +            endwhile + +            " Backing to the start of the scope +            call setpos('.', [0,curPos[0], curPos[1], 0]) +            let stopPos = curPos +        endif +    endwhile + +    let result = {} +    if s:LocalSearchDecl(a:szVariable)==0 && !omni#cpp#utils#IsCursorInCommentOrString() +        let tokens = omni#cpp#utils#TokenizeCurrentInstruction() +        let szTypeInfo = s:ExtractTypeInfoFromDecl(tokens) +        if szTypeInfo != '' +            let result = omni#cpp#utils#CreateTypeInfo(szTypeInfo) +        endif +    endif + +    call setpos('.', originalPos) + +    return result +endfunc + +" Search a declaration +" @return +"   - tokens of the current instruction if success +"   - empty list if failure +function! s:SearchDecl(szVariable) +    let result = {} +    let originalPos = getpos('.') +    let searchResult = s:LocalSearchDecl(a:szVariable) +    if searchResult==0 +        " searchdecl() may detect a decl if the variable is in a conditional +        " instruction (if, elseif, while etc...) +        " We have to check if the detected decl is really a decl instruction +        let tokens = omni#cpp#utils#TokenizeCurrentInstruction() + +        for token in tokens +            " Simple test +            if index(['if', 'elseif', 'while', 'for', 'switch'], token.value)>=0 +                " Invalid declaration instruction +                call setpos('.', originalPos) +                return result +            endif +        endfor + +        let szTypeInfo = s:ExtractTypeInfoFromDecl(tokens) +        if szTypeInfo != '' +            let result = omni#cpp#utils#CreateTypeInfo(szTypeInfo) +        endif +    endif +    call setpos('.', originalPos) +    return result +endfunc + +" Extract the type info string from an instruction. +" We use a small parser to extract the type +" We parse the code according to a C++ BNF from: http://www.nongnu.org/hcb/#basic.link +" @param tokens: token list of the current instruction +function! s:ExtractTypeInfoFromDecl(tokens) +    return omni#cpp#utils#ExtractTypeInfoFromTokens(a:tokens) +endfunc + +" Convert tokens to string +function! s:TokensToString(tokens) +    let result = '' +    for token in a:tokens +        let result = result . token.value . ' ' +    endfor +    return result[:-2] +endfunc + +" Resolve a cast. +" Resolve a C++ cast +" @param list of token. tokens must be a list that represents +" a cast expression (C++ cast) the function does not control +" if it's a cast or not +" eg: static_cast<MyClass*>(something) +" @return type info string +function! s:ResolveCppCast(tokens) +    return omni#cpp#utils#ExtractTypeInfoFromTokens(s:ResolveCast(a:tokens, '<', '>')) +endfunc + +" Resolve a cast. +" Resolve a C cast +" @param list of token. tokens must be a list that represents +" a cast expression (C cast) the function does not control +" if it's a cast or not +" eg: (MyClass*)something +" @return type info string +function! s:ResolveCCast(tokens) +    return omni#cpp#utils#ExtractTypeInfoFromTokens(s:ResolveCast(a:tokens, '(', ')')) +endfunc + +" Resolve a cast. +" Resolve a C cast +" @param list of token. tokens must be a list that represents +" a cast expression (C cast) the function does not control +" if it's a cast or not +" eg: (MyClass*)something +" @return type tokens +function! s:ResolveCast(tokens, startChar, endChar) +    let tokens = omni#cpp#utils#BuildParenthesisGroups(a:tokens) + +    " We remove useless parenthesis eg: (((MyClass))) +    let tokens = omni#cpp#utils#SimplifyParenthesis(tokens) + +    let countItem=0 +    let startIndex = -1 +    let endIndex = -1  +    let i = 0 +    for token in tokens +        if startIndex==-1 +            if token.value==a:startChar +                let countItem += 1 +                let startIndex = i +            endif +        else +            if token.value==a:startChar +                let countItem += 1 +            elseif token.value==a:endChar +                let countItem -= 1 +            endif + +            if countItem==0 +                let endIndex = i +                break +            endif +        endif +        let i+=1 +    endfor + +    return tokens[startIndex+1 : endIndex-1] +endfunc + +" Replacement for build-in function 'searchdecl' +" It does not require that the upper-level bracket is in the first column. +" Otherwise it should be equal to 'searchdecl(name, 0, 1)' +" @param name: name of variable to find declaration for +function! s:LocalSearchDecl(name) + +    if g:OmniCpp_LocalSearchDecl == 0 +        let bUserIgnoreCase = &ignorecase + +        " Forcing the noignorecase option +        " avoid bug when, for example, if we have a declaration like this : "A a;" +        set noignorecase + +        let result = searchdecl(a:name, 0, 1) + +        " Restoring user's setting +        let &ignorecase = bUserIgnoreCase + +        return result +    endif + +    let lastpos = getpos('.') +    let winview = winsaveview() +    let lastfoldenable = &foldenable +    let &foldenable = 0 + +    " We add \C (noignorecase) to  +    " avoid bug when, for example, if we have a declaration like this : "A a;" +    let varname = "\\C\\<" . a:name . "\\>" + +    " Go to first blank line before begin of highest scope +    normal 99[{ +    let scopepos = getpos('.') +    while (line('.') > 1) && (len(split(getline('.'))) > 0) +        call cursor(line('.')-1, 0) +    endwhile + +    let declpos = [ 0, 0, 0, 0 ] +    while search(varname, '', scopepos[1]) > 0 +        " Check if we are a string or a comment +        if omni#cpp#utils#IsCursorInCommentOrString() +            continue +        endif + +        " Remember match +        let declpos = getpos('.') +    endwhile +    if declpos[1] != 0 +        " We found a match +        call winrestview(winview) +        call setpos('.', declpos) +        let &foldenable = lastfoldenable +        return 0 +    endif + +    while search(varname, '', lastpos[1]) > 0 +        " Check if current scope is ending before variable +        let old_cur = getpos('.') +        normal ]} +        let new_cur = getpos('.') +        call setpos('.', old_cur) +        if (new_cur[1] < lastpos[1]) || ((new_cur[1] == lastpos[1]) && (new_cur[2] < lastpos[2])) +          continue +        endif + +        " Check if we are a string or a comment +        if omni#cpp#utils#IsCursorInCommentOrString() +          continue +        endif + +        " We found match +        call winrestview(winview) +        call setpos('.', old_cur) +        let &foldenable = lastfoldenable +        return 0 +    endwhile + +    " No match found. +    call winrestview(winview) +    let &foldenable = lastfoldenable +    return 1 +endfunc diff --git a/.vim/autoload/omni/cpp/maycomplete.vim b/.vim/autoload/omni/cpp/maycomplete.vim new file mode 100644 index 0000000..610526b --- /dev/null +++ b/.vim/autoload/omni/cpp/maycomplete.vim @@ -0,0 +1,82 @@ +" Description: Omni completion script for cpp files +" Maintainer:  Vissale NEANG +" Last Change: 26 sept. 2007 + +" Check if we can use omni completion in the current buffer +function! s:CanUseOmnicompletion() +    " For C and C++ files and only if the omnifunc is omni#cpp#complete#Main +    return (index(['c', 'cpp'], &filetype)>=0 && &omnifunc == 'omni#cpp#complete#Main' && !omni#cpp#utils#IsCursorInCommentOrString()) +endfunc + +" Return the mapping of omni completion +function! omni#cpp#maycomplete#Complete() +    let szOmniMapping = "\<C-X>\<C-O>" + +    "   0 = don't select first item +    "   1 = select first item (inserting it to the text, default vim behaviour) +    "   2 = select first item (without inserting it to the text) +    if g:OmniCpp_SelectFirstItem == 0 +        " We have to force the menuone option to avoid confusion when there is +        " only one popup item +        set completeopt-=menu +        set completeopt+=menuone +        let szOmniMapping .= "\<C-P>" +    elseif g:OmniCpp_SelectFirstItem == 2 +        " We have to force the menuone option to avoid confusion when there is +        " only one popup item +        set completeopt-=menu +        set completeopt+=menuone +        let szOmniMapping .= "\<C-P>" +        let szOmniMapping .= "\<C-R>=pumvisible() ? \"\\<down>\" : \"\"\<cr>" +    endif +    return szOmniMapping +endfunc + +" May complete function for dot +function! omni#cpp#maycomplete#Dot() +    if s:CanUseOmnicompletion() && g:OmniCpp_MayCompleteDot +        let g:omni#cpp#items#data = omni#cpp#items#Get(omni#cpp#utils#TokenizeCurrentInstruction('.')) +        if len(g:omni#cpp#items#data) +            let s:bMayComplete = 1 +            return '.' . omni#cpp#maycomplete#Complete() +        endif +    endif +    return '.' +endfunc +" May complete function for arrow +function! omni#cpp#maycomplete#Arrow() +    if s:CanUseOmnicompletion() && g:OmniCpp_MayCompleteArrow +        let index = col('.') - 2 +        if index >= 0 +            let char = getline('.')[index] +            if char == '-' +                let g:omni#cpp#items#data = omni#cpp#items#Get(omni#cpp#utils#TokenizeCurrentInstruction('>')) +                if len(g:omni#cpp#items#data) +                    let s:bMayComplete = 1 +                    return '>' . omni#cpp#maycomplete#Complete() +                endif +            endif +        endif +    endif +    return '>' +endfunc + +" May complete function for double points +function! omni#cpp#maycomplete#Scope() +    if s:CanUseOmnicompletion() && g:OmniCpp_MayCompleteScope +        let index = col('.') - 2 +        if index >= 0 +            let char = getline('.')[index] +            if char == ':' +                let g:omni#cpp#items#data = omni#cpp#items#Get(omni#cpp#utils#TokenizeCurrentInstruction(':')) +                if len(g:omni#cpp#items#data) +                    if len(g:omni#cpp#items#data[-1].tokens) && g:omni#cpp#items#data[-1].tokens[-1].value != '::' +                        let s:bMayComplete = 1 +                        return ':' . omni#cpp#maycomplete#Complete() +                    endif +                endif +            endif +        endif +    endif +    return ':' +endfunc diff --git a/.vim/autoload/omni/cpp/namespaces.vim b/.vim/autoload/omni/cpp/namespaces.vim new file mode 100644 index 0000000..386b3f9 --- /dev/null +++ b/.vim/autoload/omni/cpp/namespaces.vim @@ -0,0 +1,838 @@ +" Description: Omni completion script for cpp files +" Maintainer:  Vissale NEANG +" Last Change: 26 sept. 2007 + +let g:omni#cpp#namespaces#CacheResolve = {} +let g:omni#cpp#namespaces#CacheUsing = {} +" TODO: For the next release +"let g:omni#cpp#namespaces#CacheAlias = {} + +" Get the using namespace list from a line +function! s:GetNamespaceAliasListFromLine(szLine) +    let result = {} +    let tokens = omni#cpp#tokenizer#Tokenize(a:szLine) +    let szAlias = '' +    let szNamespace = '' +    let state = 0 +    for token in tokens +        if state==0 +            let szAlias = '' +            let szNamespace = '' +            if token.value == '/*' +                let state = 1 +            elseif token.value == '//' +                " It's a comment +                let state = -1 +                break +            elseif token.value == 'namespace' +                let state = 2 +            endif +        elseif state==1 +            if token.value == '*/' +                let state=0 +            endif +        elseif state==2 +            if token.kind == 'cppWord' +                let szAlias .= token.value +                let state = 3 +            else +                let state = -1 +                break +            endif +        elseif state == 3 +            if token.value == '=' +                let state = 4 +            else +                let state = -1 +                break +            endif +        elseif state == 4 +            if token.value == '::' +                let szNamespace .= token.value +                let state = 5 +            elseif token.kind == 'cppWord' +                let szNamespace .= token.value +                let state = 6 +                " Maybe end of tokens +            endif +        elseif state==5 +            if token.kind == 'cppWord' +                let szNamespace .= token.value +                let state = 6 +                " Maybe end of tokens +            else +                " Error, we can't have 'namespace ALIAS = Something::' +                let state = -1 +                break +            endif +        elseif state==6 +            if token.value == '::' +                let szNamespace .= token.value +                let state = 5 +            else +                call extend(result, {szAlias : szNamespace}) +                let state = 0 +            endif +        endif +    endfor + +    if state == 6 +        call extend(result, {szAlias : szNamespace}) +    endif + +    return result +endfunc + +" Get the using namespace list from a line +function! s:GetNamespaceListFromLine(szLine) +    let result = [] +    let tokens = omni#cpp#tokenizer#Tokenize(a:szLine) +    let szNamespace = '' +    let state = 0 +    for token in tokens +        if state==0 +            let szNamespace = '' +            if token.value == '/*' +                let state = 1 +            elseif token.value == '//' +                " It's a comment +                let state = -1 +                break +            elseif token.value == 'using' +                let state = 2 +            endif +        elseif state==1 +            if token.value == '*/' +                let state=0 +            endif +        elseif state==2 +            if token.value == 'namespace' +                let state = 3 +            else +                " Error, 'using' must be followed by 'namespace' +                let state = -1 +                break +            endif +        elseif state==3 +            if token.value == '::' +                let szNamespace .= token.value +                let state = 4 +            elseif token.kind == 'cppWord' +                let szNamespace .= token.value +                let state = 5 +                " Maybe end of tokens +            endif +        elseif state==4 +            if token.kind == 'cppWord' +                let szNamespace .= token.value +                let state = 5 +                " Maybe end of tokens +            else +                " Error, we can't have 'using namespace Something::' +                let state = -1 +                break +            endif +        elseif state==5 +            if token.value == '::' +                let szNamespace .= token.value +                let state = 4 +            else +                call extend(result, [szNamespace]) +                let state = 0 +            endif +        endif +    endfor + +    if state == 5 +        call extend(result, [szNamespace]) +    endif + +    return result +endfunc + +" Get the namespace list from a namespace map +function! s:GetUsingNamespaceListFromMap(namespaceMap, ...) +    let stopLine = 0 +    if a:0>0 +        let stopLine = a:1 +    endif + +    let result = [] +    let keys = sort(keys(a:namespaceMap), 'omni#common#utils#CompareNumber') +    for i in keys +        if stopLine != 0 && i > stopLine +            break +        endif +        call extend(result, a:namespaceMap[i]) +    endfor +    return result +endfunc + +" Get global using namespace list from the current buffer +function! omni#cpp#namespaces#GetListFromCurrentBuffer(...) +    let namespaceMap = s:GetAllUsingNamespaceMapFromCurrentBuffer() +    let result = [] +    if namespaceMap != {} +        let result = s:GetUsingNamespaceListFromMap(namespaceMap, (a:0 > 0)? a:1 : line('.')) +    endif +    return result +endfunc + +" Get global using namespace map from the current buffer and include files recursively +function! s:GetAllUsingNamespaceMapFromCurrentBuffer(...) +    let includeGuard = (a:0>0)? a:1 : {} + +    let szBufferName = getreg("%") +    let szFilePath = omni#cpp#utils#ResolveFilePath(szBufferName) +    let szFilePath = (szFilePath=='')? szBufferName : szFilePath + +    let namespaceMap = {} +    if has_key(includeGuard, szFilePath) +        return namespaceMap +    else +        let includeGuard[szFilePath] = 1 +    endif + +    let namespaceMap = omni#cpp#namespaces#GetMapFromCurrentBuffer() + +    if g:OmniCpp_NamespaceSearch != 2 +        " We don't search included files if OmniCpp_NamespaceSearch != 2 +        return namespaceMap +    endif + +    for inc in omni#cpp#includes#GetList() +        let lnum = inc.pos[0] +        let tmpMap = s:GetAllUsingNamespaceMapFromFile(inc.include, includeGuard) +        if tmpMap != {} +            if has_key(namespaceMap, lnum) +                call extend(namespaceMap[lnum], s:GetUsingNamespaceListFromMap(tmpMap)) +            else +                let namespaceMap[lnum] = s:GetUsingNamespaceListFromMap(tmpMap) +            endif +        endif +    endfor + +    return namespaceMap +endfunc + +" Get global using namespace map from a file and include files recursively +function! s:GetAllUsingNamespaceMapFromFile(szFilePath, ...) +    let includeGuard = {} +    if a:0 >0 +        let includeGuard = a:1 +    endif + +    let szFilePath = omni#cpp#utils#ResolveFilePath(a:szFilePath) +    let szFilePath = (szFilePath=='')? a:szFilePath : szFilePath + +    let namespaceMap = {} +    if has_key(includeGuard, szFilePath) +        return namespaceMap +    else +        let includeGuard[szFilePath] = 1 +    endif + +    " If g:OmniCpp_NamespaceSearch == 1 (search namespaces only in the current +    " buffer) we don't use cache for the current buffer +    let namespaceMap = omni#cpp#namespaces#GetMapFromBuffer(szFilePath, g:OmniCpp_NamespaceSearch==1) + +    if g:OmniCpp_NamespaceSearch != 2 +        " We don't search included files if OmniCpp_NamespaceSearch != 2 +        return namespaceMap +    endif + +    for inc in omni#cpp#includes#GetList(szFilePath) +        let lnum = inc.pos[0] +        let tmpMap = s:GetAllUsingNamespaceMapFromFile(inc.include, includeGuard) +        if tmpMap != {} +            if has_key(namespaceMap, lnum) +                call extend(namespaceMap[lnum], s:GetUsingNamespaceListFromMap(tmpMap)) +            else +                let namespaceMap[lnum] = s:GetUsingNamespaceListFromMap(tmpMap) +            endif +        endif +    endfor + +    return namespaceMap +endfunc + +" Get global using namespace map from a the current buffer +function! omni#cpp#namespaces#GetMapFromCurrentBuffer() +    let namespaceMap = {} +    let originalPos = getpos('.') + +    call setpos('.', [0, 1, 1, 0]) +    let curPos = [1,1] +    while curPos != [0,0] +        let curPos = searchpos('\C^using\s\+namespace', 'W') +        if curPos != [0,0] +            let szLine = getline('.') +            let startPos = curPos[1] +            let endPos = match(szLine, ';', startPos-1) +            if endPos!=-1 +                " We get the namespace list from the line +                let namespaceMap[curPos[0]] = s:GetNamespaceListFromLine(szLine) +            endif +        endif +    endwhile + +    call setpos('.', originalPos) +    return namespaceMap +endfunc + +" Get global using namespace map from a file +function! omni#cpp#namespaces#GetMapFromBuffer(szFilePath, ...) +    let bUpdate = 0 +    if a:0 > 0 +        let bUpdate = a:1 +    endif + +    let szFilePath = omni#cpp#utils#ResolveFilePath(a:szFilePath) +    let szFilePath = (szFilePath=='')? a:szFilePath : szFilePath + +    if !bUpdate && has_key(g:omni#cpp#namespaces#CacheUsing, szFilePath) +        return copy(g:omni#cpp#namespaces#CacheUsing[szFilePath]) +    endif + +    let namespaceMap = {} +    " The file exists, we get the global namespaces in this file +    let szFixedPath = escape(szFilePath, g:omni#cpp#utils#szEscapedCharacters) +    execute 'silent! lvimgrep /\C^using\s\+namespace/gj '.szFixedPath + +    " key = line number +    " value = list of namespaces +    let listQuickFix = getloclist(0) +    for qf in listQuickFix +        let szLine = qf.text +        let startPos = qf.col +        let endPos = match(szLine, ';', startPos-1) +        if endPos!=-1 +            " We get the namespace list from the line +            let namespaceMap[qf.lnum] = s:GetNamespaceListFromLine(szLine) +        endif +    endfor + +    if szFixedPath != '' +        let g:omni#cpp#namespaces#CacheUsing[szFixedPath] = namespaceMap +    endif + +    return copy(namespaceMap) +endfunc + +" Get the stop position when searching for local variables +function! s:GetStopPositionForLocalSearch() +    " Stop position when searching a local variable +    let originalPos = getpos('.') +    let origPos = originalPos[1:2] +    let stopPosition = origPos +    let curPos = origPos +    while curPos !=[0,0] +        let stopPosition = curPos +        let curPos = searchpairpos('{', '', '}', 'bW', g:omni#cpp#utils#expIgnoreComments) +    endwhile +    call setpos('.', originalPos) + +    return stopPosition +endfunc + +" Get namespaces alias used at the cursor postion in a vim buffer +" Note: The result depends on the current cursor position +" @return +"   -   Map of namespace alias +function! s:GetNamespaceAliasMap() +    " We store the cursor position because searchpairpos() moves the cursor +    let result = {} +    let originalPos = getpos('.') +    let origPos = originalPos[1:2] + +    let stopPos = s:GetStopPositionForLocalSearch() +    let stopLine = stopPos[0] +    let curPos = origPos +    let lastLine = 0  +    let nextStopLine = origPos[0] +    let szReAlias = '\Cnamespace\s\+\w\+\s\+=' +    while curPos !=[0,0] +        let curPos = searchpos('}\|\('. szReAlias .'\)', 'bW',stopLine) +        if curPos!=[0,0] && curPos[0]!=lastLine +            let lastLine = curPos[0] + +            let szLine = getline('.') +            if origPos[0] == curPos[0] +                " We get the line until cursor position +                let szLine = szLine[:origPos[1]] +            endif + +            let szLine = omni#cpp#utils#GetCodeFromLine(szLine) +            if match(szLine, szReAlias)<0 +                " We found a '}' +                let curPos = searchpairpos('{', '', '}', 'bW', g:omni#cpp#utils#expIgnoreComments) +            else +                " We get the namespace alias from the line +                call extend(result, s:GetNamespaceAliasListFromLine(szLine)) +                let nextStopLine = curPos[0] +            endif +        endif +    endwhile + +    " Setting the cursor to the original position +    call setpos('.', originalPos) + +    call s:ResolveAliasKeys(result) +    return result +endfunc + +" Resolve an alias +" eg: namespace IAmAnAlias1 = Ns1 +" eg: namespace IAmAnAlias2 = IAmAnAlias1::Ns2 +" => IAmAnAlias2 = Ns1::Ns2 +function! s:ResolveAliasKey(mapNamespaceAlias, szAlias) +    let szResult = a:mapNamespaceAlias[a:szAlias] +    " ::Ns1::Ns2::Ns3 => ['Ns1', 'Ns2', 'Ns3'] +    let listNamespace = split(szResult, '::') +    if len(listNamespace) +        " szBeginPart = 'Ns1' +        let szBeginPart = remove(listNamespace, 0) + +        " Is 'Ns1' an alias ? +        if has_key(a:mapNamespaceAlias, szBeginPart) && szBeginPart != a:szAlias +            " Resolving alias 'Ns1' +            " eg: Ns1 = NsResolved +            let szResult = s:ResolveAliasKey(a:mapNamespaceAlias, szBeginPart) +            " szEndPart = 'Ns2::Ns3' +            let szEndPart = join(listNamespace, '::') +            if szEndPart != '' +                " Concatenation => szResult = 'NsResolved::Ns2::Ns3' +                let szResult .= '::' . szEndPart +            endif +        endif +    endif +    return szResult +endfunc + +" Resolve all keys in the namespace alias map +function! s:ResolveAliasKeys(mapNamespaceAlias) +    let mapNamespaceAlias = a:mapNamespaceAlias +    call map(mapNamespaceAlias, 's:ResolveAliasKey(mapNamespaceAlias, v:key)') +endfunc + +" Resolve namespace alias +function! omni#cpp#namespaces#ResolveAlias(mapNamespaceAlias, szNamespace) +    let szResult = a:szNamespace +    " ::Ns1::Ns2::Ns3 => ['Ns1', 'Ns2', 'Ns3'] +    let listNamespace = split(a:szNamespace, '::') +    if len(listNamespace) +        " szBeginPart = 'Ns1' +        let szBeginPart = remove(listNamespace, 0) + +        " Is 'Ns1' an alias ? +        if has_key(a:mapNamespaceAlias, szBeginPart) +            " Resolving alias 'Ns1' +            " eg: Ns1 = NsResolved +            let szResult = a:mapNamespaceAlias[szBeginPart] +            " szEndPart = 'Ns2::Ns3' +            let szEndPart = join(listNamespace, '::') +            if szEndPart != '' +                " Concatenation => szResult = 'NsResolved::Ns2::Ns3' +                let szResult .= '::' . szEndPart +            endif + +            " If a:szNamespace starts with '::' we add '::' to the beginning +            " of the result +            if match(a:szNamespace, '^::')>=0 +                let szResult = omni#cpp#utils#SimplifyScope('::' .  szResult) +            endif +        endif +    endif +    return szResult +endfunc + +" Resolve namespace alias +function! s:ResolveAliasInNamespaceList(mapNamespaceAlias, listNamespaces) +    call map(a:listNamespaces, 'omni#cpp#namespaces#ResolveAlias(a:mapNamespaceAlias, v:val)') +endfunc + +" Get namespaces used at the cursor postion in a vim buffer +" Note: The result depends on the current cursor position +" @return +"   -   List of namespace used in the reverse order +function! omni#cpp#namespaces#GetUsingNamespaces() +    " We have to get local using namespace declarations +    " We need the current cursor position and the position of the start of the +    " current scope + +    " We store the cursor position because searchpairpos() moves the cursor +    let result = [] +    let originalPos = getpos('.') +    let origPos = originalPos[1:2] + +    let stopPos = s:GetStopPositionForLocalSearch() + +    let stopLine = stopPos[0] +    let curPos = origPos +    let lastLine = 0  +    let nextStopLine = origPos[0] +    while curPos !=[0,0] +        let curPos = searchpos('\C}\|\(using\s\+namespace\)', 'bW',stopLine) +        if curPos!=[0,0] && curPos[0]!=lastLine +            let lastLine = curPos[0] + +            let szLine = getline('.') +            if origPos[0] == curPos[0] +                " We get the line until cursor position +                let szLine = szLine[:origPos[1]] +            endif + +            let szLine = omni#cpp#utils#GetCodeFromLine(szLine) +            if match(szLine, '\Cusing\s\+namespace')<0 +                " We found a '}' +                let curPos = searchpairpos('{', '', '}', 'bW', g:omni#cpp#utils#expIgnoreComments) +            else +                " We get the namespace list from the line +                let result = s:GetNamespaceListFromLine(szLine) + result +                let nextStopLine = curPos[0] +            endif +        endif +    endwhile + +    " Setting the cursor to the original position +    call setpos('.', originalPos) + +    " 2) Now we can get all global using namespace declaration from the +    " beginning of the file to nextStopLine +    let result = omni#cpp#namespaces#GetListFromCurrentBuffer(nextStopLine) + result + +    " Resolving alias in the namespace list +    " TODO: For the next release +    "let g:omni#cpp#namespaces#CacheAlias= s:GetNamespaceAliasMap() +    "call s:ResolveAliasInNamespaceList(g:omni#cpp#namespaces#CacheAlias, result) + +    return ['::'] + result +endfunc + +" Resolve a using namespace regarding the current context +" For each namespace used: +"   -   We get all possible contexts where the namespace +"       can be define +"   -   We do a comparison test of each parent contexts with the current +"       context list +"           -   If one and only one parent context is present in the +"               current context list we add the namespace in the current +"               context +"           -   If there is more than one of parent contexts in the +"               current context the namespace is ambiguous +" @return +"   - result item +"       - kind = 0|1 +"           - 0 = unresolved or error +"           - 1 = resolved +"       - value = resolved namespace +function! s:ResolveNamespace(namespace, mapCurrentContexts) +    let result = {'kind':0, 'value': ''} + +    " If the namespace is already resolved we add it in the list of  +    " current contexts +    if match(a:namespace, '^::')>=0 +        let result.kind = 1 +        let result.value = a:namespace +        return result +    elseif match(a:namespace, '\w\+::\w\+')>=0 +        let mapCurrentContextsTmp = copy(a:mapCurrentContexts)  +        let resolvedItem = {} +        for nsTmp in  split(a:namespace, '::') +            let resolvedItem = s:ResolveNamespace(nsTmp, mapCurrentContextsTmp) +            if resolvedItem.kind +                " Note: We don't extend the map +                let mapCurrentContextsTmp = {resolvedItem.value : 1} +            else +                break +            endif +        endfor +        if resolvedItem!={} && resolvedItem.kind +            let result.kind = 1 +            let result.value = resolvedItem.value +        endif +        return result +    endif + +    " We get all possible parent contexts of this namespace +    let listTagsOfNamespace = [] +    if has_key(g:omni#cpp#namespaces#CacheResolve, a:namespace) +        let listTagsOfNamespace = g:omni#cpp#namespaces#CacheResolve[a:namespace] +    else +        let listTagsOfNamespace = omni#common#utils#TagList('^'.a:namespace.'$') +        let g:omni#cpp#namespaces#CacheResolve[a:namespace] = listTagsOfNamespace +    endif + +    if len(listTagsOfNamespace)==0 +        return result +    endif +    call filter(listTagsOfNamespace, 'v:val.kind[0]=="n"') + +    " We extract parent context from tags +    " We use a map to avoid multiple entries +    let mapContext = {} +    for tagItem in listTagsOfNamespace +        let szParentContext = omni#cpp#utils#ExtractScope(tagItem) +        let mapContext[szParentContext] = 1 +    endfor +    let listParentContext = keys(mapContext) + +    " Now for each parent context we test if the context is in the current +    " contexts list +    let listResolvedNamespace = [] +    for szParentContext in listParentContext +        if has_key(a:mapCurrentContexts, szParentContext) +            call extend(listResolvedNamespace, [omni#cpp#utils#SimplifyScope(szParentContext.'::'.a:namespace)]) +        endif +    endfor + +    " Now we know if the namespace is ambiguous or not +    let len = len(listResolvedNamespace) +    if len==1 +        " Namespace resolved +        let result.kind = 1 +        let result.value = listResolvedNamespace[0] +    elseif len > 1 +        " Ambiguous namespace, possible matches are in listResolvedNamespace +    else +        " Other cases +    endif +    return result +endfunc + +" Resolve namespaces +"@return +"   - List of resolved namespaces +function! omni#cpp#namespaces#ResolveAll(namespacesUsed) + +    " We add the default context '::' +    let contextOrder = 0 +    let mapCurrentContexts  = {} + +    " For each namespace used: +    "   -   We get all possible contexts where the namespace +    "       can be define +    "   -   We do a comparison test of each parent contexts with the current +    "       context list +    "           -   If one and only one parent context is present in the +    "               current context list we add the namespace in the current +    "               context +    "           -   If there is more than one of parent contexts in the +    "               current context the namespace is ambiguous +    for ns in a:namespacesUsed +        let resolvedItem = s:ResolveNamespace(ns, mapCurrentContexts) +        if resolvedItem.kind +            let contextOrder+=1 +            let mapCurrentContexts[resolvedItem.value] = contextOrder +        endif +    endfor + +    " Build the list of current contexts from the map, we have to keep the +    " order +    let mapReorder = {} +    for key in keys(mapCurrentContexts) +        let mapReorder[ mapCurrentContexts[key] ] = key +    endfor +    let result = [] +    for key in sort(keys(mapReorder)) +        call extend(result, [mapReorder[key]]) +    endfor +    return result +endfunc + +" Build the context stack +function! s:BuildContextStack(namespaces, szCurrentScope) +    let result = copy(a:namespaces) +    if a:szCurrentScope != '::' +        let tagItem = omni#cpp#utils#GetResolvedTagItem(a:namespaces, omni#cpp#utils#CreateTypeInfo(a:szCurrentScope)) +        if has_key(tagItem, 'inherits') +            let listBaseClass = omni#cpp#utils#GetClassInheritanceList(a:namespaces, omni#cpp#utils#CreateTypeInfo(a:szCurrentScope)) +            let result = listBaseClass + result +        elseif has_key(tagItem, 'kind') && index(['c', 's', 'u', 'n'], tagItem.kind[0])>=0 +            call insert(result, omni#cpp#utils#ExtractTypeInfoFromTag(tagItem)) +        endif +    endif +    return result +endfunc + +" Returns the class scope at the current position of the cursor +" @return a string that represents the class scope +" eg: ::NameSpace1::Class1 +" The returned string always starts with '::' +" Note: In term of performance it's the weak point of the script +function! s:GetClassScopeAtCursor() +    " We store the cursor position because searchpairpos() moves the cursor +    let originalPos = getpos('.') +    let endPos = originalPos[1:2] +    let listCode = [] +    let result = {'namespaces': [], 'scope': ''} + +    while endPos!=[0,0] +        let endPos = searchpairpos('{', '', '}', 'bW', g:omni#cpp#utils#expIgnoreComments) +        let szReStartPos = '[;{}]\|\%^' +        let startPos = searchpairpos(szReStartPos, '', '{', 'bWn', g:omni#cpp#utils#expIgnoreComments) + +        " If the file starts with a comment so the startPos can be [0,0] +        " we change it to [1,1] +        if startPos==[0,0] +            let startPos = [1,1] +        endif + +        " Get lines backward from cursor position to last ; or { or } +        " or when we are at the beginning of the file. +        " We store lines in listCode +        if endPos!=[0,0] +            " We remove the last character which is a '{' +            " We also remove starting { or } or ; if exits +            let szCodeWithoutComments = substitute(omni#cpp#utils#GetCode(startPos, endPos)[:-2], '^[;{}]', '', 'g') +            call insert(listCode, {'startLine' : startPos[0], 'code' : szCodeWithoutComments}) +        endif +    endwhile +    " Setting the cursor to the original position +    call setpos('.', originalPos) + +    let listClassScope = [] +    let bResolved = 0 +    let startLine = 0 +    " Now we can check in the list of code if there is a function +    for code in listCode +        " We get the name of the namespace, class, struct or union +        " and we store it in listClassScope +        let tokens = omni#cpp#tokenizer#Tokenize(code.code) +        let bContinue=0 +        let bAddNamespace = 0 +        let state=0 +        for token in tokens +            if state==0 +                if index(['namespace', 'class', 'struct', 'union'], token.value)>=0 +                    if token.value == 'namespace' +                        let bAddNamespace = 1 +                    endif +                    let state= 1 +                    " Maybe end of tokens +                endif +            elseif state==1 +                if token.kind == 'cppWord' +                    " eg: namespace MyNs { class MyCl {}; } +                    " => listClassScope = [MyNs, MyCl] +                    call extend( listClassScope , [token.value] ) + +                    " Add the namespace in result +                    if bAddNamespace +                        call extend(result.namespaces, [token.value]) +                        let bAddNamespace = 0 +                    endif + +                    let bContinue=1 +                    break +                endif +            endif +        endfor +        if bContinue==1 +            continue +        endif + +        " Simple test to check if we have a chance to find a +        " class method +        let aPos = matchend(code.code, '::\s*\~*\s*\w\+\s*(') +        if aPos ==-1 +            continue +        endif + +        let startLine = code.startLine +        let listTmp = [] +        " eg: 'void MyNamespace::MyClass::foo(' +        " => tokens = ['MyClass', '::', 'MyNamespace', 'void'] +        let tokens = reverse(omni#cpp#tokenizer#Tokenize(code.code[:aPos-1])[:-4]) +        let state = 0 +        " Reading tokens backward +        for token in tokens +            if state==0 +                if token.kind=='cppWord' +                    call insert(listTmp, token.value) +                    let state=1 +                endif +            elseif state==1 +                if token.value=='::' +                    let state=2 +                else +                    break +                endif +            elseif state==2 +                if token.kind=='cppWord' +                    call insert(listTmp, token.value) +                    let state=1 +                else +                    break +                endif +            endif +        endfor +         +        if len(listTmp) +            if len(listClassScope) +                let bResolved = 1 +                " Merging class scopes +                " eg: current class scope = 'MyNs::MyCl1' +                " method class scope = 'MyCl1::MyCl2' +                " If we add the method class scope to current class scope +                " we'll have MyNs::MyCl1::MyCl1::MyCl2 => it's wrong +                " we want MyNs::MyCl1::MyCl2 +                let index = 0 +                for methodClassScope in listTmp +                    if methodClassScope==listClassScope[-1] +                        let listTmp = listTmp[index+1:] +                        break +                    else +                        let index+=1 +                    endif +                endfor +            endif +            call extend(listClassScope, listTmp) +            break +        endif +    endfor + +    let szClassScope = '::' +    if len(listClassScope) +        if bResolved +            let szClassScope .= join(listClassScope, '::') +        else +            let szClassScope = join(listClassScope, '::') +             +            " The class scope is not resolved, we have to check using +            " namespace declarations and search the class scope in each +            " namespace +            if startLine != 0 +                let namespaces = ['::'] + omni#cpp#namespaces#GetListFromCurrentBuffer(startLine) +                let namespaces = omni#cpp#namespaces#ResolveAll(namespaces) +                let tagItem = omni#cpp#utils#GetResolvedTagItem(namespaces, omni#cpp#utils#CreateTypeInfo(szClassScope)) +                if tagItem != {} +                    let szClassScope = omni#cpp#utils#ExtractTypeInfoFromTag(tagItem) +                endif +            endif +        endif +    endif + +    let result.scope = szClassScope +    return result +endfunc + +" Get all contexts at the cursor position +function! omni#cpp#namespaces#GetContexts() +    " Get the current class scope at the cursor, the result depends on the current cursor position +    let scopeItem = s:GetClassScopeAtCursor() +    let listUsingNamespace = copy(g:OmniCpp_DefaultNamespaces) +    call extend(listUsingNamespace, scopeItem.namespaces) +    if g:OmniCpp_NamespaceSearch && &filetype != 'c' +        " Get namespaces used in the file until the cursor position +        let listUsingNamespace = omni#cpp#namespaces#GetUsingNamespaces() + listUsingNamespace +        " Resolving namespaces, removing ambiguous namespaces +        let namespaces = omni#cpp#namespaces#ResolveAll(listUsingNamespace) +    else +        let namespaces = ['::'] + listUsingNamespace +    endif +    call reverse(namespaces) + +    " Building context stack from namespaces and the current class scope +    return s:BuildContextStack(namespaces, scopeItem.scope) +endfunc diff --git a/.vim/autoload/omni/cpp/settings.vim b/.vim/autoload/omni/cpp/settings.vim new file mode 100644 index 0000000..6683d3a --- /dev/null +++ b/.vim/autoload/omni/cpp/settings.vim @@ -0,0 +1,96 @@ +" Description: Omni completion script for cpp files +" Maintainer:  Vissale NEANG +" Last Change: 26 sept. 2007 + +function! omni#cpp#settings#Init() +    " Global scope search on/off +    "   0 = disabled +    "   1 = enabled +    if !exists('g:OmniCpp_GlobalScopeSearch')  +        let g:OmniCpp_GlobalScopeSearch = 1 +    endif + +    " Sets the namespace search method +    "   0 = disabled +    "   1 = search namespaces in the current file +    "   2 = search namespaces in the current file and included files +    if !exists('g:OmniCpp_NamespaceSearch')  +        let g:OmniCpp_NamespaceSearch = 1 +    endif + +    " Set the class scope completion mode +    "   0 = auto +    "   1 = show all members (static, public, protected and private) +    if !exists('g:OmniCpp_DisplayMode')  +        let g:OmniCpp_DisplayMode = 0 +    endif + +    " Set if the scope is displayed in the abbr column of the popup +    "   0 = no +    "   1 = yes +    if !exists('g:OmniCpp_ShowScopeInAbbr')  +        let g:OmniCpp_ShowScopeInAbbr = 0 +    endif + +    " Set if the function prototype is displayed in the abbr column of the popup +    "   0 = no +    "   1 = yes +    if !exists('g:OmniCpp_ShowPrototypeInAbbr')  +        let g:OmniCpp_ShowPrototypeInAbbr = 0 +    endif +     +    " Set if the access (+,#,-) is displayed +    "   0 = no +    "   1 = yes +    if !exists('g:OmniCpp_ShowAccess')  +        let g:OmniCpp_ShowAccess = 1 +    endif + +    " Set the list of default namespaces +    " eg: ['std'] +    if !exists('g:OmniCpp_DefaultNamespaces')  +        let g:OmniCpp_DefaultNamespaces = [] +    endif + +    " Set MayComplete to '.' +    "   0 = disabled +    "   1 = enabled +    "   default = 1 +    if !exists('g:OmniCpp_MayCompleteDot')  +        let g:OmniCpp_MayCompleteDot = 1 +    endif + +    " Set MayComplete to '->' +    "   0 = disabled +    "   1 = enabled +    "   default = 1 +    if !exists('g:OmniCpp_MayCompleteArrow')  +        let g:OmniCpp_MayCompleteArrow = 1 +    endif + +    " Set MayComplete to dot +    "   0 = disabled +    "   1 = enabled +    "   default = 0 +    if !exists('g:OmniCpp_MayCompleteScope')  +        let g:OmniCpp_MayCompleteScope = 0 +    endif + +    " When completeopt does not contain longest option, this setting  +    " controls the behaviour of the popup menu selection when starting the completion +    "   0 = don't select first item +    "   1 = select first item (inserting it to the text) +    "   2 = select first item (without inserting it to the text) +    "   default = 0 +    if !exists('g:OmniCpp_SelectFirstItem')  +        let g:OmniCpp_SelectFirstItem= 0 +    endif + +    " Use local search function for variable definitions +    "   0 = use standard vim search function +    "   1 = use local search function +    "   default = 0 +    if !exists('g:OmniCpp_LocalSearchDecl')  +        let g:OmniCpp_LocalSearchDecl= 0 +    endif +endfunc diff --git a/.vim/autoload/omni/cpp/tokenizer.vim b/.vim/autoload/omni/cpp/tokenizer.vim new file mode 100644 index 0000000..16e0be2 --- /dev/null +++ b/.vim/autoload/omni/cpp/tokenizer.vim @@ -0,0 +1,93 @@ +" Description: Omni completion tokenizer +" Maintainer:  Vissale NEANG +" Last Change: 26 sept. 2007 +" TODO: Generic behaviour for Tokenize() + +" From the C++ BNF +let s:cppKeyword = ['asm', 'auto', 'bool', 'break', 'case', 'catch', 'char', 'class', 'const', 'const_cast', 'continue', 'default', 'delete', 'do', 'double', 'dynamic_cast', 'else', 'enum', 'explicit', 'export', 'extern', 'false', 'float', 'for', 'friend', 'goto', 'if', 'inline', 'int', 'long', 'mutable', 'namespace', 'new', 'operator', 'private', 'protected', 'public', 'register', 'reinterpret_cast', 'return', 'short', 'signed', 'sizeof', 'static', 'static_cast', 'struct', 'switch', 'template', 'this', 'throw', 'true', 'try', 'typedef', 'typeid', 'typename', 'union', 'unsigned', 'using', 'virtual', 'void', 'volatile', 'wchar_t', 'while', 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not', 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'] + +let s:reCppKeyword = '\C\<'.join(s:cppKeyword, '\>\|\<').'\>' + +" The order of items in this list is very important because we use this list to build a regular +" expression (see below) for tokenization +let s:cppOperatorPunctuator = ['->*', '->', '--', '-=', '-', '!=', '!', '##', '#', '%:%:', '%=', '%>', '%:', '%', '&&', '&=', '&', '(', ')', '*=', '*', ',', '...', '.*', '.', '/=', '/', '::', ':>', ':', ';', '?', '[', ']', '^=', '^', '{', '||', '|=', '|', '}', '~', '++', '+=', '+', '<<=', '<%', '<:', '<<', '<=', '<', '==', '=', '>>=', '>>', '>=', '>'] + +" We build the regexp for the tokenizer +let s:reCComment = '\/\*\|\*\/' +let s:reCppComment = '\/\/' +let s:reComment = s:reCComment.'\|'.s:reCppComment +let s:reCppOperatorOrPunctuator = escape(join(s:cppOperatorPunctuator, '\|'), '*./^~[]') + + +" Tokenize a c++ code +" a token is dictionary where keys are: +"   -   kind = cppKeyword|cppWord|cppOperatorPunctuator|unknown|cComment|cppComment|cppDigit +"   -   value = 'something' +"   Note: a cppWord is any word that is not a cpp keyword +function! omni#cpp#tokenizer#Tokenize(szCode) +    let result = [] + +    " The regexp to find a token, a token is a keyword, word or +    " c++ operator or punctuator. To work properly we have to put  +    " spaces and tabs to our regexp. +    let reTokenSearch = '\(\w\+\)\|\s\+\|'.s:reComment.'\|'.s:reCppOperatorOrPunctuator +    " eg: 'using namespace std;' +    "      ^    ^ +    "  start=0 end=5 +    let startPos = 0 +    let endPos = matchend(a:szCode, reTokenSearch) +    let len = endPos-startPos +    while endPos!=-1 +        " eg: 'using namespace std;' +        "      ^    ^ +        "  start=0 end=5 +        "  token = 'using' +        " We also remove space and tabs +        let token = substitute(strpart(a:szCode, startPos, len), '\s', '', 'g') + +        " eg: 'using namespace std;' +        "           ^         ^ +        "       start=5     end=15 +        let startPos = endPos +        let endPos = matchend(a:szCode, reTokenSearch, startPos) +        let len = endPos-startPos + +        " It the token is empty we continue +        if token=='' +            continue +        endif + +        " Building the token +        let resultToken = {'kind' : 'unknown', 'value' : token} + +        " Classify the token +        if token =~ '^\d\+' +            " It's a digit +            let resultToken.kind = 'cppDigit' +        elseif token=~'^\w\+$' +            " It's a word +            let resultToken.kind = 'cppWord' + +            " But maybe it's a c++ keyword +            if match(token, s:reCppKeyword)>=0 +                let resultToken.kind = 'cppKeyword' +            endif +        else +            if match(token, s:reComment)>=0 +                if index(['/*','*/'],token)>=0 +                    let resultToken.kind = 'cComment' +                else +                    let resultToken.kind = 'cppComment' +                endif +            else +                " It's an operator +                let resultToken.kind = 'cppOperatorPunctuator' +            endif +        endif + +        " We have our token, let's add it to the result list +        call extend(result, [resultToken]) +    endwhile + +    return result +endfunc diff --git a/.vim/autoload/omni/cpp/utils.vim b/.vim/autoload/omni/cpp/utils.vim new file mode 100644 index 0000000..5d74d34 --- /dev/null +++ b/.vim/autoload/omni/cpp/utils.vim @@ -0,0 +1,587 @@ +" Description: Omni completion script for cpp files +" Maintainer:  Vissale NEANG +" Last Change: 26 sept. 2007 + +let g:omni#cpp#utils#CACHE_TAG_INHERITS = {} +let g:omni#cpp#utils#szFilterGlobalScope = "(!has_key(v:val, 'class') && !has_key(v:val, 'struct') && !has_key(v:val, 'union') && !has_key(v:val, 'namespace')" +let g:omni#cpp#utils#szFilterGlobalScope .= "&& (!has_key(v:val, 'enum') || (has_key(v:val, 'enum') && v:val.enum =~ '^\\w\\+$')))" + +" Expression used to ignore comments +" Note: this expression drop drastically the performance +"let omni#cpp#utils#expIgnoreComments = 'match(synIDattr(synID(line("."), col("."), 1), "name"), '\CcComment')!=-1' +" This one is faster but not really good for C comments +let omni#cpp#utils#reIgnoreComment = escape('\/\/\|\/\*\|\*\/', '*/\') +let omni#cpp#utils#expIgnoreComments = 'getline(".") =~ g:omni#cpp#utils#reIgnoreComment' + +" Characters to escape in a filename for vimgrep +"TODO: Find more characters to escape +let omni#cpp#utils#szEscapedCharacters = ' %#' + +" Resolve the path of the file +" TODO: absolute file path +function! omni#cpp#utils#ResolveFilePath(szFile) +    let result = '' +    let listPath = split(globpath(&path, a:szFile), "\n") +    if len(listPath) +        let result = listPath[0] +    endif +    return simplify(result) +endfunc + +" Get code without comments and with empty strings +" szSingleLine must not have carriage return +function! omni#cpp#utils#GetCodeFromLine(szSingleLine) +    " We set all strings to empty strings, it's safer for  +    " the next of the process +    let szResult = substitute(a:szSingleLine, '".*"', '""', 'g') + +    " Removing c++ comments, we can use the pattern ".*" because +    " we are modifying a line +    let szResult = substitute(szResult, '\/\/.*', '', 'g') + +    " Now we have the entire code in one line and we can remove C comments +    return s:RemoveCComments(szResult) +endfunc + +" Remove C comments on a line +function! s:RemoveCComments(szLine) +    let result = a:szLine + +    " We have to match the first '/*' and first '*/' +    let startCmt = match(result, '\/\*') +    let endCmt = match(result, '\*\/') +    while startCmt!=-1 && endCmt!=-1 && startCmt<endCmt +        if startCmt>0 +            let result = result[ : startCmt-1 ] . result[ endCmt+2 : ] +        else +            " Case where '/*' is at the start of the line +            let result = result[ endCmt+2 : ] +        endif +        let startCmt = match(result, '\/\*') +        let endCmt = match(result, '\*\/') +    endwhile +    return result +endfunc + +" Get a c++ code from current buffer from [lineStart, colStart] to  +" [lineEnd, colEnd] without c++ and c comments, without end of line +" and with empty strings if any +" @return a string +function! omni#cpp#utils#GetCode(posStart, posEnd) +    let posStart = a:posStart +    let posEnd = a:posEnd +    if a:posStart[0]>a:posEnd[0] +        let posStart = a:posEnd +        let posEnd = a:posStart +    elseif a:posStart[0]==a:posEnd[0] && a:posStart[1]>a:posEnd[1] +        let posStart = a:posEnd +        let posEnd = a:posStart +    endif + +    " Getting the lines +    let lines = getline(posStart[0], posEnd[0]) +    let lenLines = len(lines) + +    " Formatting the result +    let result = '' +    if lenLines==1 +        let sStart = posStart[1]-1 +        let sEnd = posEnd[1]-1 +        let line = lines[0] +        let lenLastLine = strlen(line) +        let sEnd = (sEnd>lenLastLine)?lenLastLine : sEnd +        if sStart >= 0 +            let result = omni#cpp#utils#GetCodeFromLine(line[ sStart : sEnd ]) +        endif +    elseif lenLines>1 +        let sStart = posStart[1]-1 +        let sEnd = posEnd[1]-1 +        let lenLastLine = strlen(lines[-1]) +        let sEnd = (sEnd>lenLastLine)?lenLastLine : sEnd +        if sStart >= 0 +            let lines[0] = lines[0][ sStart : ] +            let lines[-1] = lines[-1][ : sEnd ] +            for aLine in lines +                let result = result . omni#cpp#utils#GetCodeFromLine(aLine)." " +            endfor +            let result = result[:-2] +        endif +    endif + +    " Now we have the entire code in one line and we can remove C comments +    return s:RemoveCComments(result) +endfunc + +" Extract the scope (context) of a tag item +" eg: ::MyNamespace +" @return a string of the scope. a scope from tag always starts with '::' +function! omni#cpp#utils#ExtractScope(tagItem) +    let listKindScope = ['class', 'struct', 'union', 'namespace', 'enum'] +    let szResult = '::' +    for scope in listKindScope +        if has_key(a:tagItem, scope) +            let szResult = szResult . a:tagItem[scope] +            break +        endif +    endfor +    return szResult +endfunc + +" Simplify scope string, remove consecutive '::' if any +function! omni#cpp#utils#SimplifyScope(szScope) +    let szResult = substitute(a:szScope, '\(::\)\+', '::', 'g') +    if szResult=='::' +        return szResult +    else +        return substitute(szResult, '::$', '', 'g') +    endif +endfunc + +" Check if the cursor is in comment +function! omni#cpp#utils#IsCursorInCommentOrString() +    return match(synIDattr(synID(line("."), col(".")-1, 1), "name"), '\C\<cComment\|\<cCppString\|\<cIncluded')>=0 +endfunc + +" Tokenize the current instruction until the cursor position. +" @return list of tokens +function! omni#cpp#utils#TokenizeCurrentInstruction(...) +    let szAppendText = '' +    if a:0>0 +        let szAppendText = a:1 +    endif + +    let startPos = searchpos('[;{}]\|\%^', 'bWn') +    let curPos = getpos('.')[1:2] +    " We don't want the character under the cursor +    let column = curPos[1]-1 +    let curPos[1] = (column<1)?1:column +    return omni#cpp#tokenizer#Tokenize(omni#cpp#utils#GetCode(startPos, curPos)[1:] . szAppendText) +endfunc + +" Tokenize the current instruction until the word under the cursor. +" @return list of tokens +function! omni#cpp#utils#TokenizeCurrentInstructionUntilWord() +    let startPos = searchpos('[;{}]\|\%^', 'bWn') + +    " Saving the current cursor pos +    let originalPos = getpos('.') + +    " We go at the end of the word +    execute 'normal gee' +    let curPos = getpos('.')[1:2] + +    " Restoring the original cursor pos +    call setpos('.', originalPos) + +    let szCode = omni#cpp#utils#GetCode(startPos, curPos)[1:] +    return omni#cpp#tokenizer#Tokenize(szCode) +endfunc + +" Build parenthesis groups +" add a new key 'group' in the token +" where value is the group number of the parenthesis +" eg: (void*)(MyClass*) +"      group1  group0 +" if a parenthesis is unresolved the group id is -1       +" @return a copy of a:tokens with parenthesis group +function! omni#cpp#utils#BuildParenthesisGroups(tokens) +    let tokens = copy(a:tokens) +    let kinds = {'(': '()', ')' : '()', '[' : '[]', ']' : '[]', '<' : '<>', '>' : '<>', '{': '{}', '}': '{}'} +    let unresolved = {'()' : [], '[]': [], '<>' : [], '{}' : []} +    let groupId = 0 + +    " Note: we build paren group in a backward way +    " because we can often have parenthesis unbalanced +    " instruction +    " eg: doSomething(_member.get()-> +    for token in reverse(tokens) +        if index([')', ']', '>', '}'], token.value)>=0 +            let token['group'] = groupId +            call extend(unresolved[kinds[token.value]], [token]) +            let groupId+=1 +        elseif index(['(', '[', '<', '{'], token.value)>=0 +            if len(unresolved[kinds[token.value]]) +                let tokenResolved = remove(unresolved[kinds[token.value]], -1) +                let token['group'] = tokenResolved.group +            else +                let token['group'] = -1 +            endif +        endif +    endfor + +    return reverse(tokens) +endfunc + +" Determine if tokens represent a C cast +" @return +"   - itemCast +"   - itemCppCast +"   - itemVariable +"   - itemThis +function! omni#cpp#utils#GetCastType(tokens) +    " Note: a:tokens is not modified +    let tokens = omni#cpp#utils#SimplifyParenthesis(omni#cpp#utils#BuildParenthesisGroups(a:tokens)) + +    if tokens[0].value == '(' +        return 'itemCast'  +    elseif index(['static_cast', 'dynamic_cast', 'reinterpret_cast', 'const_cast'], tokens[0].value)>=0 +        return 'itemCppCast' +    else +        for token in tokens +            if token.value=='this' +                return 'itemThis' +            endif +        endfor +        return 'itemVariable'  +    endif +endfunc + +" Remove useless parenthesis +function! omni#cpp#utils#SimplifyParenthesis(tokens) +    "Note: a:tokens is not modified +    let tokens = a:tokens +    " We remove useless parenthesis eg: (((MyClass))) +    if len(tokens)>2 +        while tokens[0].value=='(' && tokens[-1].value==')' && tokens[0].group==tokens[-1].group +            let tokens = tokens[1:-2] +        endwhile +    endif +    return tokens +endfunc + +" Function create a type info +function! omni#cpp#utils#CreateTypeInfo(param) +    let type = type(a:param) +    return {'type': type, 'value':a:param} +endfunc + +" Extract type info from a tag item +" eg: ::MyNamespace::MyClass +function! omni#cpp#utils#ExtractTypeInfoFromTag(tagItem) +    let szTypeInfo = omni#cpp#utils#ExtractScope(a:tagItem) . '::' . substitute(a:tagItem.name, '.*::', '', 'g') +    return omni#cpp#utils#SimplifyScope(szTypeInfo) +endfunc + +" Build a class inheritance list +function! omni#cpp#utils#GetClassInheritanceList(namespaces, typeInfo) +    let result = [] +    for tagItem in omni#cpp#utils#GetResolvedTags(a:namespaces, a:typeInfo) +        call extend(result, [omni#cpp#utils#ExtractTypeInfoFromTag(tagItem)]) +    endfor +    return result +endfunc + +" Get class inheritance list where items in the list are tag items. +" TODO: Verify inheritance order +function! omni#cpp#utils#GetResolvedTags(namespaces, typeInfo) +    let result = [] +    let tagItem = omni#cpp#utils#GetResolvedTagItem(a:namespaces, a:typeInfo) +    if tagItem!={} +        let szTypeInfo = omni#cpp#utils#ExtractTypeInfoFromTag(tagItem) +        if has_key(g:omni#cpp#utils#CACHE_TAG_INHERITS, szTypeInfo) +            let result = g:omni#cpp#utils#CACHE_TAG_INHERITS[szTypeInfo] +        else +            call extend(result, [tagItem]) +            if has_key(tagItem, 'inherits') +                for baseClassTypeInfo in split(tagItem.inherits, ',') +                    let namespaces = [omni#cpp#utils#ExtractScope(tagItem), '::'] +                    call extend(result, omni#cpp#utils#GetResolvedTags(namespaces, omni#cpp#utils#CreateTypeInfo(baseClassTypeInfo))) +                endfor +            endif +            let g:omni#cpp#utils#CACHE_TAG_INHERITS[szTypeInfo] = result +        endif +    endif +    return result +endfunc + +" Get a tag item after a scope resolution and typedef resolution +function! omni#cpp#utils#GetResolvedTagItem(namespaces, typeInfo) +    let typeInfo = {} +    if type(a:typeInfo) == 1 +        let typeInfo = omni#cpp#utils#CreateTypeInfo(a:typeInfo) +    else +        let typeInfo = a:typeInfo +    endif + +    let result = {} +    if !omni#cpp#utils#IsTypeInfoValid(typeInfo) +        return result +    endif + +    " Unnamed type case eg: '1::2' +    if typeInfo.type == 4 +        " Here there is no typedef or namespace to resolve, the tagInfo.value is a tag item +        " representing a variable ('v') a member ('m') or a typedef ('t') and the typename is +        " always in global scope +        return typeInfo.value +    endif + +    " Named type case eg:  'MyNamespace::MyClass' +    let szTypeInfo = omni#cpp#utils#GetTypeInfoString(typeInfo) + +    " Resolving namespace alias +    " TODO: For the next release +    "let szTypeInfo = omni#cpp#namespaces#ResolveAlias(g:omni#cpp#namespaces#CacheAlias, szTypeInfo) + +    if szTypeInfo=='::' +        return result +    endif + +    " We can only get members of class, struct, union and namespace +    let szTagFilter = "index(['c', 's', 'u', 'n', 't'], v:val.kind[0])>=0" +    let szTagQuery = szTypeInfo + +    if s:IsTypeInfoResolved(szTypeInfo) +        " The type info is already resolved, we remove the starting '::' +        let szTagQuery = substitute(szTypeInfo, '^::', '', 'g') +        if len(split(szTagQuery, '::'))==1 +            " eg: ::MyClass +            " Here we have to get tags that have no parent scope +            " That's why we change the szTagFilter +            let szTagFilter .= '&& ' . g:omni#cpp#utils#szFilterGlobalScope +            let tagList = omni#common#utils#TagListNoThrow('^'.szTagQuery.'$') +            call filter(tagList, szTagFilter) +            if len(tagList) +                let result = tagList[0] +            endif +        else +            " eg: ::MyNamespace::MyClass +            let tagList = omni#common#utils#TagListNoThrow('^'.szTagQuery.'$') +            call filter(tagList, szTagFilter) + +            if len(tagList) +                let result = tagList[0] +            endif +        endif +    else +        " The type is not resolved +        let tagList = omni#common#utils#TagListNoThrow('^'.szTagQuery.'$') +        call filter(tagList, szTagFilter) + +        if len(tagList) +            " Resolving scope (namespace, nested class etc...) +            let szScopeOfTypeInfo = s:ExtractScopeFromTypeInfo(szTypeInfo) +            if s:IsTypeInfoResolved(szTypeInfo) +                let result = s:GetTagOfSameScope(tagList, szScopeOfTypeInfo) +            else +                " For each namespace of the namespace list we try to get a tag +                " that can be in the same scope +                if g:OmniCpp_NamespaceSearch && &filetype != 'c' +                    for scope in a:namespaces +                        let szTmpScope = omni#cpp#utils#SimplifyScope(scope.'::'.szScopeOfTypeInfo) +                        let result = s:GetTagOfSameScope(tagList, szTmpScope) +                        if result!={} +                            break +                        endif +                    endfor +                else +                    let szTmpScope = omni#cpp#utils#SimplifyScope('::'.szScopeOfTypeInfo) +                    let result = s:GetTagOfSameScope(tagList, szTmpScope) +                endif +            endif +        endif +    endif + +    if result!={} +        " We have our tagItem but maybe it's a typedef or an unnamed type +        if result.kind[0]=='t' +            " Here we can have a typedef to another typedef, a class, struct, union etc +            " but we can also have a typedef to an unnamed type, in that +            " case the result contains a 'typeref' key +            let namespaces = [omni#cpp#utils#ExtractScope(result), '::'] +            if has_key(result, 'typeref') +                let result = omni#cpp#utils#GetResolvedTagItem(namespaces, omni#cpp#utils#CreateTypeInfo(result)) +            else +                let szCmd = omni#cpp#utils#ExtractCmdFromTagItem(result) +                let szCode = substitute(omni#cpp#utils#GetCodeFromLine(szCmd), '\C\<'.result.name.'\>.*', '', 'g') +                let szTypeInfo = omni#cpp#utils#ExtractTypeInfoFromTokens(omni#cpp#tokenizer#Tokenize(szCode)) +                let result = omni#cpp#utils#GetResolvedTagItem(namespaces, omni#cpp#utils#CreateTypeInfo(szTypeInfo)) +                " TODO: Namespace resolution for result +            endif +        endif +    endif + +    return result +endfunc + +" Returns if the type info is valid +" @return +"   - 1 if valid +"   - 0 otherwise +function! omni#cpp#utils#IsTypeInfoValid(typeInfo) +    if a:typeInfo=={} +        return 0 +    else +        if a:typeInfo.type == 1 && a:typeInfo.value=='' +            " String case +            return 0 +        elseif a:typeInfo.type == 4 && a:typeInfo.value=={} +            " Dictionary case +            return 0 +        endif +    endif +    return 1 +endfunc + +" Get the string of the type info +function! omni#cpp#utils#GetTypeInfoString(typeInfo) +    if a:typeInfo.type == 1 +        return a:typeInfo.value +    else +        return substitute(a:typeInfo.value.typeref, '^\w\+:', '', 'g') +    endif +endfunc + +" A resolved type info starts with '::' +" @return +"   - 1 if type info starts with '::' +"   - 0 otherwise +function! s:IsTypeInfoResolved(szTypeInfo) +    return match(a:szTypeInfo, '^::')!=-1 +endfunc + +" A returned type info's scope may not have the global namespace '::' +" eg: '::NameSpace1::NameSpace2::MyClass' => '::NameSpace1::NameSpace2' +" 'NameSpace1::NameSpace2::MyClass' => 'NameSpace1::NameSpace2' +function! s:ExtractScopeFromTypeInfo(szTypeInfo) +    let szScope = substitute(a:szTypeInfo, '\w\+$', '', 'g') +    if szScope =='::' +        return szScope +    else +        return substitute(szScope, '::$', '', 'g') +    endif +endfunc + +" @return +"   -   the tag with the same scope +"   -   {} otherwise +function! s:GetTagOfSameScope(listTags, szScopeToMatch) +    for tagItem in a:listTags  +        let szScopeOfTag = omni#cpp#utils#ExtractScope(tagItem) +        if szScopeOfTag == a:szScopeToMatch +            return tagItem +        endif +    endfor +    return {} +endfunc + +" Extract the cmd of a tag item without regexp +function! omni#cpp#utils#ExtractCmdFromTagItem(tagItem) +    let line = a:tagItem.cmd +    let re = '\(\/\^\)\|\(\$\/\)' +    if match(line, re)!=-1 +        let line = substitute(line, re, '', 'g') +        return line +    else +        " TODO: the cmd is a line number +        return '' +    endif +endfunc + +" Extract type from tokens. +" eg: examples of tokens format +"   'const MyClass&' +"   'const map < int, int >&' +"   'MyNs::MyClass' +"   '::MyClass**' +"   'MyClass a, *b = NULL, c[1] = {}; +"   'hello(MyClass a, MyClass* b' +" @return the type info string eg: ::std::map +" can be empty +function! omni#cpp#utils#ExtractTypeInfoFromTokens(tokens) +    let szResult = '' +    let state = 0 + +    let tokens = omni#cpp#utils#BuildParenthesisGroups(a:tokens) + +    " If there is an unbalanced parenthesis we are in a parameter list +    let bParameterList = 0 +    for token in tokens +        if token.value == '(' && token.group==-1 +            let bParameterList = 1 +            break +        endif +    endfor + +    if bParameterList +        let tokens = reverse(tokens) +        let state = 0 +        let parenGroup = -1 +        for token in tokens +            if state==0 +                if token.value=='>' +                    let parenGroup = token.group +                    let state=1 +                elseif token.kind == 'cppWord' +                    let szResult = token.value.szResult +                    let state=2 +                elseif index(['*', '&'], token.value)<0 +                    break +                endif +            elseif state==1 +                if token.value=='<' && token.group==parenGroup +                    let state=0 +                endif +            elseif state==2 +                if token.value=='::' +                    let szResult = token.value.szResult +                    let state=3 +                else +                    break +                endif +            elseif state==3 +                if token.kind == 'cppWord' +                    let szResult = token.value.szResult +                    let state=2 +                else +                    break +                endif +            endif +        endfor +        return szResult +    endif + +    for token in tokens +        if state==0 +            if token.value == '::' +                let szResult .= token.value +                let state = 1 +            elseif token.kind == 'cppWord' +                let szResult .= token.value +                let state = 2 +                " Maybe end of token +            endif +        elseif state==1 +            if token.kind == 'cppWord' +                let szResult .= token.value +                let state = 2 +                " Maybe end of token +            else +                break +            endif +        elseif state==2 +            if token.value == '::' +                let szResult .= token.value +                let state = 1 +            else +                break +            endif +        endif +    endfor +    return szResult +endfunc + +" Get the preview window string +function! omni#cpp#utils#GetPreviewWindowStringFromTagItem(tagItem) +    let szResult = '' + +    let szResult .= 'name: '.a:tagItem.name."\n" +    for tagKey in keys(a:tagItem) +        if index(['name', 'static'], tagKey)>=0 +            continue +        endif +        let szResult .= tagKey.': '.a:tagItem[tagKey]."\n" +    endfor + +    return substitute(szResult, "\n$", '', 'g') +endfunc | 
