📄 utils.vim
字号:
" Description: Omni completion script for cpp files" Maintainer: Vissale NEANG" Last Change: 25 jun 2006let 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 commentslet 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 escapelet omni#cpp#utils#szEscapedCharacters = ' %#'" Resolve the path of the file" TODO: absolute file pathfunction! 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 returnfunction! 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 linefunction! 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 resultendfunc" 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 stringfunction! 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 szResultendfunc" Simplify scope string, remove consecutive '::' if anyfunction! omni#cpp#utils#SimplifyScope(szScope) let szResult = substitute(a:szScope, '\(::\)\+', '::', 'g') if szResult=='::' return szResult else return substitute(szResult, '::$', '', 'g') endifendfunc" Check if the cursor is in commentfunction! omni#cpp#utils#IsCursorInCommentOrString() return match(synIDattr(synID(line("."), col(".")-1, 1), "name"), '\C\<cComment\|\<cCppString\|\<cIncluded')>=0endfunc" Tokenize the current instruction until the cursor position." @return list of tokensfunction! 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 tokensfunction! 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 groupfunction! 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" - itemThisfunction! 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' endifendfunc" Remove useless parenthesisfunction! 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 tokensendfunc" Function create a type infofunction! 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::MyClassfunction! 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 listfunction! 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 resultendfunc" Get class inheritance list where items in the list are tag items." TODO: Verify inheritance orderfunction! 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -