summaryrefslogtreecommitdiff
path: root/.vim/autoload/omni/cpp/items.vim
diff options
context:
space:
mode:
Diffstat (limited to '.vim/autoload/omni/cpp/items.vim')
-rw-r--r--.vim/autoload/omni/cpp/items.vim660
1 files changed, 660 insertions, 0 deletions
diff --git a/.vim/autoload/omni/cpp/items.vim b/.vim/autoload/omni/cpp/items.vim
new file mode 100644
index 0000000..b943ad4
--- /dev/null
+++ b/.vim/autoload/omni/cpp/items.vim
@@ -0,0 +1,660 @@
+" Description: Omni completion script for cpp files
+" Maintainer: Vissale NEANG
+" Last Change: 26 sept. 2007
+
+" Build the item list of an instruction
+" An item is an instruction between a -> or . or ->* or .*
+" We can sort an item in different kinds:
+" eg: ((MyClass1*)(pObject))->_memberOfClass1.get() ->show()
+" | cast | | member | | method | | method |
+" @return a list of item
+" an item is a dictionnary where keys are:
+" tokens = list of token
+" kind = itemVariable|itemCast|itemCppCast|itemTemplate|itemFunction|itemUnknown|itemThis|itemScope
+function! omni#cpp#items#Get(tokens, ...)
+ let bGetWordUnderCursor = (a:0>0)? a:1 : 0
+
+ let result = []
+ let itemsDelimiters = ['->', '.', '->*', '.*']
+
+ let tokens = reverse(omni#cpp#utils#BuildParenthesisGroups(a:tokens))
+
+ " fsm states:
+ " 0 = initial state
+ " TODO: add description of fsm states
+ let state=(bGetWordUnderCursor)? 1 : 0
+ let item = {'tokens' : [], 'kind' : 'itemUnknown'}
+ let parenGroup=-1
+ for token in tokens
+ if state==0
+ if index(itemsDelimiters, token.value)>=0
+ let item = {'tokens' : [], 'kind' : 'itemUnknown'}
+ let state = 1
+ elseif token.value=='::'
+ let state = 9
+ let item.kind = 'itemScope'
+ " Maybe end of tokens
+ elseif token.kind =='cppOperatorPunctuator'
+ " If it's a cppOperatorPunctuator and the current token is not
+ " a itemsDelimiters or '::' we can exit
+ let state=-1
+ break
+ endif
+ elseif state==1
+ call insert(item.tokens, token)
+ if token.kind=='cppWord'
+ " It's an attribute member or a variable
+ let item.kind = 'itemVariable'
+ let state = 2
+ " Maybe end of tokens
+ elseif token.value=='this'
+ let item.kind = 'itemThis'
+ let state = 2
+ " Maybe end of tokens
+ elseif token.value==')'
+ let parenGroup = token.group
+ let state = 3
+ elseif token.value==']'
+ let parenGroup = token.group
+ let state = 4
+ elseif token.kind == 'cppDigit'
+ let state = -1
+ break
+ endif
+ elseif state==2
+ if index(itemsDelimiters, token.value)>=0
+ call insert(result, item)
+ let item = {'tokens' : [], 'kind' : 'itemUnknown'}
+ let state = 1
+ elseif token.value == '::'
+ call insert(item.tokens, token)
+ " We have to get namespace or classscope
+ let state = 8
+ " Maybe end of tokens
+ else
+ call insert(result, item)
+ let state=-1
+ break
+ endif
+ elseif state==3
+ call insert(item.tokens, token)
+ if token.value=='(' && token.group == parenGroup
+ let state = 5
+ " Maybe end of tokens
+ endif
+ elseif state==4
+ call insert(item.tokens, token)
+ if token.value=='[' && token.group == parenGroup
+ let state = 1
+ endif
+ elseif state==5
+ if token.kind=='cppWord'
+ " It's a function or method
+ let item.kind = 'itemFunction'
+ call insert(item.tokens, token)
+ let state = 2
+ " Maybe end of tokens
+ elseif token.value == '>'
+ " Maybe a cpp cast or template
+ let item.kind = 'itemTemplate'
+ call insert(item.tokens, token)
+ let parenGroup = token.group
+ let state = 6
+ else
+ " Perhaps it's a C cast eg: ((void*)(pData)) or a variable eg:(*pData)
+ let item.kind = omni#cpp#utils#GetCastType(item.tokens)
+ let state=-1
+ call insert(result, item)
+ break
+ endif
+ elseif state==6
+ call insert(item.tokens, token)
+ if token.value == '<' && token.group == parenGroup
+ " Maybe a cpp cast or template
+ let state = 7
+ endif
+ elseif state==7
+ call insert(item.tokens, token)
+ if token.kind=='cppKeyword'
+ " It's a cpp cast
+ let item.kind = omni#cpp#utils#GetCastType(item.tokens)
+ let state=-1
+ call insert(result, item)
+ break
+ else
+ " Template ?
+ let state=-1
+ call insert(result, item)
+ break
+ endif
+ elseif state==8
+ if token.kind=='cppWord'
+ call insert(item.tokens, token)
+ let state = 2
+ " Maybe end of tokens
+ else
+ let state=-1
+ call insert(result, item)
+ break
+ endif
+ elseif state==9
+ if token.kind == 'cppWord'
+ call insert(item.tokens, token)
+ let state = 10
+ " Maybe end of tokens
+ else
+ let state=-1
+ call insert(result, item)
+ break
+ endif
+ elseif state==10
+ if token.value == '::'
+ call insert(item.tokens, token)
+ let state = 9
+ " Maybe end of tokens
+ else
+ let state=-1
+ call insert(result, item)
+ break
+ endif
+ endif
+ endfor
+
+ if index([2, 5, 8, 9, 10], state)>=0
+ if state==5
+ let item.kind = omni#cpp#utils#GetCastType(item.tokens)
+ endif
+ call insert(result, item)
+ endif
+
+ return result
+endfunc
+
+" Resolve type information of items
+" @param namespaces: list of namespaces used in the file
+" @param szCurrentClassScope: the current class scope, only used for the first
+" item to detect if this item is a class member (attribute, method)
+" @param items: list of item, can be an empty list @see GetItemsToComplete
+function! omni#cpp#items#ResolveItemsTypeInfo(contextStack, items)
+ " Note: kind = itemVariable|cCast|cppCast|template|function|itemUnknown|this
+ " For the first item, if it's a variable we try to detect the type of the
+ " variable with the function searchdecl. If it fails, thanks to the
+ " current class scope, we try to detect if the variable is an attribute
+ " member.
+ " If the kind of the item is a function, we have to first check if the
+ " function is a method of the class, if it fails we try to get a match in
+ " the global namespace. After that we get the returned type of the
+ " function.
+ " It the kind is a C cast or C++ cast, there is no problem, it's the
+ " easiest case. We just extract the type of the cast.
+
+ let szCurrentContext = ''
+ let typeInfo = {}
+ " Note: We search the decl only for the first item
+ let bSearchDecl = 1
+ for item in a:items
+ let curItem = item
+ if index(['itemVariable', 'itemFunction'], curItem.kind)>=0
+ " Note: a variable can be : MyNs::MyClass::_var or _var or (*pVar)
+ " or _var[0][0]
+ let szSymbol = s:GetSymbol(curItem.tokens)
+
+ " If we have MyNamespace::myVar
+ " We add MyNamespace in the context stack set szSymbol to myVar
+ if match(szSymbol, '::\w\+$') >= 0
+ let szCurrentContext = substitute(szSymbol, '::\w\+$', '', 'g')
+ let szSymbol = matchstr(szSymbol, '\w\+$')
+ endif
+ let tmpContextStack = a:contextStack
+ if szCurrentContext != ''
+ let tmpContextStack = [szCurrentContext] + a:contextStack
+ endif
+
+ if curItem.kind == 'itemVariable'
+ let typeInfo = s:GetTypeInfoOfVariable(tmpContextStack, szSymbol, bSearchDecl)
+ else
+ let typeInfo = s:GetTypeInfoOfReturnedType(tmpContextStack, szSymbol)
+ endif
+
+ elseif curItem.kind == 'itemThis'
+ if len(a:contextStack)
+ let typeInfo = omni#cpp#utils#CreateTypeInfo(substitute(a:contextStack[0], '^::', '', 'g'))
+ endif
+ elseif curItem.kind == 'itemCast'
+ let typeInfo = omni#cpp#utils#CreateTypeInfo(s:ResolveCCast(curItem.tokens))
+ elseif curItem.kind == 'itemCppCast'
+ let typeInfo = omni#cpp#utils#CreateTypeInfo(s:ResolveCppCast(curItem.tokens))
+ elseif curItem.kind == 'itemScope'
+ let typeInfo = omni#cpp#utils#CreateTypeInfo(substitute(s:TokensToString(curItem.tokens), '\s', '', 'g'))
+ endif
+
+ if omni#cpp#utils#IsTypeInfoValid(typeInfo)
+ let szCurrentContext = omni#cpp#utils#GetTypeInfoString(typeInfo)
+ endif
+ let bSearchDecl = 0
+ endfor
+
+ return typeInfo
+endfunc
+
+" Get symbol name
+function! s:GetSymbol(tokens)
+ let szSymbol = ''
+ let state = 0
+ for token in a:tokens
+ if state == 0
+ if token.value == '::'
+ let szSymbol .= token.value
+ let state = 1
+ elseif token.kind == 'cppWord'
+ let szSymbol .= token.value
+ let state = 2
+ " Maybe end of token
+ endif
+ elseif state == 1
+ if token.kind == 'cppWord'
+ let szSymbol .= token.value
+ let state = 2
+ " Maybe end of token
+ else
+ " Error
+ break
+ endif
+ elseif state == 2
+ if token.value == '::'
+ let szSymbol .= token.value
+ let state = 1
+ else
+ break
+ endif
+ endif
+ endfor
+ return szSymbol
+endfunc
+
+" Search a declaration.
+" eg: std::map
+" can be empty
+" Note: The returned type info can be a typedef
+" The typedef resolution is done later
+" @return
+" - a dictionnary where keys are
+" - type: the type of value same as type()
+" - value: the value
+function! s:GetTypeInfoOfVariable(contextStack, szVariable, bSearchDecl)
+ let result = {}
+
+ if a:bSearchDecl
+ " Search type of declaration
+ "let result = s:SearchTypeInfoOfDecl(a:szVariable)
+ let result = s:SearchDecl(a:szVariable)
+ endif
+
+ if result=={}
+ let szFilter = "index(['m', 'v'], v:val.kind[0])>=0"
+ let tagItem = s:ResolveSymbol(a:contextStack, a:szVariable, szFilter)
+ if tagItem=={}
+ return result
+ endif
+
+ let szCmdWithoutVariable = substitute(omni#cpp#utils#ExtractCmdFromTagItem(tagItem), '\C\<'.a:szVariable.'\>.*', '', 'g')
+ let tokens = omni#cpp#tokenizer#Tokenize(omni#cpp#utils#GetCodeFromLine(szCmdWithoutVariable))
+ let result = omni#cpp#utils#CreateTypeInfo(omni#cpp#utils#ExtractTypeInfoFromTokens(tokens))
+ " TODO: Namespace resolution for result
+
+ if result != {} && result.value==''
+ " result.value==''
+ " eg:
+ " struct
+ " {
+ " }gVariable;
+ if has_key(tagItem, 'typeref')
+ " Maybe the variable is a global var of an
+ " unnamed class, struct or union.
+ " eg:
+ " 1)
+ " struct
+ " {
+ " }gVariable;
+ " In this case we need the tags (the patched version)
+ " Note: We can have a named type like this:
+ " 2)
+ " class A
+ " {
+ " }gVariable;
+ if s:IsUnnamedType(tagItem)
+ " It's an unnamed type we are in the case 1)
+ let result = omni#cpp#utils#CreateTypeInfo(tagItem)
+ else
+ " It's not an unnamed type we are in the case 2)
+
+ " eg: tagItem.typeref = 'struct:MY_STRUCT::MY_SUBSTRUCT'
+ let szTypeRef = substitute(tagItem.typeref, '^\w\+:', '', '')
+
+ " eg: szTypeRef = 'MY_STRUCT::MY_SUBSTRUCT'
+ let result = omni#cpp#utils#CreateTypeInfo(szTypeRef)
+ endif
+ endif
+ endif
+ endif
+ return result
+endfunc
+
+" Get the type info string from the returned type of function
+function! s:GetTypeInfoOfReturnedType(contextStack, szFunctionName)
+ let result = {}
+
+ let szFilter = "index(['f', 'p'], v:val.kind[0])>=0"
+ let tagItem = s:ResolveSymbol(a:contextStack, a:szFunctionName, szFilter)
+
+ if tagItem != {}
+ let szCmdWithoutVariable = substitute(omni#cpp#utils#ExtractCmdFromTagItem(tagItem), '\C\<'.a:szFunctionName.'\>.*', '', 'g')
+ let tokens = omni#cpp#tokenizer#Tokenize(omni#cpp#utils#GetCodeFromLine(szCmdWithoutVariable))
+ let result = omni#cpp#utils#CreateTypeInfo(omni#cpp#utils#ExtractTypeInfoFromTokens(tokens))
+ " TODO: Namespace resolution for result
+ return result
+ endif
+ return result
+endfunc
+
+" Resolve a symbol, return a tagItem
+" Gets the first symbol found in the context stack
+function! s:ResolveSymbol(contextStack, szSymbol, szTagFilter)
+ let tagItem = {}
+ for szCurrentContext in a:contextStack
+ if szCurrentContext != '::'
+ let szTagQuery = substitute(szCurrentContext, '^::', '', 'g').'::'.a:szSymbol
+ else
+ let szTagQuery = a:szSymbol
+ endif
+
+ let tagList = omni#common#utils#TagListNoThrow('^'.szTagQuery.'$')
+ call filter(tagList, a:szTagFilter)
+ if len(tagList)
+ let tagItem = tagList[0]
+ break
+ endif
+ endfor
+ return tagItem
+endfunc
+
+" Return if the tag item represent an unnamed type
+function! s:IsUnnamedType(tagItem)
+ let bResult = 0
+ if has_key(a:tagItem, 'typeref')
+ " Note: Thanks for __anon !
+ let bResult = match(a:tagItem.typeref, '\C\<__anon') >= 0
+ endif
+ return bResult
+endfunc
+
+" Search the declaration of a variable and return the type info
+function! s:SearchTypeInfoOfDecl(szVariable)
+ let szReVariable = '\C\<'.a:szVariable.'\>'
+
+ let originalPos = getpos('.')
+ let origPos = originalPos[1:2]
+ let curPos = origPos
+ let stopPos = origPos
+
+ while curPos !=[0,0]
+ " We go to the start of the current scope
+ let curPos = searchpairpos('{', '', '}', 'bW', g:omni#cpp#utils#expIgnoreComments)
+ if curPos != [0,0]
+ let matchPos = curPos
+ " Now want to search our variable but we don't want to go in child
+ " scope
+ while matchPos != [0,0]
+ let matchPos = searchpos('{\|'.szReVariable, 'W', stopPos[0])
+ if matchPos != [0,0]
+ " We ignore matches under comment
+ if omni#cpp#utils#IsCursorInCommentOrString()
+ continue
+ endif
+
+ " Getting the current line
+ let szLine = getline('.')
+ if match(szLine, szReVariable)>=0
+ " We found our variable
+ " Check if the current instruction is a decl instruction
+ let tokens = omni#cpp#utils#TokenizeCurrentInstruction()
+ let szTypeInfo = s:ExtractTypeInfoFromDecl(tokens)
+ if szTypeInfo != ''
+ call setpos('.', originalPos)
+ return omni#cpp#utils#CreateTypeInfo(szTypeInfo)
+ endif
+ else
+ " We found a child scope, we don't want to go in, thus
+ " we search for the end } of this child scope
+ let bracketEnd = searchpairpos('{', '', '}', 'nW', g:omni#cpp#utils#expIgnoreComments)
+ if bracketEnd == [0,0]
+ break
+ endif
+
+ if bracketEnd[0] >= stopPos[0]
+ " The end of the scope is after our cursor we stop
+ " the search
+ break
+ else
+ " We move the cursor and continue to search our
+ " variable
+ call setpos('.', [0, bracketEnd[0], bracketEnd[1], 0])
+ endif
+ endif
+ endif
+ endwhile
+
+ " Backing to the start of the scope
+ call setpos('.', [0,curPos[0], curPos[1], 0])
+ let stopPos = curPos
+ endif
+ endwhile
+
+ let result = {}
+ if s:LocalSearchDecl(a:szVariable)==0 && !omni#cpp#utils#IsCursorInCommentOrString()
+ let tokens = omni#cpp#utils#TokenizeCurrentInstruction()
+ let szTypeInfo = s:ExtractTypeInfoFromDecl(tokens)
+ if szTypeInfo != ''
+ let result = omni#cpp#utils#CreateTypeInfo(szTypeInfo)
+ endif
+ endif
+
+ call setpos('.', originalPos)
+
+ return result
+endfunc
+
+" Search a declaration
+" @return
+" - tokens of the current instruction if success
+" - empty list if failure
+function! s:SearchDecl(szVariable)
+ let result = {}
+ let originalPos = getpos('.')
+ let searchResult = s:LocalSearchDecl(a:szVariable)
+ if searchResult==0
+ " searchdecl() may detect a decl if the variable is in a conditional
+ " instruction (if, elseif, while etc...)
+ " We have to check if the detected decl is really a decl instruction
+ let tokens = omni#cpp#utils#TokenizeCurrentInstruction()
+
+ for token in tokens
+ " Simple test
+ if index(['if', 'elseif', 'while', 'for', 'switch'], token.value)>=0
+ " Invalid declaration instruction
+ call setpos('.', originalPos)
+ return result
+ endif
+ endfor
+
+ let szTypeInfo = s:ExtractTypeInfoFromDecl(tokens)
+ if szTypeInfo != ''
+ let result = omni#cpp#utils#CreateTypeInfo(szTypeInfo)
+ endif
+ endif
+ call setpos('.', originalPos)
+ return result
+endfunc
+
+" Extract the type info string from an instruction.
+" We use a small parser to extract the type
+" We parse the code according to a C++ BNF from: http://www.nongnu.org/hcb/#basic.link
+" @param tokens: token list of the current instruction
+function! s:ExtractTypeInfoFromDecl(tokens)
+ return omni#cpp#utils#ExtractTypeInfoFromTokens(a:tokens)
+endfunc
+
+" Convert tokens to string
+function! s:TokensToString(tokens)
+ let result = ''
+ for token in a:tokens
+ let result = result . token.value . ' '
+ endfor
+ return result[:-2]
+endfunc
+
+" Resolve a cast.
+" Resolve a C++ cast
+" @param list of token. tokens must be a list that represents
+" a cast expression (C++ cast) the function does not control
+" if it's a cast or not
+" eg: static_cast<MyClass*>(something)
+" @return type info string
+function! s:ResolveCppCast(tokens)
+ return omni#cpp#utils#ExtractTypeInfoFromTokens(s:ResolveCast(a:tokens, '<', '>'))
+endfunc
+
+" Resolve a cast.
+" Resolve a C cast
+" @param list of token. tokens must be a list that represents
+" a cast expression (C cast) the function does not control
+" if it's a cast or not
+" eg: (MyClass*)something
+" @return type info string
+function! s:ResolveCCast(tokens)
+ return omni#cpp#utils#ExtractTypeInfoFromTokens(s:ResolveCast(a:tokens, '(', ')'))
+endfunc
+
+" Resolve a cast.
+" Resolve a C cast
+" @param list of token. tokens must be a list that represents
+" a cast expression (C cast) the function does not control
+" if it's a cast or not
+" eg: (MyClass*)something
+" @return type tokens
+function! s:ResolveCast(tokens, startChar, endChar)
+ let tokens = omni#cpp#utils#BuildParenthesisGroups(a:tokens)
+
+ " We remove useless parenthesis eg: (((MyClass)))
+ let tokens = omni#cpp#utils#SimplifyParenthesis(tokens)
+
+ let countItem=0
+ let startIndex = -1
+ let endIndex = -1
+ let i = 0
+ for token in tokens
+ if startIndex==-1
+ if token.value==a:startChar
+ let countItem += 1
+ let startIndex = i
+ endif
+ else
+ if token.value==a:startChar
+ let countItem += 1
+ elseif token.value==a:endChar
+ let countItem -= 1
+ endif
+
+ if countItem==0
+ let endIndex = i
+ break
+ endif
+ endif
+ let i+=1
+ endfor
+
+ return tokens[startIndex+1 : endIndex-1]
+endfunc
+
+" Replacement for build-in function 'searchdecl'
+" It does not require that the upper-level bracket is in the first column.
+" Otherwise it should be equal to 'searchdecl(name, 0, 1)'
+" @param name: name of variable to find declaration for
+function! s:LocalSearchDecl(name)
+
+ if g:OmniCpp_LocalSearchDecl == 0
+ let bUserIgnoreCase = &ignorecase
+
+ " Forcing the noignorecase option
+ " avoid bug when, for example, if we have a declaration like this : "A a;"
+ set noignorecase
+
+ let result = searchdecl(a:name, 0, 1)
+
+ " Restoring user's setting
+ let &ignorecase = bUserIgnoreCase
+
+ return result
+ endif
+
+ let lastpos = getpos('.')
+ let winview = winsaveview()
+ let lastfoldenable = &foldenable
+ let &foldenable = 0
+
+ " We add \C (noignorecase) to
+ " avoid bug when, for example, if we have a declaration like this : "A a;"
+ let varname = "\\C\\<" . a:name . "\\>"
+
+ " Go to first blank line before begin of highest scope
+ normal 99[{
+ let scopepos = getpos('.')
+ while (line('.') > 1) && (len(split(getline('.'))) > 0)
+ call cursor(line('.')-1, 0)
+ endwhile
+
+ let declpos = [ 0, 0, 0, 0 ]
+ while search(varname, '', scopepos[1]) > 0
+ " Check if we are a string or a comment
+ if omni#cpp#utils#IsCursorInCommentOrString()
+ continue
+ endif
+
+ " Remember match
+ let declpos = getpos('.')
+ endwhile
+ if declpos[1] != 0
+ " We found a match
+ call winrestview(winview)
+ call setpos('.', declpos)
+ let &foldenable = lastfoldenable
+ return 0
+ endif
+
+ while search(varname, '', lastpos[1]) > 0
+ " Check if current scope is ending before variable
+ let old_cur = getpos('.')
+ normal ]}
+ let new_cur = getpos('.')
+ call setpos('.', old_cur)
+ if (new_cur[1] < lastpos[1]) || ((new_cur[1] == lastpos[1]) && (new_cur[2] < lastpos[2]))
+ continue
+ endif
+
+ " Check if we are a string or a comment
+ if omni#cpp#utils#IsCursorInCommentOrString()
+ continue
+ endif
+
+ " We found match
+ call winrestview(winview)
+ call setpos('.', old_cur)
+ let &foldenable = lastfoldenable
+ return 0
+ endwhile
+
+ " No match found.
+ call winrestview(winview)
+ let &foldenable = lastfoldenable
+ return 1
+endfunc