diff --git a/doc/clang_complete.txt b/doc/clang_complete.txt index 73b42bd4..ae2d5de9 100644 --- a/doc/clang_complete.txt +++ b/doc/clang_complete.txt @@ -137,6 +137,12 @@ The snippets engine (clang_complete, ultisnips... see the snippets subdirectory). Default: "clang_complete" + *clang_complete-snippet_jump_map* + *g:clang_complete_snippet_jump_map* +Key clang_complete snippet engine uses to jump between replaceables. +If it is empty string, then nothing is mapped. +Default: '' + *clang_complete-conceal_snippets* *g:clang_conceal_snippets* Note: This option is specific to clang_complete snippets engine. @@ -180,6 +186,7 @@ Default: 'iunmap ' *g:clang_close_preview* If equal to 1, the preview window will be close automatically after a completion. +If equal to 2, the preview window won't even be opened. Default: 0 *clang_complete-user_options* @@ -267,15 +274,37 @@ Default: 0 If clang should complete code patterns, i.e loop constructs etc. Default: 0 + *clang_complete-print_type_key* + *g:clang_print_type_key* +Set the key used to print the type of the identifier under cursor. +If g:clang_print_type_key is empty, then no shortcut will be created +to gather this info. +Defaut: "" +Note: You can call ClangPrintType() vim function to print this information. + + *clang_complete-print_type_and_constant_value_key* + *g:clang_print_type_and_constant_value_key* +Set the key used to print the type and value of the identifier under cursor. +If cursor is on an enum, then the value of that enum is printed after the type. +If cursor is on a constant, then the value of that constant is printed +after the type. +If g:clang_print_type_and_constant_value_key is empty, +then no shortcut will be created to gather this info. +Defaut: "zp" +Note: You can call ClangPrintTypeAndconstantvalue() vim function +to print this information. + *clang_complete-jumpto_declaration_key* *g:clang_jumpto_declaration_key* Set the key used to jump to declaration. +If it is empty then no shortcut will be created for this jump. Default: "" Note: You could use the g:ClangGotoDeclaration() to do the same with a mapping. *clang_complete-jumpto_declaration_in_preview_key* *g:clang_jumpto_declaration_in_preview_key* Set the key used to jump to declaration in a preview window. +If it is empty then no shortcut will be created for this jump. Default: "]" Note: You could use the g:ClangGotoDeclarationPreview() to do the same with a mapping. @@ -284,6 +313,7 @@ Note: You could use the g:ClangGotoDeclarationPreview() to do the same with a ma Set the key used to jump back. Note: Effectively this will be remapped to . The default value is chosen to be coherent with ctags implementation. +If it is empty then nothing will be remapped to , you can use as it is. Default: "" *clang_complete-make_default_keymappings* diff --git a/plugin/clang/cindex.py b/plugin/clang/cindex.py index 4e6e3c5b..73217d20 100644 --- a/plugin/clang/cindex.py +++ b/plugin/clang/cindex.py @@ -1078,6 +1078,18 @@ def is_definition(self): """ return conf.lib.clang_isCursorDefinition(self) + def is_virtual_method(self): + """Determine if a C++ member function or member function template is + explicitly declared 'virtual' or if it overrides a virtual method from + one of the base classes. + """ + return conf.lib.clang_CXXMethod_isVirtual(self) + + def is_function(self): + """Determine if cursor is over a function. + """ + return ( -1 != conf.lib.clang_Cursor_getNumArguments(self) ) + def is_static_method(self): """Returns True if the cursor refers to a C++ member function or member function template that is declared 'static'. @@ -1242,6 +1254,39 @@ def enum_value(self): self._enum_value = conf.lib.clang_getEnumConstantDeclValue(self) return self._enum_value + @property + def evaluated_value(self): + """Return the value of the constant the cursor is on, or None if not on a constant""" + + if not hasattr(self, '_evaluated_value'): + # print("kind: " + str(self.kind)) + # print("kind: " + str(self.type.kind)) + # TODO: if CursorKind.MACRO_DEFINITION == self.kind: + # TODO: if CursorKind.MACRO_INSTANTIATION == self.kind: + + self._evaluated_value = None + evalResult = conf.lib.clang_Cursor_Evaluate(self) + + if evalResult: + if EvalResultKind.INT == evalResult.kind: + if TypeKind.ULONGLONG == self.type.kind: + self._evaluated_value = evalResult.getAsUnsigned() + else: + # Every other type should fit inside long long range. + self._evaluated_value = evalResult.getAsLongLong() + + elif EvalResultKind.FLOAT == evalResult.kind: + self._evaluated_value = evalResult.getAsDouble() + if TypeKind.FLOAT == self.type.kind: + # TODO: I have not yet found a way to get value as float, so instead of 3.14 as float + # I get 3.140000104904175 as double. + self._evaluated_value = "about " + str(self._evaluated_value) + elif EvalResultKind.UNEXPOSED != evalResult.kind: + # C string constants (const char*, const char array) are written here. + self._evaluated_value = '"%s"' % (evalResult.getAsString().decode("utf-8")) + + return self._evaluated_value + @property def objc_type_encoding(self): """Return the Objective-C type encoding as a str.""" @@ -1435,6 +1480,17 @@ def __repr__(self): TypeKind.OBJCID = TypeKind(27) TypeKind.OBJCCLASS = TypeKind(28) TypeKind.OBJCSEL = TypeKind(29) +TypeKind.FLOAT128 = TypeKind(30) +TypeKind.HALF = TypeKind(31) +TypeKind.FLOAT16 = TypeKind(32) +TypeKind.SHORTACCUM = TypeKind(33) +TypeKind.ACCUM = TypeKind(34) +TypeKind.LONGACCUM = TypeKind(35) +TypeKind.USHORTACCUM = TypeKind(36) +TypeKind.UACCUM = TypeKind(37) +TypeKind.ULONGACCUM = TypeKind(38) +TypeKind.BFLOAT16 = TypeKind(39) +TypeKind.IBM128 = TypeKind(40) TypeKind.COMPLEX = TypeKind(100) TypeKind.POINTER = TypeKind(101) TypeKind.BLOCKPOINTER = TypeKind(102) @@ -1449,6 +1505,71 @@ def __repr__(self): TypeKind.FUNCTIONPROTO = TypeKind(111) TypeKind.CONSTANTARRAY = TypeKind(112) TypeKind.VECTOR = TypeKind(113) +TypeKind.INCOMPLETEARRAY = TypeKind(114) +TypeKind.VARIABLEARRAY = TypeKind(115) +TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116) +TypeKind.MEMBERPOINTER = TypeKind(117) +TypeKind.AUTO = TypeKind(118) +TypeKind.ELABORATED = TypeKind(119) # type that was referred to using an elaborated type keyword, e.g. struct S, N::M::type. +TypeKind.PIPE = TypeKind(120) +TypeKind.OCLIMAGE1DRO = TypeKind(121) +TypeKind.OCLIMAGE1DARRAYRO = TypeKind(122) +TypeKind.OCLIMAGE1DBUFFERRO = TypeKind(123) +TypeKind.OCLIMAGE2DRO = TypeKind(124) +TypeKind.OCLIMAGE2DARRAYRO = TypeKind(125) +TypeKind.OCLIMAGE2DDEPTHRO = TypeKind(126) +TypeKind.OCLIMAGE2DARRAYDEPTHRO = TypeKind(127) +TypeKind.OCLIMAGE2DMSAARO = TypeKind(128) +TypeKind.OCLIMAGE2DARRAYMSAARO = TypeKind(129) +TypeKind.OCLIMAGE2DMSAADEPTHRO = TypeKind(130) +TypeKind.OCLIMAGE2DARRAYMSAADEPTHRO = TypeKind(131) +TypeKind.OCLIMAGE3DRO = TypeKind(132) +TypeKind.OCLIMAGE1DWO = TypeKind(133) +TypeKind.OCLIMAGE1DARRAYWO = TypeKind(134) +TypeKind.OCLIMAGE1DBUFFERWO = TypeKind(135) +TypeKind.OCLIMAGE2DWO = TypeKind(136) +TypeKind.OCLIMAGE2DARRAYWO = TypeKind(137) +TypeKind.OCLIMAGE2DDEPTHWO = TypeKind(138) +TypeKind.OCLIMAGE2DARRAYDEPTHWO = TypeKind(139) +TypeKind.OCLIMAGE2DMSAAWO = TypeKind(140) +TypeKind.OCLIMAGE2DARRAYMSAAWO = TypeKind(141) +TypeKind.OCLIMAGE2DMSAADEPTHWO = TypeKind(142) +TypeKind.OCLIMAGE2DARRAYMSAADEPTHWO = TypeKind(143) +TypeKind.OCLIMAGE3DWO = TypeKind(144) +TypeKind.OCLIMAGE1DRW = TypeKind(145) +TypeKind.OCLIMAGE1DARRAYRW = TypeKind(146) +TypeKind.OCLIMAGE1DBUFFERRW = TypeKind(147) +TypeKind.OCLIMAGE2DRW = TypeKind(148) +TypeKind.OCLIMAGE2DARRAYRW = TypeKind(149) +TypeKind.OCLIMAGE2DDEPTHRW = TypeKind(150) +TypeKind.OCLIMAGE2DARRAYDEPTHRW = TypeKind(151) +TypeKind.OCLIMAGE2DMSAARW = TypeKind(152) +TypeKind.OCLIMAGE2DARRAYMSAARW = TypeKind(153) +TypeKind.OCLIMAGE2DMSAADEPTHRW = TypeKind(154) +TypeKind.OCLIMAGE2DARRAYMSAADEPTHRW = TypeKind(155) +TypeKind.OCLIMAGE3DRW = TypeKind(156) +TypeKind.OCLSAMPLER = TypeKind(157) +TypeKind.OCLEVENT = TypeKind(158) +TypeKind.OCLQUEUE = TypeKind(159) +TypeKind.OCLRESERVEID = TypeKind(160) +TypeKind.OBJCOBJECT = TypeKind(161) +TypeKind.OBJCTYPEPARAM = TypeKind(162) +TypeKind.ATTRIBUTED = TypeKind(163) +TypeKind.OCLINTELSUBGROUPAVCMCEPAYLOAD = TypeKind(164) +TypeKind.OCLINTELSUBGROUPAVCIMEPAYLOAD = TypeKind(165) +TypeKind.OCLINTELSUBGROUPAVCREFPAYLOAD = TypeKind(166) +TypeKind.OCLINTELSUBGROUPAVCSICPAYLOAD = TypeKind(167) +TypeKind.OCLINTELSUBGROUPAVCMCERESULT = TypeKind(168) +TypeKind.OCLINTELSUBGROUPAVCIMERESULT = TypeKind(169) +TypeKind.OCLINTELSUBGROUPAVCREFRESULT = TypeKind(170) +TypeKind.OCLINTELSUBGROUPAVCSICRESULT = TypeKind(171) +TypeKind.OCLINTELSUBGROUPAVCIMERESULTSINGLEREFSTREAMOUT = TypeKind(172) +TypeKind.OCLINTELSUBGROUPAVCIMERESULTDUALREFSTREAMOUT = TypeKind(173) +TypeKind.OCLINTELSUBGROUPAVCIMESINGLEREFSTREAMIN = TypeKind(174) +TypeKind.OCLINTELSUBGROUPAVCIMEDUALREFSTREAMIN = TypeKind(175) +TypeKind.EXTVECTOR = TypeKind(176) +TypeKind.ATOMIC = TypeKind(177) +TypeKind.BTFTAGATTRIBUTED = TypeKind(178) class Type(Structure): """ @@ -1560,6 +1681,15 @@ def get_canonical(self): """ return conf.lib.clang_getCanonicalType(self) + def get_spelling(self): + """ + Pretty-print the underlying type using the rules of the + language of the translation unit from which it came. + + If the type is invalid, an empty string is returned. + """ + return conf.lib.clang_getTypeSpelling(self).decode("utf-8") + def is_const_qualified(self): """Determine whether a Type has the "const" qualifier set. @@ -1633,6 +1763,56 @@ def __eq__(self, other): def __ne__(self, other): return not self.__eq__(other) +### Eval Result Kinds ### + +class EvalResultKind(object): + """ + Describes the kind of EvalResult. + """ + + # The unique kind objects, indexed by id. + _kinds = [] + _name_map = None + + def __init__(self, value): + if value >= len(EvalResultKind._kinds): + EvalResultKind._kinds += [None] * (value - len(EvalResultKind._kinds) + 1) + if EvalResultKind._kinds[value] is not None: + raise ValueError('EvalResultKind already loaded') + self.value = value + EvalResultKind._kinds[value] = self + EvalResultKind._name_map = None + + def from_param(self): + return self.value + + @property + def name(self): + """Get the enumeration name of this cursor kind.""" + if self._name_map is None: + self._name_map = {} + for key,value in EvalResultKind.__dict__.items(): + if isinstance(value,EvalResultKind): + self._name_map[value] = key + return self._name_map[self] + + @staticmethod + def from_id(id): + if id >= len(EvalResultKind._kinds) or EvalResultKind._kinds[id] is None: + raise ValueError('Unknown type kind %d' % id) + return EvalResultKind._kinds[id] + + def __repr__(self): + return 'EvalResultKind.%s' % (self.name,) + +EvalResultKind.UNEXPOSED = EvalResultKind(0) +EvalResultKind.INT = EvalResultKind(1) +EvalResultKind.FLOAT = EvalResultKind(2) +EvalResultKind.Obj_CStr_Literal = EvalResultKind(3) +EvalResultKind.Str_Literal = EvalResultKind(4) +EvalResultKind.CF_Str = EvalResultKind(5) +EvalResultKind.Other = EvalResultKind(6) + ## CIndex Objects ## # CIndex objects (derived from ClangObject) are essentially lightweight @@ -2506,6 +2686,43 @@ def cursor(self): return cursor +class EvalResult(object): + """Evaluation result of a cursor. E.g. cursor on FORTYTWO constant will evaluate to 42.""" + + def __init__(self, as_parameter): + self._obj = as_parameter + + def __del__(self): + conf.lib.clang_EvalResult_dispose(self._obj) + + def __repr__(self): + return "" + + @property + def kind(self): + if not hasattr(self, '_kind'): + self._kind = EvalResultKind.from_id(conf.lib.clang_EvalResult_getKind(self._obj)) + return self._kind + + def getAsUnsigned(self): + return conf.lib.clang_EvalResult_getAsUnsigned(self._obj) + + def getAsString(self): + assert self.kind not in [EvalResultKind.UNEXPOSED, EvalResultKind.INT, EvalResultKind.FLOAT] + return conf.lib.clang_EvalResult_getAsStr(self._obj) + + def getAsLongLong(self): + return conf.lib.clang_EvalResult_getAsLongLong(self._obj) + + def getAsDouble(self): + return conf.lib.clang_EvalResult_getAsDouble(self._obj) + + @staticmethod + def from_result(res, fn, args): + if not res: + return None + return EvalResult(res) + # Now comes the plumbing to hook up the C library. # Register callback types in common container. @@ -2576,6 +2793,11 @@ def cursor(self): [Index, c_char_p], c_object_p), + ("clang_Cursor_Evaluate", + [Cursor], + c_object_p, + EvalResult.from_result), + ("clang_CXXMethod_isStatic", [Cursor], bool), @@ -2625,6 +2847,33 @@ def cursor(self): [Type, Type], bool), + ("clang_EvalResult_dispose()", + [c_object_p]), + + ("clang_EvalResult_getAsDouble", + [c_object_p], + c_double), + + ("clang_EvalResult_getAsInt", + [c_object_p], + c_int), + + ("clang_EvalResult_getAsLongLong", + [c_object_p], + c_longlong), + + ("clang_EvalResult_getAsUnsigned", + [c_object_p], + c_ulonglong), + + ("clang_EvalResult_getAsStr", + [c_object_p], + c_char_p), + + ("clang_EvalResult_getKind", + [c_object_p], + c_uint), + ("clang_getArgType", [Type, c_uint], Type, @@ -2955,6 +3204,11 @@ def cursor(self): _CXString, _CXString.from_result), + ("clang_getTypeSpelling", + [Type], + _CXString, + _CXString.from_result), + ("clang_hashCursor", [Cursor], c_uint), diff --git a/plugin/clang_complete.vim b/plugin/clang_complete.vim index 8a5ef041..34f64f93 100644 --- a/plugin/clang_complete.vim +++ b/plugin/clang_complete.vim @@ -78,6 +78,10 @@ function! s:ClangCompleteInit() let g:clang_snippets_engine = 'clang_complete' endif + if !exists('g:clang_complete_snippet_jump_map') + let g:clang_complete_snippet_jump_map = '' + endif + if !exists('g:clang_user_options') let g:clang_user_options = '' endif @@ -124,6 +128,14 @@ function! s:ClangCompleteInit() let g:clang_auto_user_options = '.clang_complete, path' endif + if !exists('g:clang_print_type_key') + let g:clang_print_type_key = '' + endif + + if !exists('g:clang_print_type_and_constant_value_key') + let g:clang_print_type_and_constant_value_key = 'zp' + endif + if !exists('g:clang_jumpto_declaration_key') let g:clang_jumpto_declaration_key = '' endif @@ -191,9 +203,21 @@ function! s:ClangCompleteInit() inoremap . CompleteDot() inoremap > CompleteArrow() inoremap : CompleteColon() - execute "nnoremap " . g:clang_jumpto_declaration_key . " :call GotoDeclaration(0)" - execute "nnoremap " . g:clang_jumpto_declaration_in_preview_key . " :call GotoDeclaration(1)" - execute "nnoremap " . g:clang_jumpto_back_key . " " + if g:clang_print_type_key != "" + execute "nnoremap " . g:clang_print_type_key . " :call ClangPrintType()" + endif + if g:clang_print_type_and_constant_value_key != "" + execute "nnoremap " . g:clang_print_type_and_constant_value_key . " :call ClangPrintTypeAndconstantvalue()" + endif + if g:clang_jumpto_declaration_key != "" + execute "nnoremap " . g:clang_jumpto_declaration_key . " :call GotoDeclaration(0)" + endif + if g:clang_jumpto_declaration_in_preview_key != "" + execute "nnoremap " . g:clang_jumpto_declaration_in_preview_key . " :call GotoDeclaration(1)" + endif + if g:clang_jumpto_back_key != "" + execute "nnoremap " . g:clang_jumpto_back_key . " " + endif endif if g:clang_omnicppcomplete_compliance == 1 @@ -207,6 +231,10 @@ function! s:ClangCompleteInit() set completeopt+=menuone endif + if g:clang_close_preview == 2 + set completeopt-=preview + endif + " Disable every autocmd that could have been set. augroup ClangComplete autocmd! @@ -530,6 +558,10 @@ function! s:StopMonitoring() return endif + if g:clang_close_preview == 1 + pclose + endif + if g:clang_make_default_keymappings == 1 " Restore original return and Ctrl-Y key mappings @@ -572,10 +604,6 @@ function! s:TriggerSnippet() " Trigger the snippet execute s:py_cmd 'snippetsTrigger()' - - if g:clang_close_preview - pclose - endif endfunction function! s:ShouldComplete() @@ -630,9 +658,32 @@ function! s:CompleteColon() return ':' . s:LaunchCompletion() endfunction +function! ClangPrintType() + execute s:py_cmd "clangGetType()" + redraw + echom b:clang_type +endfunction + +function! ClangPrintTypeAndconstantvalue() + execute s:py_cmd "clangGetTypeAndConstantValue()" + redraw + echom b:clang_type_and_value +endfunction + function! s:GotoDeclaration(preview) try execute s:py_cmd "gotoDeclaration(vim.eval('a:preview') == '1')" + if g:clang_is_virtual_method + redraw + echohl ErrorMsg | echom "This is a virtual function!" | echohl None + elseif g:clang_is_function + redraw + echom "non-virtual function" + else + " clear previous message + redraw + echom "" + endif catch /^Vim\%((\a\+)\)\=:E37/ echoe "The current file is not saved, and 'hidden' is not set." \ "Either save the file or add 'set hidden' in your vimrc." diff --git a/plugin/libclang.py b/plugin/libclang.py index 302b3e38..51f66756 100644 --- a/plugin/libclang.py +++ b/plugin/libclang.py @@ -434,7 +434,10 @@ def roll_out_optional(chunks): for optional_arg in roll_out_optional(chunk.string): if place_markers_for_optional_args: word += snippetsFormatPlaceHolder(optional_arg) - info += optional_arg + "=?" + if -1 != optional_arg.find('='): + info += optional_arg + else: + info += optional_arg + "=?" if chunk.isKindPlaceHolder(): word += snippetsFormatPlaceHolder(chunk_spelling) @@ -576,14 +579,17 @@ def jumpToLocation(filename, line, column, preview): if not preview: vim.current.window.cursor = (line, column - 1) -def gotoDeclaration(preview=True): +# You must call finish to the timer later. +def _createTimerAndGetVimPositionAndParameters(): global debug debug = int(vim.eval("g:clang_debug")) == 1 params = getCompileParams(vim.current.buffer.name) line, col = vim.current.window.cursor timer = CodeCompleteTimer(debug, vim.current.buffer.name, line, col, params) + return [line, col, params, timer] - with libclangLock: +# You must get libclangLock before calling this function. +def _getCursorAndLocation(line, col, params, timer): tu = getCurrentTranslationUnit(params['args'], getCurrentFile(), vim.current.buffer.name, timer, update = True) @@ -594,6 +600,18 @@ def gotoDeclaration(preview=True): f = File.from_name(tu, vim.current.buffer.name) loc = SourceLocation.from_position(tu, f, line, col + 1) cursor = Cursor.from_location(tu, loc) + return [cursor, loc] + +def gotoDeclaration(preview=True): + [line, col, params, timer] = _createTimerAndGetVimPositionAndParameters() + vim.command("let g:clang_is_virtual_method = 0"); + vim.command("let g:clang_is_function = 0"); + with libclangLock: + [cursor, loc] = _getCursorAndLocation(line, col, params, timer) + if cursor.is_virtual_method(): + vim.command("let g:clang_is_virtual_method = 1"); + if cursor.is_function(): + vim.command("let g:clang_is_function = 1"); defs = [cursor.get_definition(), cursor.referenced] for d in defs: @@ -601,8 +619,76 @@ def gotoDeclaration(preview=True): loc = d.location if loc.file is not None: jumpToLocation(loc.file.name, loc.line, loc.column, preview) + if d.is_virtual_method(): + vim.command("let g:clang_is_virtual_method = 1"); + if d.is_function(): + vim.command("let g:clang_is_function = 1"); break timer.finish() +def getTypeStringUnderCursor(cursor): + type_str = "type: " + + type = cursor.type + type_spelling = type.get_spelling() + type_canonical_spelling = type.get_canonical().get_spelling() + + if type_spelling: + type_str += type_spelling + else: + type_str += "?" + + if type_canonical_spelling and type_canonical_spelling != type_spelling: + type_str += ", canonical type: "+type_canonical_spelling + + return type_str + +def getConstantValueStringUnderCursor(cursor): + result = "" + enum_value = "" + const_value = "" + + if CursorKind.ENUM_CONSTANT_DECL == cursor.kind: + enum_value = str(cursor.enum_value) + + if "" == enum_value and TypeKind.ENUM == cursor.type.kind: + enum_def = cursor.get_definition() + if enum_def is not None and CursorKind.ENUM_CONSTANT_DECL == enum_def.kind: + enum_value = str(enum_def.enum_value) + + if "" == enum_value and cursor.evaluated_value != None: + const_value = str(cursor.evaluated_value) + + if "" != enum_value: + result += ", enum value: " + enum_value + if "" != const_value: + result += ", const value: " + const_value + + return result + +def clangGetType(): + [line, col, params, timer] = _createTimerAndGetVimPositionAndParameters() + + with libclangLock: + [cursor, loc] = _getCursorAndLocation(line, col, params, timer) + type_str = getTypeStringUnderCursor(cursor) + + vim.command("let b:clang_type = '" + type_str.replace("'","''")+"'") + + timer.finish() + +def clangGetTypeAndConstantValue(): + [line, col, params, timer] = _createTimerAndGetVimPositionAndParameters() + + with libclangLock: + [cursor, loc] = _getCursorAndLocation(line, col, params, timer) + result = getTypeStringUnderCursor(cursor) + result += getConstantValueStringUnderCursor(cursor) + + vim.command("let b:clang_type_and_value = '" + result.replace("'","''")+"'") + + timer.finish() + + # vim: set ts=2 sts=2 sw=2 expandtab : diff --git a/plugin/snippets/clang_complete.py b/plugin/snippets/clang_complete.py index ce5bf30b..aa8d327b 100644 --- a/plugin/snippets/clang_complete.py +++ b/plugin/snippets/clang_complete.py @@ -1,10 +1,20 @@ import re import vim +def getClangSnippetJumpKey(escapeForFeedkeys): + snippet_jump_map = vim.eval("g:clang_complete_snippet_jump_map") + if escapeForFeedkeys: + snippet_jump_map = snippet_jump_map.replace('<', r'\<').replace('"', r'\"') + return snippet_jump_map + def snippetsInit(): python_cmd = vim.eval('s:py_cmd') - vim.command("noremap :{} updateSnips()".format(python_cmd)) - vim.command("snoremap :{} updateSnips()".format(python_cmd)) + vim.command("noremap ClangSnippetJumpN :{} updateSnips()".format(python_cmd)) + vim.command("snoremap ClangSnippetJumpS :{} updateSnips()".format(python_cmd)) + snippet_jump_map = getClangSnippetJumpKey(False) + if "" != snippet_jump_map: + vim.command("map {} ClangSnippetJumpN".format(snippet_jump_map)) + vim.command("smap {} ClangSnippetJumpS".format(snippet_jump_map)) if int(vim.eval("g:clang_conceal_snippets")) == 1: vim.command("syntax match placeHolder /\$`[^`]*`/ contains=placeHolderMark") vim.command("syntax match placeHolderMark contained /\$`/ conceal") @@ -24,7 +34,8 @@ def snippetsAddSnippet(fullname, word, abbr): def snippetsTrigger(): if r.search(vim.current.line) is None: return - vim.command('call feedkeys("\^\")') + # Using the Plug here works even if g:clang_complete_snippet_jump_map is empty. + vim.command('call feedkeys("\^\ClangSnippetJumpN")') def snippetsReset(): pass @@ -37,7 +48,9 @@ def updateSnips(): if result is None: result = r.search(line) if result is None: - vim.command('call feedkeys("\", "n")') + snippet_jump_map = getClangSnippetJumpKey(True) + if "" != snippet_jump_map: + vim.command('call feedkeys("{}", "n")'.format(snippet_jump_map)) return start, end = result.span()