[vim]simplify omnicomplete conf
Support omnicpp with vundle Simplify conf
This commit is contained in:
parent
5d4c6b26c5
commit
d29c40e35e
@ -1,2 +0,0 @@
|
||||
" OmniCppComplete initialization
|
||||
call omni#cpp#complete#Init()
|
@ -1,2 +0,0 @@
|
||||
" OmniCppComplete initialization
|
||||
call omni#cpp#complete#Init()
|
@ -1,32 +0,0 @@
|
||||
" 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
|
@ -1,67 +0,0 @@
|
||||
" 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
|
@ -1,569 +0,0 @@
|
||||
" 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
|
@ -1,126 +0,0 @@
|
||||
" 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
|
||||
|
||||
|
@ -1,660 +0,0 @@
|
||||
" 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
|
@ -1,82 +0,0 @@
|
||||
" 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
|
@ -1,838 +0,0 @@
|
||||
" 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
|
@ -1,96 +0,0 @@
|
||||
" 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
|
@ -1,93 +0,0 @@
|
||||
" 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
|
@ -1,587 +0,0 @@
|
||||
" 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
|
1492
.vim/doc/tags
1492
.vim/doc/tags
File diff suppressed because it is too large
Load Diff
17
.vimrc
17
.vimrc
@ -369,15 +369,10 @@ nmap <S-F10> zo<CR><CR>
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
"Omni-completion par CTRL-X_CTRL-O
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
au FileType html set omnifunc=htmlcomplete#CompleteTags
|
||||
au FileType css set omnifunc=csscomplete#CompleteCSS
|
||||
au FileType javascript set omnifunc=javascriptcomplete#CompleteJS
|
||||
au FileType c set omnifunc=ccomplete#Complete
|
||||
au FileType php set omnifunc=phpcomplete#CompletePHP
|
||||
au FileType ruby set omnifunc=rubycomplete#Complete
|
||||
au FileType sql set omnifunc=sqlcomplete#Complete
|
||||
au FileType python set omnifunc=pythoncomplete#Complete
|
||||
au FileType xml set omnifunc=xmlcomplete#CompleteTags
|
||||
|
||||
filetype plugin on
|
||||
set omnifunc=syntaxcomplete#Complete
|
||||
|
||||
|
||||
" Enable omnicppcompletion
|
||||
set nocp
|
||||
@ -450,6 +445,7 @@ Plugin 'gmarik/Vundle.vim'
|
||||
Plugin 'airblade/vim-gitgutter'
|
||||
Plugin 'tpope/vim-fugitive'
|
||||
Plugin 'tpope/vim-commentary'
|
||||
|
||||
" language pack
|
||||
Plugin 'sheerun/vim-polyglot'
|
||||
" color even for terminal without gui...
|
||||
@ -483,6 +479,9 @@ Plugin 'scrooloose/nerdtree'
|
||||
"Plugin 'majutsushi/tagbar'
|
||||
"Plugin 'Yggdroot/indentLine'
|
||||
|
||||
" Omni completion for cpp
|
||||
Plugin 'vim-scripts/OmniCppComplete'
|
||||
|
||||
"Syntax checking
|
||||
Plugin 'scrooloose/syntastic.git'
|
||||
"Completion (need more configuration for python, c# ...)
|
||||
|
Loading…
Reference in New Issue
Block a user