diff --git a/.gitignore b/.gitignore index fde244ed..d451092f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.vmb *.cache tags +*.swp diff --git a/README b/README deleted file mode 100644 index db7be6f4..00000000 --- a/README +++ /dev/null @@ -1,15 +0,0 @@ -This plugin uses clang for accurately completing C and C++ code. - -To build and install in one step, type: -$ make install - -To build and install in two steps, type: -$ make -$ vim clang_complete.vmb -c 'so %' -c 'q' - -Alternatively, you can also put the files in ~/.vim/ - -You need Vim 7.3 or higher, compiled with python support and ideally, with -the conceal feature. - -See doc/clang_complete.txt for help and license. diff --git a/README.md b/README.md new file mode 100755 index 00000000..2973b184 --- /dev/null +++ b/README.md @@ -0,0 +1,64 @@ +This plugin uses clang for accurately completing C and C++ code. + +## Installation + +- To build and install in one step, type: `$ make install` + +- To build and install in two steps, type: + +``` +$ make +$ vim clang_complete.vmb -c 'so %' -c 'q' +``` + +- Alternatively, you can also put the files in `~/.vim/` + +You need Vim 7.3 or higher, compiled with python support and ideally, with +the conceal feature. + +## Minimum Configuration + +- Set the `clang_library_path` to the directory containing file named + libclang.{dll,so,dylib} (for Windows, Unix variants and OS X respectively) or + the file itself, example: + +```vim + " path to directory where library can be found + let g:clang_library_path='/usr/lib/llvm-3.8/lib' + " or path directly to the library file + let g:clang_library_path='/usr/lib64/libclang.so.3.8' +``` + +- Compiler options can be configured in a `.clang_complete` file in each project + root. Example of `.clang_complete` file: + +``` +-DDEBUG +-include ../config.h +-I../common +-I/usr/include/c++/4.5.3/ +-I/usr/include/c++/4.5.3/x86_64-slackware-linux/ +``` + +## Usage + +The plugin provides list of matches, after that you pick completion from a +generic completion menu where Ctrl+N, Ctrl+P and alike +work and wrap around ends of list. + +## License + +See doc/clang_complete.txt for help and license. + +## Troubleshooting + +The first step is to check values of `'omnifunc'` and `'completefunc'` options +in a C++ buffer where completion doesn't work (the value should be +`ClangComplete`). This can be done with the following command: +`:set omnifunc? completefunc?` + +Output of `:messages` command after startup could also show something useful in +case there were problems with plugin initialization. + +If everything is fine, next step might be to load only clang_complete plugin +and see if anything changes. diff --git a/bin/cc_args.py b/bin/cc_args.py index 5f6ac3d9..eebd79fa 100755 --- a/bin/cc_args.py +++ b/bin/cc_args.py @@ -28,11 +28,13 @@ def parseArguments(arguments): nextIsInclude = False nextIsDefine = False nextIsIncludeFile = False + nextIsIsystem = False includes = [] defines = [] include_file = [] options = [] + isystem = [] for arg in arguments: if nextIsInclude: @@ -44,6 +46,9 @@ def parseArguments(arguments): elif nextIsIncludeFile: include_file += [arg] nextIsIncludeFile = False + elif nextIsIsystem: + isystem += [arg] + nextIsIsystem = False elif arg == "-I": nextIsInclude = True elif arg == "-D": @@ -54,6 +59,8 @@ def parseArguments(arguments): defines += [arg[2:]] elif arg == "-include": nextIsIncludeFile = True + elif arg == "-isystem": + nextIsIsystem = True elif arg.startswith('-std='): options.append(arg) elif arg == '-ansi': @@ -66,6 +73,7 @@ def parseArguments(arguments): result = list(map(lambda x: "-I" + x, includes)) result.extend(map(lambda x: "-D" + x, defines)) result.extend(map(lambda x: "-include " + x, include_file)) + result.extend(map(lambda x: "-isystem" + x, isystem)) result.extend(options) return result diff --git a/bin/generate_kinds.py b/bin/generate_kinds.py new file mode 100755 index 00000000..8e975507 --- /dev/null +++ b/bin/generate_kinds.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +#-*- coding: utf-8 -*- + +import re +import sys +import os.path +import clang.cindex + +# you can use this dictionary to map some kinds to better +# textual representation than just the number +mapping = { + 1 : 't' , # CXCursor_UnexposedDecl (A declaration whose specific kind is not + # exposed via this interface) + 2 : 't' , # CXCursor_StructDecl (A C or C++ struct) + 3 : 't' , # CXCursor_UnionDecl (A C or C++ union) + 4 : 't' , # CXCursor_ClassDecl (A C++ class) + 5 : 't' , # CXCursor_EnumDecl (An enumeration) + 6 : 'm' , # CXCursor_FieldDecl (A field (in C) or non-static data member + # (in C++) in a struct, union, or C++ class) + 7 : 'e' , # CXCursor_EnumConstantDecl (An enumerator constant) + 8 : 'f' , # CXCursor_FunctionDecl (A function) + 9 : 'v' , # CXCursor_VarDecl (A variable) + 10 : 'a' , # CXCursor_ParmDecl (A function or method parameter) + 20 : 't' , # CXCursor_TypedefDecl (A typedef) + 21 : 'f' , # CXCursor_CXXMethod (A C++ class method) + 22 : 'n' , # CXCursor_Namespace (A C++ namespace) + 24 : '+' , # CXCursor_Constructor (A C++ constructor) + 25 : '~' , # CXCursor_Destructor (A C++ destructor) + 27 : 'a' , # CXCursor_TemplateTypeParameter (A C++ template type parameter) + 28 : 'a' , # CXCursor_NonTypeTemplateParameter (A C++ non-type template + # parameter) + 29 : 'a' , # CXCursor_TemplateTemplateParameter (A C++ template template + # parameter) + 30 : 'f' , # CXCursor_FunctionTemplate (A C++ function template) + 31 : 'p' , # CXCursor_ClassTemplate (A C++ class template) + 33 : 'n' , # CXCursor_NamespaceAlias (A C++ namespace alias declaration) + 36 : 't' , # CXCursor_TypeAliasDecl (A C++ alias declaration) + 72 : 'u' , # CXCursor_NotImplemented + 501 : 'd' , # CXCursor_MacroDefinition + 601 : 'ta', # CXCursor_TypeAliasTemplateDecl (Template alias declaration). + 700 : 'oc', # CXCursor_OverloadCandidate A code completion overload candidate. +} + +if len(sys.argv) != 2: + print("Usage:", sys.argv[0], "") + exit(-1) + +index = clang.cindex.Index.create() +tu = index.parse(sys.argv[1]) + +kinds = None +for child in tu.cursor.get_children(): + if (child.spelling == "CXCursorKind"): + kinds = child + break +else: + print("Index.h doesn't contain CXCursorKind where it is expected, please report a bug.") + exit(-1) + +kinds_py_path = os.path.join( + os.path.dirname( + os.path.dirname( + os.path.abspath(__file__) + ) + ), + "plugin", + "kinds.py" +) + +with open(kinds_py_path, "w") as f: + # First/Last pattern + fl = re.compile("CXCursor_(First|Last)[A-Z].*") + + f.write("# !! GENERATED FILE, DO NOT EDIT\n") + f.write("kinds = {\n") + + for kind in kinds.get_children(): + # filter out First/Last markers from the enum + if fl.match(kind.spelling) is not None: + continue + + text = mapping.get(kind.enum_value, kind.enum_value) + f.write("{0} : '{1}', # {2} {3}\n".format(kind.enum_value, text, kind.spelling, kind.brief_comment)) + + f.write("}\n") + +# vim: set ts=2 sts=2 sw=2 expandtab : diff --git a/doc/clang_complete.txt b/doc/clang_complete.txt index b3a50024..73b42bd4 100644 --- a/doc/clang_complete.txt +++ b/doc/clang_complete.txt @@ -1,4 +1,4 @@ -*clang_complete.txt* For Vim version 7.3. Last change: 2014 Apr 13 +*clang_complete.txt* For Vim version 7.3. Last change: 2016 Sep 24 clang_complete plugin documentation @@ -184,7 +184,7 @@ Default: 0 *clang_complete-user_options* *g:clang_user_options* -Additionnal compilation argument passed to libclang. +Additional compilation argument passed to libclang. Example: > " compile all sources as c++11 (just for example, use .clang_complete for @@ -239,11 +239,18 @@ Default: 1 *clang_complete-library_path* *g:clang_library_path* -If libclang is not in your library search path, set this to the absolute path -where libclang is available. This should either be a directory containing a -file named libclang.[dll/so/dylib] or the clang shared library file itself. +If libclang is not in the library search path of your system, you should set +this variable to the absolute path of either directory containing +libclang.{dll,so,dylib} (for Windows, Unix variants and OS X respectively) or +to that file itself. Default: "" +Example: > + " path to directory where library can be found + let g:clang_library_path='/usr/lib/llvm-3.8/lib' + " or path directly to the library file + let g:clang_library_path='/usr/lib64/libclang.so.3.8' +< *clang_complete-sort_algo* *g:clang_sort_algo* How results are sorted (alpha, priority, none). Currently only works with @@ -258,18 +265,18 @@ Default: 0 *clang_complete-complete_patterns* *g:clang_complete_patterns* If clang should complete code patterns, i.e loop constructs etc. -Defaut: 0 +Default: 0 *clang_complete-jumpto_declaration_key* *g:clang_jumpto_declaration_key* Set the key used to jump to declaration. -Defaut: "" +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. -Defaut: "]" +Default: "]" Note: You could use the g:ClangGotoDeclarationPreview() to do the same with a mapping. *clang_complete-jumpto_back_key* @@ -277,7 +284,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. -Defaut: "" +Default: "" *clang_complete-make_default_keymappings* *g:clang_make_default_keymappings* @@ -290,7 +297,7 @@ Default: 1 Omnicppcomplete compatibility mode. Keeps omni auto-completion in control of omnicppcomplete, disables clang's auto-completion (|g:clang_complete_auto|) and enables only as main clang completion function. -Defaut: 0 +Default: 0 ============================================================================== 6. Known issues *clang_complete-issues* diff --git a/plugin/clang/cindex.py b/plugin/clang/cindex.py index eb05560c..4e6e3c5b 100644 --- a/plugin/clang/cindex.py +++ b/plugin/clang/cindex.py @@ -76,6 +76,16 @@ callbacks = {} +def encode(value): + import sys + if sys.version_info[0] == 2: + return value + + try: + return value.encode('utf-8') + except AttributeError: + return value + ### Exception Classes ### class TranslationUnitLoadError(Exception): @@ -427,7 +437,7 @@ def get_tokens(tu, extent): token_group = TokenGroup(tu, tokens_memory, tokens_count) - for i in xrange(0, count): + for i in range(0, count): token = Token() token.int_data = tokens_array[i].int_data token.ptr_data = tokens_array[i].ptr_data @@ -488,7 +498,7 @@ def __init__(self, value): if value >= len(CursorKind._kinds): CursorKind._kinds += [None] * (value - len(CursorKind._kinds) + 1) if CursorKind._kinds[value] is not None: - raise ValueError,'CursorKind already loaded' + raise ValueError('CursorKind already loaded') self.value = value CursorKind._kinds[value] = self CursorKind._name_map = None @@ -509,13 +519,13 @@ def name(self): @staticmethod def from_id(id): if id >= len(CursorKind._kinds) or CursorKind._kinds[id] is None: - raise ValueError,'Unknown cursor kind' + raise ValueError('Unknown cursor kind') return CursorKind._kinds[id] @staticmethod def get_all_kinds(): """Return all CursorKind enumeration instances.""" - return filter(None, CursorKind._kinds) + return [_f for _f in CursorKind._kinds if _f] def is_declaration(self): """Test if this is a declaration kind.""" @@ -1363,7 +1373,7 @@ def __init__(self, value): if value >= len(TypeKind._kinds): TypeKind._kinds += [None] * (value - len(TypeKind._kinds) + 1) if TypeKind._kinds[value] is not None: - raise ValueError,'TypeKind already loaded' + raise ValueError('TypeKind already loaded') self.value = value TypeKind._kinds[value] = self TypeKind._name_map = None @@ -1389,7 +1399,7 @@ def spelling(self): @staticmethod def from_id(id): if id >= len(TypeKind._kinds) or TypeKind._kinds[id] is None: - raise ValueError,'Unknown type kind %d' % id + raise ValueError('Unknown type kind %d' % id) return TypeKind._kinds[id] def __repr__(self): @@ -1990,6 +2000,11 @@ def from_source(cls, filename, args=None, unsaved_files=None, options=0, """ if args is None: args = [] + else: + # make a copy, because we're modifying the list right below + args = list(args) + + args.append('-fno-color-diagnostics') if unsaved_files is None: unsaved_files = [] @@ -1999,7 +2014,7 @@ def from_source(cls, filename, args=None, unsaved_files=None, options=0, args_array = None if len(args) > 0: - args_array = (c_char_p * len(args))(* args) + args_array = (c_char_p * len(args))(* [encode(arg) for arg in args]) unsaved_array = None if len(unsaved_files) > 0: @@ -2008,12 +2023,12 @@ def from_source(cls, filename, args=None, unsaved_files=None, options=0, if hasattr(contents, "read"): contents = contents.read() - unsaved_array[i].name = name - unsaved_array[i].contents = contents + unsaved_array[i].name = encode(name) + unsaved_array[i].contents = encode(contents) unsaved_array[i].length = len(contents) - ptr = conf.lib.clang_parseTranslationUnit(index, filename, args_array, - len(args), unsaved_array, + ptr = conf.lib.clang_parseTranslationUnit(index, encode(filename), + args_array, len(args), unsaved_array, len(unsaved_files), options) if not ptr: @@ -2187,11 +2202,11 @@ def reparse(self, unsaved_files=None, options=0): # FIXME: It would be great to support an efficient version # of this, one day. value = value.read() - print value + print(value) if not isinstance(value, str): - raise TypeError,'Unexpected unsaved file contents.' - unsaved_files_array[i].name = name - unsaved_files_array[i].contents = value + raise TypeError('Unexpected unsaved file contents.') + unsaved_files_array[i].name = encode(name) + unsaved_files_array[i].contents = encode(value) unsaved_files_array[i].length = len(value) ptr = conf.lib.clang_reparseTranslationUnit(self, len(unsaved_files), unsaved_files_array, options) @@ -2251,13 +2266,13 @@ def codeComplete(self, path, line, column, unsaved_files=None, # FIXME: It would be great to support an efficient version # of this, one day. value = value.read() - print value + print(value) if not isinstance(value, str): - raise TypeError,'Unexpected unsaved file contents.' - unsaved_files_array[i].name = name - unsaved_files_array[i].contents = value + raise TypeError('Unexpected unsaved file contents.') + unsaved_files_array[i].name = encode(name) + unsaved_files_array[i].contents = encode(value) unsaved_files_array[i].length = len(value) - ptr = conf.lib.clang_codeCompleteAt(self, path, line, column, + ptr = conf.lib.clang_codeCompleteAt(self, encode(path), line, column, unsaved_files_array, len(unsaved_files), options) if ptr: return CodeCompletionResults(ptr) @@ -2285,7 +2300,7 @@ class File(ClangObject): @staticmethod def from_name(translation_unit, file_name): """Retrieve a file handle within the given translation unit.""" - return File(conf.lib.clang_getFile(translation_unit, file_name)) + return File(conf.lib.clang_getFile(translation_unit, encode(file_name))) @property def name(self): @@ -2378,7 +2393,7 @@ def arguments(self): Invariant : the first argument is the compiler executable """ length = conf.lib.clang_CompileCommand_getNumArgs(self.cmd) - for i in xrange(length): + for i in range(length): yield conf.lib.clang_CompileCommand_getArg(self.cmd, i) class CompileCommands(object): @@ -2430,8 +2445,8 @@ def fromDirectory(buildDir): """Builds a CompilationDatabase from the database found in buildDir""" errorCode = c_uint() try: - cdb = conf.lib.clang_CompilationDatabase_fromDirectory(buildDir, - byref(errorCode)) + cdb = conf.lib.clang_CompilationDatabase_fromDirectory(encode(buildDir), + byref(errorCode)) except CompilationDatabaseError as e: raise CompilationDatabaseError(int(errorCode.value), "CompilationDatabase loading failed") @@ -2443,7 +2458,7 @@ def getCompileCommands(self, filename): build filename. Returns None if filename is not found in the database. """ return conf.lib.clang_CompilationDatabase_getCompileCommands(self, - filename) + encode(filename)) class Token(Structure): """Represents a single token from the preprocessor. @@ -3079,7 +3094,7 @@ def register_functions(lib, ignore_errors): def register(item): return register_function(lib, item, ignore_errors) - map(register, functionList) + list(map(register, functionList)) class Config: library_path = None diff --git a/plugin/clang_complete.vim b/plugin/clang_complete.vim index ef20fa79..df791f1b 100644 --- a/plugin/clang_complete.vim +++ b/plugin/clang_complete.vim @@ -13,19 +13,26 @@ endif let g:clang_complete_loaded = 1 au FileType c,cpp,objc,objcpp call ClangCompleteInit() -au FileType c.*,cpp.*,objc.*,objcpp.* call ClangCompleteInit() - -let b:clang_parameters = '' -let b:clang_user_options = '' -let b:my_changedtick = 0 " Store plugin path, as this is available only when sourcing the file, " not during a function call. let s:plugin_path = escape(expand(':p:h'), '\') +let b:clang_parameters = '' +let b:clang_user_options = '' +let b:my_changedtick = 0 + " Older versions of Vim can't check if a map was made with let s:use_maparg = v:version > 703 || (v:version == 703 && has('patch32')) +if has('python') + let s:py_cmd = 'python' + let s:pyfile_cmd = 'pyfile' +elseif has('python3') + let s:py_cmd = 'python3' + let s:pyfile_cmd = 'py3file' +endif + function! s:ClangCompleteInit() let l:bufname = bufname("%") if l:bufname == '' @@ -154,7 +161,7 @@ function! s:ClangCompleteInit() let b:clang_parameters = '-x objective-c' endif - if &filetype == 'cpp' || &filetype == 'objcpp' + if &filetype == 'cpp' || &filetype == 'objcpp' || &filetype =~ 'cpp.*' || &filetype =~ 'objcpp.*' let b:clang_parameters .= '++' endif @@ -176,7 +183,7 @@ function! s:ClangCompleteInit() return endif - python snippetsInit() + execute s:py_cmd 'snippetsInit()' if g:clang_make_default_keymappings == 1 inoremap LaunchCompletion() @@ -214,7 +221,6 @@ function! s:ClangCompleteInit() if g:clang_omnicppcomplete_compliance == 0 setlocal omnifunc=ClangComplete endif - endfunction function! LoadUserOptions() @@ -268,14 +274,12 @@ for s:flag in values(s:flagInfo) endfor let s:flagPattern = '\%(' . join(s:flagPatterns, '\|') . '\)' - function! s:processFilename(filename, root) " Handle Unix absolute path if matchstr(a:filename, '\C^[''"\\]\=/') != '' let l:filename = a:filename " Handle Windows absolute path - elseif s:isWindows() - \ && matchstr(a:filename, '\C^"\=[a-zA-Z]:[/\\]') != '' + elseif s:isWindows() && matchstr(a:filename, '\C^"\=[a-zA-Z]:[/\\]') != '' let l:filename = a:filename " Convert relative path to absolute path else @@ -312,24 +316,34 @@ function! s:parseConfig() endif let l:root = fnamemodify(l:local_conf, ':p:h') . l:sep - let l:opts = readfile(l:local_conf) - for l:opt in l:opts - " Ensure passed filenames are absolute. Only performed on flags which - " require a filename/directory as an argument, as specified in s:flagInfo - if matchstr(l:opt, '\C^\s*' . s:flagPattern . '\s*') != '' - let l:flag = substitute(l:opt, '\C^\s*\(' . s:flagPattern . '\).*' - \ , '\1', 'g') - let l:flag = substitute(l:flag, '^\(.\{-}\)\s*$', '\1', 'g') - let l:filename = substitute(l:opt, - \ '\C^\s*' . s:flagPattern . '\(.\{-}\)\s*$', - \ '\1', 'g') - let l:filename = s:processFilename(l:filename, l:root) - let l:opt = s:flagInfo[l:flag].output . l:filename - endif - let b:clang_user_options .= ' ' . l:opt - endfor + if 0 + let g:opt_processed = [] + + for l:opt in l:opts + " Ensure passed filenames are absolute. Only performed on flags which + " require a filename/directory as an argument, as specified in s:flagInfo + if matchstr(l:opt, '\C^\s*' . s:flagPattern . '\s*') != '' + let l:flag = substitute(l:opt, '\C^\s*\(' . s:flagPattern . '\).*', '\1', 'g') + let l:flag = substitute(l:flag, '^\(.\{-}\)\s*$', '\1', 'g') + let l:filename = substitute(l:opt, + \ '\C^\s*' . s:flagPattern . '\(.\{-}\)\s*$', + \ '\1', 'g') + " [j5shi]: no need to process filename for my options + " let l:filename = s:processFilename(l:filename, l:root) + echo l:opt + let l:opt = s:flagInfo[l:flag].output . l:filename + echo l:opt + endif + + let g:opt_processed = add(g:opt_processed, l:opt) + endfor + + let b:clang_user_options .= join(g:opt_processed, ' ') + else + let b:clang_user_options .= join(l:opts, ' ') + endif endfunction function! s:findCompilationDatase(cdb) @@ -357,7 +371,7 @@ function! s:parsePathOption() endfunction function! s:initClangCompletePython() - if !has('python') + if !has('python') && !has('python3') echoe 'clang_complete: No python support available.' echoe 'Cannot use clang library' echoe 'Compile vim with python support to use libclang' @@ -366,13 +380,14 @@ function! s:initClangCompletePython() " Only parse the python library once if !exists('s:libclang_loaded') - python import sys + execute s:py_cmd 'import sys' + execute s:py_cmd 'import json' - exe 'python sys.path = ["' . s:plugin_path . '"] + sys.path' - exe 'pyfile ' . fnameescape(s:plugin_path) . '/libclang.py' + execute s:py_cmd 'sys.path = ["' . s:plugin_path . '"] + sys.path' + execute s:pyfile_cmd fnameescape(s:plugin_path) . '/libclang.py' try - exe 'python from snippets.' . g:clang_snippets_engine . ' import *' + execute s:py_cmd 'from snippets.' . g:clang_snippets_engine . ' import *' let l:snips_loaded = 1 catch let l:snips_loaded = 0 @@ -380,18 +395,20 @@ function! s:initClangCompletePython() if l:snips_loaded == 0 " Oh yeah, vimscript rocks! " Putting that echoe inside the catch, will throw an error, and - " display spurious unwanted errors… + " display spurious unwanted error echoe 'Snippets engine ' . g:clang_snippets_engine . ' not found' return 0 endif - py vim.command('let l:res = ' + str(initClangComplete(vim.eval('g:clang_complete_lib_flags'), vim.eval('g:clang_compilation_database'), vim.eval('g:clang_library_path')))) + execute s:py_cmd "vim.command('let l:res = ' + str(initClangComplete(vim.eval('g:clang_complete_lib_flags')," + \."vim.eval('g:clang_compilation_database')," + \."vim.eval('g:clang_library_path'))))" if l:res == 0 return 0 endif let s:libclang_loaded = 1 endif - python WarmupCache() + execute s:py_cmd 'WarmupCache()' return 1 endfunction @@ -402,7 +419,7 @@ function! s:DoPeriodicQuickFix() endif let b:my_changedtick = b:changedtick - python updateCurrentDiagnostics() + execute s:py_cmd 'updateCurrentDiagnostics()' call s:ClangQuickFix() endfunction @@ -411,8 +428,8 @@ function! s:ClangQuickFix() syntax clear SpellBad syntax clear SpellLocal - python vim.command('let l:list = ' + str(getCurrentQuickFixList())) - python highlightCurrentDiagnostics() + execute s:py_cmd "vim.command('let l:list = ' + json.dumps(getCurrentQuickFixList()))" + execute s:py_cmd 'highlightCurrentDiagnostics()' if g:clang_complete_copen == 1 " We should get back to the original buffer @@ -464,11 +481,11 @@ function! ClangComplete(findstart, base) let l:time_start = reltime() endif - python snippetsReset() + execute s:py_cmd 'snippetsReset()' - python completions, timer = getCurrentCompletions(vim.eval('a:base')) - python vim.command('let l:res = ' + completions) - python timer.registerEvent("Load into vimscript") + execute s:py_cmd "completions, timer = getCurrentCompletions(vim.eval('a:base'))" + execute s:py_cmd "vim.command('let l:res = ' + completions)" + execute s:py_cmd "timer.registerEvent('Load into vimscript')" if g:clang_make_default_keymappings == 1 if s:use_maparg @@ -489,7 +506,7 @@ function! ClangComplete(findstart, base) augroup end let b:snippet_chosen = 0 - python timer.finish() + execute s:py_cmd 'timer.finish()' if g:clang_debug == 1 echom 'clang_complete: completion time ' . split(reltimestr(reltime(l:time_start)))[0] @@ -560,7 +577,7 @@ function! s:TriggerSnippet() call s:StopMonitoring() " Trigger the snippet - python snippetsTrigger() + execute s:py_cmd 'snippetsTrigger()' if g:clang_close_preview pclose @@ -621,7 +638,7 @@ endfunction function! s:GotoDeclaration(preview) try - python gotoDeclaration(vim.eval('a:preview') == '1') + execute s:py_cmd "gotoDeclaration(vim.eval('a:preview') == '1')" 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/kinds.py b/plugin/kinds.py new file mode 100755 index 00000000..4325c6fd --- /dev/null +++ b/plugin/kinds.py @@ -0,0 +1,196 @@ +# !! GENERATED FILE, DO NOT EDIT +kinds = { +1 : 't', # CXCursor_UnexposedDecl A declaration whose specific kind is not exposed via this interface. +2 : 't', # CXCursor_StructDecl A C or C++ struct. +3 : 't', # CXCursor_UnionDecl A C or C++ union. +4 : 't', # CXCursor_ClassDecl A C++ class. +5 : 't', # CXCursor_EnumDecl An enumeration. +6 : 'm', # CXCursor_FieldDecl A field (in C) or non-static data member (in C++) in a struct, union, or C++ class. +7 : 'e', # CXCursor_EnumConstantDecl An enumerator constant. +8 : 'f', # CXCursor_FunctionDecl A function. +9 : 'v', # CXCursor_VarDecl A variable. +10 : 'a', # CXCursor_ParmDecl A function or method parameter. +11 : '11', # CXCursor_ObjCInterfaceDecl An Objective-C @interface. +12 : '12', # CXCursor_ObjCCategoryDecl An Objective-C @interface for a category. +13 : '13', # CXCursor_ObjCProtocolDecl An Objective-C @protocol declaration. +14 : '14', # CXCursor_ObjCPropertyDecl An Objective-C @property declaration. +15 : '15', # CXCursor_ObjCIvarDecl An Objective-C instance variable. +16 : '16', # CXCursor_ObjCInstanceMethodDecl An Objective-C instance method. +17 : '17', # CXCursor_ObjCClassMethodDecl An Objective-C class method. +18 : '18', # CXCursor_ObjCImplementationDecl An Objective-C @implementation. +19 : '19', # CXCursor_ObjCCategoryImplDecl An Objective-C @implementation for a category. +20 : 't', # CXCursor_TypedefDecl A typedef. +21 : 'f', # CXCursor_CXXMethod A C++ class method. +22 : 'n', # CXCursor_Namespace A C++ namespace. +23 : '23', # CXCursor_LinkageSpec A linkage specification, e.g. 'extern "C"'. +24 : '+', # CXCursor_Constructor A C++ constructor. +25 : '~', # CXCursor_Destructor A C++ destructor. +26 : '26', # CXCursor_ConversionFunction A C++ conversion function. +27 : 'a', # CXCursor_TemplateTypeParameter A C++ template type parameter. +28 : 'a', # CXCursor_NonTypeTemplateParameter A C++ non-type template parameter. +29 : 'a', # CXCursor_TemplateTemplateParameter A C++ template template parameter. +30 : 'f', # CXCursor_FunctionTemplate A C++ function template. +31 : 'p', # CXCursor_ClassTemplate A C++ class template. +32 : '32', # CXCursor_ClassTemplatePartialSpecialization A C++ class template partial specialization. +33 : 'n', # CXCursor_NamespaceAlias A C++ namespace alias declaration. +34 : '34', # CXCursor_UsingDirective A C++ using directive. +35 : '35', # CXCursor_UsingDeclaration A C++ using declaration. +36 : 't', # CXCursor_TypeAliasDecl A C++ alias declaration +37 : '37', # CXCursor_ObjCSynthesizeDecl An Objective-C @synthesize definition. +38 : '38', # CXCursor_ObjCDynamicDecl An Objective-C @dynamic definition. +39 : '39', # CXCursor_CXXAccessSpecifier An access specifier. +40 : '40', # CXCursor_ObjCSuperClassRef An access specifier. +41 : '41', # CXCursor_ObjCProtocolRef An access specifier. +42 : '42', # CXCursor_ObjCClassRef An access specifier. +43 : '43', # CXCursor_TypeRef A reference to a type declaration. +44 : '44', # CXCursor_CXXBaseSpecifier A reference to a type declaration. +45 : '45', # CXCursor_TemplateRef A reference to a class template, function template, template template parameter, or class template partial specialization. +46 : '46', # CXCursor_NamespaceRef A reference to a namespace or namespace alias. +47 : '47', # CXCursor_MemberRef A reference to a member of a struct, union, or class that occurs in some non-expression context, e.g., a designated initializer. +48 : '48', # CXCursor_LabelRef A reference to a labeled statement. +49 : '49', # CXCursor_OverloadedDeclRef A reference to a set of overloaded functions or function templates that has not yet been resolved to a specific function or function template. +50 : '50', # CXCursor_VariableRef A reference to a variable that occurs in some non-expression context, e.g., a C++ lambda capture list. +70 : '70', # CXCursor_InvalidFile A reference to a variable that occurs in some non-expression context, e.g., a C++ lambda capture list. +71 : '71', # CXCursor_NoDeclFound A reference to a variable that occurs in some non-expression context, e.g., a C++ lambda capture list. +72 : 'u', # CXCursor_NotImplemented A reference to a variable that occurs in some non-expression context, e.g., a C++ lambda capture list. +73 : '73', # CXCursor_InvalidCode A reference to a variable that occurs in some non-expression context, e.g., a C++ lambda capture list. +100 : '100', # CXCursor_UnexposedExpr An expression whose specific kind is not exposed via this interface. +101 : '101', # CXCursor_DeclRefExpr An expression that refers to some value declaration, such as a function, variable, or enumerator. +102 : '102', # CXCursor_MemberRefExpr An expression that refers to a member of a struct, union, class, Objective-C class, etc. +103 : '103', # CXCursor_CallExpr An expression that calls a function. +104 : '104', # CXCursor_ObjCMessageExpr An expression that sends a message to an Objective-C object or class. +105 : '105', # CXCursor_BlockExpr An expression that represents a block literal. +106 : '106', # CXCursor_IntegerLiteral An integer literal. +107 : '107', # CXCursor_FloatingLiteral A floating point number literal. +108 : '108', # CXCursor_ImaginaryLiteral An imaginary number literal. +109 : '109', # CXCursor_StringLiteral A string literal. +110 : '110', # CXCursor_CharacterLiteral A character literal. +111 : '111', # CXCursor_ParenExpr A parenthesized expression, e.g. "(1)". +112 : '112', # CXCursor_UnaryOperator This represents the unary-expression's (except sizeof and alignof). +113 : '113', # CXCursor_ArraySubscriptExpr [C99 6.5.2.1] Array Subscripting. +114 : '114', # CXCursor_BinaryOperator A builtin binary operation expression such as "x + y" or "x <= y". +115 : '115', # CXCursor_CompoundAssignOperator Compound assignment such as "+=". +116 : '116', # CXCursor_ConditionalOperator The ?: ternary operator. +117 : '117', # CXCursor_CStyleCastExpr An explicit cast in C (C99 6.5.4) or a C-style cast in C++ (C++ [expr.cast]), which uses the syntax (Type)expr. +118 : '118', # CXCursor_CompoundLiteralExpr [C99 6.5.2.5] +119 : '119', # CXCursor_InitListExpr Describes an C or C++ initializer list. +120 : '120', # CXCursor_AddrLabelExpr The GNU address of label extension, representing &&label. +121 : '121', # CXCursor_StmtExpr This is the GNU Statement Expression extension: ({int X=4; X;}) +122 : '122', # CXCursor_GenericSelectionExpr Represents a C11 generic selection. +123 : '123', # CXCursor_GNUNullExpr Implements the GNU __null extension, which is a name for a null pointer constant that has integral type (e.g., int or long) and is the same size and alignment as a pointer. +124 : '124', # CXCursor_CXXStaticCastExpr C++'s static_cast<> expression. +125 : '125', # CXCursor_CXXDynamicCastExpr C++'s dynamic_cast<> expression. +126 : '126', # CXCursor_CXXReinterpretCastExpr C++'s reinterpret_cast<> expression. +127 : '127', # CXCursor_CXXConstCastExpr C++'s const_cast<> expression. +128 : '128', # CXCursor_CXXFunctionalCastExpr Represents an explicit C++ type conversion that uses "functional" notion (C++ [expr.type.conv]). +129 : '129', # CXCursor_CXXTypeidExpr A C++ typeid expression (C++ [expr.typeid]). +130 : '130', # CXCursor_CXXBoolLiteralExpr [C++ 2.13.5] C++ Boolean Literal. +131 : '131', # CXCursor_CXXNullPtrLiteralExpr [C++0x 2.14.7] C++ Pointer Literal. +132 : '132', # CXCursor_CXXThisExpr Represents the "this" expression in C++ +133 : '133', # CXCursor_CXXThrowExpr [C++ 15] C++ Throw Expression. +134 : '134', # CXCursor_CXXNewExpr A new expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)". +135 : '135', # CXCursor_CXXDeleteExpr A delete expression for memory deallocation and destructor calls, e.g. "delete[] pArray". +136 : '136', # CXCursor_UnaryExpr A unary expression. +137 : '137', # CXCursor_ObjCStringLiteral An Objective-C string literal i.e. "foo". +138 : '138', # CXCursor_ObjCEncodeExpr An Objective-C @encode expression. +139 : '139', # CXCursor_ObjCSelectorExpr An Objective-C @selector expression. +140 : '140', # CXCursor_ObjCProtocolExpr An Objective-C @protocol expression. +141 : '141', # CXCursor_ObjCBridgedCastExpr An Objective-C "bridged" cast expression, which casts between Objective-C pointers and C pointers, transferring ownership in the process. +142 : '142', # CXCursor_PackExpansionExpr Represents a C++0x pack expansion that produces a sequence of expressions. +143 : '143', # CXCursor_SizeOfPackExpr Represents an expression that computes the length of a parameter pack. +144 : '144', # CXCursor_LambdaExpr None +145 : '145', # CXCursor_ObjCBoolLiteralExpr Objective-c Boolean Literal. +146 : '146', # CXCursor_ObjCSelfExpr Represents the "self" expression in an Objective-C method. +147 : '147', # CXCursor_OMPArraySectionExpr OpenMP 4.0 [2.4, Array Section]. +200 : '200', # CXCursor_UnexposedStmt A statement whose specific kind is not exposed via this interface. +201 : '201', # CXCursor_LabelStmt A labelled statement in a function. +202 : '202', # CXCursor_CompoundStmt A group of statements like { stmt stmt }. +203 : '203', # CXCursor_CaseStmt A case statement. +204 : '204', # CXCursor_DefaultStmt A default statement. +205 : '205', # CXCursor_IfStmt An if statement +206 : '206', # CXCursor_SwitchStmt A switch statement. +207 : '207', # CXCursor_WhileStmt A while statement. +208 : '208', # CXCursor_DoStmt A do statement. +209 : '209', # CXCursor_ForStmt A for statement. +210 : '210', # CXCursor_GotoStmt A goto statement. +211 : '211', # CXCursor_IndirectGotoStmt An indirect goto statement. +212 : '212', # CXCursor_ContinueStmt A continue statement. +213 : '213', # CXCursor_BreakStmt A break statement. +214 : '214', # CXCursor_ReturnStmt A return statement. +215 : '215', # CXCursor_GCCAsmStmt A GCC inline assembly statement extension. +215 : '215', # CXCursor_AsmStmt A GCC inline assembly statement extension. +216 : '216', # CXCursor_ObjCAtTryStmt Objective-C's overall @try-@catch-@finally statement. +217 : '217', # CXCursor_ObjCAtCatchStmt Objective-C's @catch statement. +218 : '218', # CXCursor_ObjCAtFinallyStmt Objective-C's @finally statement. +219 : '219', # CXCursor_ObjCAtThrowStmt Objective-C's @throw statement. +220 : '220', # CXCursor_ObjCAtSynchronizedStmt Objective-C's @synchronized statement. +221 : '221', # CXCursor_ObjCAutoreleasePoolStmt Objective-C's autorelease pool statement. +222 : '222', # CXCursor_ObjCForCollectionStmt Objective-C's collection statement. +223 : '223', # CXCursor_CXXCatchStmt C++'s catch statement. +224 : '224', # CXCursor_CXXTryStmt C++'s try statement. +225 : '225', # CXCursor_CXXForRangeStmt C++'s for (* : *) statement. +226 : '226', # CXCursor_SEHTryStmt Windows Structured Exception Handling's try statement. +227 : '227', # CXCursor_SEHExceptStmt Windows Structured Exception Handling's except statement. +228 : '228', # CXCursor_SEHFinallyStmt Windows Structured Exception Handling's finally statement. +229 : '229', # CXCursor_MSAsmStmt A MS inline assembly statement extension. +230 : '230', # CXCursor_NullStmt The null statement ";": C99 6.8.3p3. +231 : '231', # CXCursor_DeclStmt Adaptor class for mixing declarations with statements and expressions. +232 : '232', # CXCursor_OMPParallelDirective OpenMP parallel directive. +233 : '233', # CXCursor_OMPSimdDirective OpenMP SIMD directive. +234 : '234', # CXCursor_OMPForDirective OpenMP for directive. +235 : '235', # CXCursor_OMPSectionsDirective OpenMP sections directive. +236 : '236', # CXCursor_OMPSectionDirective OpenMP section directive. +237 : '237', # CXCursor_OMPSingleDirective OpenMP single directive. +238 : '238', # CXCursor_OMPParallelForDirective OpenMP parallel for directive. +239 : '239', # CXCursor_OMPParallelSectionsDirective OpenMP parallel sections directive. +240 : '240', # CXCursor_OMPTaskDirective OpenMP task directive. +241 : '241', # CXCursor_OMPMasterDirective OpenMP master directive. +242 : '242', # CXCursor_OMPCriticalDirective OpenMP critical directive. +243 : '243', # CXCursor_OMPTaskyieldDirective OpenMP taskyield directive. +244 : '244', # CXCursor_OMPBarrierDirective OpenMP barrier directive. +245 : '245', # CXCursor_OMPTaskwaitDirective OpenMP taskwait directive. +246 : '246', # CXCursor_OMPFlushDirective OpenMP flush directive. +247 : '247', # CXCursor_SEHLeaveStmt Windows Structured Exception Handling's leave statement. +248 : '248', # CXCursor_OMPOrderedDirective OpenMP ordered directive. +249 : '249', # CXCursor_OMPAtomicDirective OpenMP atomic directive. +250 : '250', # CXCursor_OMPForSimdDirective OpenMP for SIMD directive. +251 : '251', # CXCursor_OMPParallelForSimdDirective OpenMP parallel for SIMD directive. +252 : '252', # CXCursor_OMPTargetDirective OpenMP target directive. +253 : '253', # CXCursor_OMPTeamsDirective OpenMP teams directive. +254 : '254', # CXCursor_OMPTaskgroupDirective OpenMP taskgroup directive. +255 : '255', # CXCursor_OMPCancellationPointDirective OpenMP cancellation point directive. +256 : '256', # CXCursor_OMPCancelDirective OpenMP cancel directive. +257 : '257', # CXCursor_OMPTargetDataDirective OpenMP target data directive. +258 : '258', # CXCursor_OMPTaskLoopDirective OpenMP taskloop directive. +259 : '259', # CXCursor_OMPTaskLoopSimdDirective OpenMP taskloop simd directive. +260 : '260', # CXCursor_OMPDistributeDirective OpenMP distribute directive. +300 : '300', # CXCursor_TranslationUnit Cursor that represents the translation unit itself. +400 : '400', # CXCursor_UnexposedAttr An attribute whose specific kind is not exposed via this interface. +401 : '401', # CXCursor_IBActionAttr An attribute whose specific kind is not exposed via this interface. +402 : '402', # CXCursor_IBOutletAttr An attribute whose specific kind is not exposed via this interface. +403 : '403', # CXCursor_IBOutletCollectionAttr An attribute whose specific kind is not exposed via this interface. +404 : '404', # CXCursor_CXXFinalAttr An attribute whose specific kind is not exposed via this interface. +405 : '405', # CXCursor_CXXOverrideAttr An attribute whose specific kind is not exposed via this interface. +406 : '406', # CXCursor_AnnotateAttr An attribute whose specific kind is not exposed via this interface. +407 : '407', # CXCursor_AsmLabelAttr An attribute whose specific kind is not exposed via this interface. +408 : '408', # CXCursor_PackedAttr An attribute whose specific kind is not exposed via this interface. +409 : '409', # CXCursor_PureAttr An attribute whose specific kind is not exposed via this interface. +410 : '410', # CXCursor_ConstAttr An attribute whose specific kind is not exposed via this interface. +411 : '411', # CXCursor_NoDuplicateAttr An attribute whose specific kind is not exposed via this interface. +412 : '412', # CXCursor_CUDAConstantAttr An attribute whose specific kind is not exposed via this interface. +413 : '413', # CXCursor_CUDADeviceAttr An attribute whose specific kind is not exposed via this interface. +414 : '414', # CXCursor_CUDAGlobalAttr An attribute whose specific kind is not exposed via this interface. +415 : '415', # CXCursor_CUDAHostAttr An attribute whose specific kind is not exposed via this interface. +416 : '416', # CXCursor_CUDASharedAttr An attribute whose specific kind is not exposed via this interface. +417 : '417', # CXCursor_VisibilityAttr An attribute whose specific kind is not exposed via this interface. +418 : '418', # CXCursor_DLLExport An attribute whose specific kind is not exposed via this interface. +419 : '419', # CXCursor_DLLImport An attribute whose specific kind is not exposed via this interface. +500 : '500', # CXCursor_PreprocessingDirective An attribute whose specific kind is not exposed via this interface. +501 : 'd', # CXCursor_MacroDefinition An attribute whose specific kind is not exposed via this interface. +502 : '502', # CXCursor_MacroExpansion An attribute whose specific kind is not exposed via this interface. +502 : '502', # CXCursor_MacroInstantiation An attribute whose specific kind is not exposed via this interface. +503 : '503', # CXCursor_InclusionDirective An attribute whose specific kind is not exposed via this interface. +600 : '600', # CXCursor_ModuleImportDecl A module import declaration. +601 : 'ta', # CXCursor_TypeAliasTemplateDecl A module import declaration. +700 : 'oc', # CXCursor_OverloadCandidate A code completion overload candidate. +} diff --git a/plugin/libclang.py b/plugin/libclang.py index 4cb7f125..7c31f855 100644 --- a/plugin/libclang.py +++ b/plugin/libclang.py @@ -1,3 +1,5 @@ +from __future__ import print_function + from clang.cindex import * import vim import time @@ -5,6 +7,18 @@ import os import shlex +from kinds import kinds + +def decode(value): + import sys + if sys.version_info[0] == 2: + return value + + try: + return value.decode('utf-8') + except AttributeError: + return value + # Check if libclang is able to find the builtin include files. # # libclang sometimes fails to correctly locate its builtin include files. This @@ -15,7 +29,7 @@ def canFindBuiltinHeaders(index, args = []): currentFile = ("test.c", '#include "stddef.h"') try: tu = index.parse("test.c", args, [currentFile], flags) - except TranslationUnitLoadError, e: + except TranslationUnitLoadError as e: return 0 return len(tu.diagnostics) == 0 @@ -40,15 +54,10 @@ def getBuiltinHeaderPath(library_path): for path in knownPaths: try: - files = os.listdir(path) - if len(files) >= 1: - files = sorted(files) - subDir = files[-1] - else: - subDir = '.' - path = path + "/" + subDir + "/include/" - arg = "-I" + path - if canFindBuiltinHeaders(index, [arg]): + subDirs = [f for f in os.listdir(path) if os.path.isdir(path + "/" + f)] + subDirs = sorted(subDirs) or ['.'] + path = path + "/" + subDirs[-1] + "/include" + if canFindBuiltinHeaders(index, ["-I" + path]): return path except: pass @@ -71,7 +80,7 @@ def initClangComplete(clang_complete_flags, clang_compilation_database, \ try: index = Index.create() - except Exception, e: + except Exception as e: if library_path: suggestion = "Are you sure '%s' contains libclang?" % library_path else: @@ -82,9 +91,9 @@ def initClangComplete(clang_complete_flags, clang_compilation_database, \ else: exception_msg = '' - print '''Loading libclang failed, completion won't be available. %s + print('''Loading libclang failed, completion won't be available. %s %s - ''' % (suggestion, exception_msg) + ''' % (suggestion, exception_msg)) return 0 global builtinHeaderPath @@ -93,12 +102,20 @@ def initClangComplete(clang_complete_flags, clang_compilation_database, \ builtinHeaderPath = getBuiltinHeaderPath(library_path) if not builtinHeaderPath: - print "WARNING: libclang can not find the builtin includes." - print " This will cause slow code completion." - print " Please report the problem." - + print("WARNING: libclang can not find the builtin includes.") + print(" This will cause slow code completion.") + print(" Please report the problem.") + + # Cache of translation units. Maps paths of files: + # : { + # 'tu': , + # 'args': , + # } + # New cache entry for the same path, but with different list of arguments, + # overwrite previously cached data. global translationUnits translationUnits = dict() + global complete_flags complete_flags = int(clang_complete_flags) global compilation_database @@ -124,18 +141,18 @@ def __init__(self, debug, file, line, column, params): return content = vim.current.line - print " " - print "libclang code completion" - print "========================" - print "Command: clang %s -fsyntax-only " % " ".join(params['args']), - print "-Xclang -code-completion-at=%s:%d:%d %s" % (file, line, column, file) - print "cwd: %s" % params['cwd'] - print "File: %s" % file - print "Line: %d, Column: %d" % (line, column) - print " " - print "%s" % content - - print " " + print(" ") + print("libclang code completion") + print("========================") + print("Command: clang %s -fsyntax-only " % " ".join(decode(params['args'])), end=' ') + print("-Xclang -code-completion-at=%s:%d:%d %s" % (file, line, column, file)) + print("cwd: %s" % params['cwd']) + print("File: %s" % file) + print("Line: %d, Column: %d" % (line, column)) + print(" ") + print("%s" % content) + + print(" ") current = time.time() self._start = current @@ -160,18 +177,19 @@ def finish(self): for event in self._events: name, since_last = event percent = 1 / overall * since_last * 100 - print "libclang code completion - %25s: %.3fs (%5.1f%%)" % \ - (name, since_last, percent) + print("libclang code completion - %25s: %.3fs (%5.1f%%)" % \ + (name, since_last, percent)) - print " " - print "Overall: %.3f s" % overall - print "========================" - print " " + print(" ") + print("Overall: %.3f s" % overall) + print("========================") + print(" ") def getCurrentTranslationUnit(args, currentFile, fileName, timer, update = False): - tu = translationUnits.get(fileName) - if tu != None: + tuCache = translationUnits.get(fileName) + if tuCache is not None and tuCache['args'] == args: + tu = tuCache['tu'] if update: tu.reparse([currentFile]) timer.registerEvent("Reparsing") @@ -182,10 +200,10 @@ def getCurrentTranslationUnit(args, currentFile, fileName, timer, try: tu = index.parse(fileName, args, [currentFile], flags) timer.registerEvent("First parse") - except TranslationUnitLoadError, e: + except TranslationUnitLoadError as e: return None - translationUnits[fileName] = tu + translationUnits[fileName] = { 'tu': tu, 'args': args } # Reparse to initialize the PCH cache even for auto completion # This should be done by index.parse(), however it is not. @@ -202,7 +220,7 @@ def splitOptions(options): def getQuickFix(diagnostic): # Some diagnostics have no file, e.g. "too many errors emitted, stopping now" if diagnostic.location.file: - filename = diagnostic.location.file.name + filename = decode(diagnostic.location.file.name) else: filename = "" @@ -211,7 +229,7 @@ def getQuickFix(diagnostic): elif diagnostic.severity == diagnostic.Note: type = 'I' elif diagnostic.severity == diagnostic.Warning: - if "argument unused during compilation" in diagnostic.spelling: + if "argument unused during compilation" in decode(diagnostic.spelling): return None type = 'W' elif diagnostic.severity == diagnostic.Error: @@ -224,11 +242,11 @@ def getQuickFix(diagnostic): return dict({ 'bufnr' : int(vim.eval("bufnr('" + filename + "', 1)")), 'lnum' : diagnostic.location.line, 'col' : diagnostic.location.column, - 'text' : diagnostic.spelling, + 'text' : decode(diagnostic.spelling), 'type' : type}) def getQuickFixList(tu): - return filter (None, map (getQuickFix, tu.diagnostics)) + return [_f for _f in map (getQuickFix, tu.diagnostics) if _f] def highlightRange(range, hlGroup): pattern = '/\%' + str(range.start.line) + 'l' + '\%' \ @@ -238,6 +256,10 @@ def highlightRange(range, hlGroup): vim.command(command) def highlightDiagnostic(diagnostic): + if diagnostic.location.file is None or \ + decode(diagnostic.location.file.name) != vim.eval('expand("%:p")'): + return + if diagnostic.severity == diagnostic.Warning: hlGroup = 'SpellLocal' elif diagnostic.severity == diagnostic.Error: @@ -254,15 +276,16 @@ def highlightDiagnostic(diagnostic): highlightRange(range, hlGroup) def highlightDiagnostics(tu): - map (highlightDiagnostic, tu.diagnostics) + for diagnostic in tu.diagnostics: + highlightDiagnostic(diagnostic) def highlightCurrentDiagnostics(): if vim.current.buffer.name in translationUnits: - highlightDiagnostics(translationUnits[vim.current.buffer.name]) + highlightDiagnostics(translationUnits[vim.current.buffer.name]['tu']) def getCurrentQuickFixList(): if vim.current.buffer.name in translationUnits: - return getQuickFixList(translationUnits[vim.current.buffer.name]) + return getQuickFixList(translationUnits[vim.current.buffer.name]['tu']) return [] # Get the compilation parameters from the compilation database for source @@ -286,10 +309,10 @@ def getCompilationDBParams(fileName): if compilation_database: cmds = compilation_database.getCompileCommands(fileName) if cmds != None: - cwd = cmds[0].directory + cwd = decode(cmds[0].directory) args = [] skip_next = 1 # Skip compiler invocation - for arg in cmds[0].arguments: + for arg in (decode(x) for x in cmds[0].arguments): if skip_next: skip_next = 0; continue @@ -326,7 +349,7 @@ def getCompileParams(fileName): args += splitOptions(vim.eval("b:clang_user_options")) args += splitOptions(vim.eval("b:clang_parameters")) - if builtinHeaderPath: + if builtinHeaderPath and '-nobuiltininc' not in args: args.append("-I" + builtinHeaderPath) return { 'args' : args, @@ -343,7 +366,11 @@ def updateCurrentDiagnostics(): vim.current.buffer.name, timer, update = True) timer.finish() -def getCurrentCompletionResults(line, column, args, currentFile, fileName, +def getCurrentCompletionResults(line, + column, + args, + currentFile, + fileName, timer): tu = getCurrentTranslationUnit(args, currentFile, fileName, timer) @@ -352,13 +379,32 @@ def getCurrentCompletionResults(line, column, args, currentFile, fileName, if tu == None: return None - cr = tu.codeComplete(fileName, line, column, [currentFile], - complete_flags) + cr = tu.codeComplete(fileName, + line, + column, + [currentFile], + complete_flags) + timer.registerEvent("Code Complete") + return cr +""" +A normal dictionary will escape single quotes by doing +"\'", but vimscript expects them to be escaped as "''". +This dictionary inherits from the built-in dict and overrides +repr to call the original, then re-escape single quotes in +the way that vimscript expects +""" +class VimscriptEscapingDict(dict): + + def __repr__(self): + repr = super(VimscriptEscapingDict, self).__repr__() + new_repr = repr.replace("\\'", "''") + return new_repr + def formatResult(result): - completion = dict() + completion = VimscriptEscapingDict() returnValue = None abbr = "" word = "" @@ -372,7 +418,7 @@ def roll_out_optional(chunks): if chunk.isKindInformative() or chunk.isKindResultType() or chunk.isKindTypedText(): continue - word += chunk.spelling + word += decode(chunk.spelling) if chunk.isKindOptional(): result += roll_out_optional(chunk.string) @@ -387,7 +433,7 @@ def roll_out_optional(chunks): returnValue = chunk continue - chunk_spelling = chunk.spelling + chunk_spelling = decode(chunk.spelling) if chunk.isKindTypedText(): abbr = chunk_spelling @@ -408,7 +454,7 @@ def roll_out_optional(chunks): menu = info if returnValue: - menu = returnValue.spelling + " " + menu + menu = decode(returnValue.spelling) + " " + menu completion['word'] = snippetsAddSnippet(info, word, abbr) completion['abbr'] = abbr @@ -424,6 +470,7 @@ def roll_out_optional(chunks): class CompleteThread(threading.Thread): + def __init__(self, line, column, currentFile, fileName, params, timer): threading.Thread.__init__(self) # Complete threads are daemon threads. Python and consequently vim does not @@ -451,18 +498,29 @@ def run(self): # not locked The user does not see any delay, as we just pause # a background thread. time.sleep(0.1) - getCurrentTranslationUnit(self.args, self.currentFile, self.fileName, + + getCurrentTranslationUnit(self.args, + self.currentFile, + self.fileName, self.timer) else: - self.result = getCurrentCompletionResults(self.line, self.column, - self.args, self.currentFile, - self.fileName, self.timer) + self.result = getCurrentCompletionResults(self.line, + self.column, + self.args, + self.currentFile, + self.fileName, + self.timer) def WarmupCache(): params = getCompileParams(vim.current.buffer.name) timer = CodeCompleteTimer(0, "", -1, -1, params) - t = CompleteThread(-1, -1, getCurrentFile(), vim.current.buffer.name, - params, timer) + + t = CompleteThread(-1, + -1, + getCurrentFile(), + vim.current.buffer.name, + params, + timer) t.start() def getCurrentCompletions(base): @@ -487,8 +545,8 @@ def getCurrentCompletions(base): cr = t.result if cr is None: - print "Cannot parse this source file. The following arguments " \ - + "are used for clang: " + " ".join(params['args']) + print("Cannot parse this source file. The following arguments " + + "are used for clang: " + " ".join(decode(params['args']))) return (str([]), timer) results = cr.results @@ -496,20 +554,20 @@ def getCurrentCompletions(base): timer.registerEvent("Count # Results (%s)" % str(len(results))) if base != "": - results = filter(lambda x: getAbbr(x.string).startswith(base), results) + results = [x for x in results if getAbbr(x.string).startswith(base)] timer.registerEvent("Filter") if sorting == 'priority': getPriority = lambda x: x.string.priority - results = sorted(results, None, getPriority) + results = sorted(results, key=getPriority) if sorting == 'alpha': getAbbrevation = lambda x: getAbbr(x.string).lower() - results = sorted(results, None, getAbbrevation) + results = sorted(results, key=getAbbrevation) timer.registerEvent("Sort") - result = map(formatResult, results) + result = list(map(formatResult, results)) timer.registerEvent("Format") return (str(result), timer) @@ -517,17 +575,17 @@ def getCurrentCompletions(base): def getAbbr(strings): for chunks in strings: if chunks.isKindTypedText(): - return chunks.spelling + return decode(chunks.spelling) return "" def jumpToLocation(filename, line, column, preview): - filenameEscaped = filename.replace(" ", "\\ ") + filenameEscaped = decode(filename).replace(" ", "\\ ") if preview: command = "pedit +%d %s" % (line, filenameEscaped) elif filename != vim.current.buffer.name: command = "edit %s" % filenameEscaped else: - command = "normal m'" + command = "normal! m'" try: vim.command(command) except: @@ -550,7 +608,7 @@ def gotoDeclaration(preview=True): vim.current.buffer.name, timer, update = True) if tu is None: - print "Couldn't get the TranslationUnit" + print("Couldn't get the TranslationUnit") return f = File.from_name(tu, vim.current.buffer.name) @@ -567,227 +625,4 @@ def gotoDeclaration(preview=True): timer.finish() -# Manually extracted from Index.h -# Doing it by hand is long, error prone and horrible, we must find a way -# to do that automatically. -kinds = dict({ \ -# Declarations \ - 1 : 't', # CXCursor_UnexposedDecl (A declaration whose specific kind is not \ - # exposed via this interface) \ - 2 : 't', # CXCursor_StructDecl (A C or C++ struct) \ - 3 : 't', # CXCursor_UnionDecl (A C or C++ union) \ - 4 : 't', # CXCursor_ClassDecl (A C++ class) \ - 5 : 't', # CXCursor_EnumDecl (An enumeration) \ - 6 : 'm', # CXCursor_FieldDecl (A field (in C) or non-static data member \ - # (in C++) in a struct, union, or C++ class) \ - 7 : 'e', # CXCursor_EnumConstantDecl (An enumerator constant) \ - 8 : 'f', # CXCursor_FunctionDecl (A function) \ - 9 : 'v', # CXCursor_VarDecl (A variable) \ -10 : 'a', # CXCursor_ParmDecl (A function or method parameter) \ -11 : '11', # CXCursor_ObjCInterfaceDecl (An Objective-C @interface) \ -12 : '12', # CXCursor_ObjCCategoryDecl (An Objective-C @interface for a \ - # category) \ -13 : '13', # CXCursor_ObjCProtocolDecl (An Objective-C @protocol declaration) \ -14 : '14', # CXCursor_ObjCPropertyDecl (An Objective-C @property declaration) \ -15 : '15', # CXCursor_ObjCIvarDecl (An Objective-C instance variable) \ -16 : '16', # CXCursor_ObjCInstanceMethodDecl (An Objective-C instance method) \ -17 : '17', # CXCursor_ObjCClassMethodDecl (An Objective-C class method) \ -18 : '18', # CXCursor_ObjCImplementationDec (An Objective-C @implementation) \ -19 : '19', # CXCursor_ObjCCategoryImplDecll (An Objective-C @implementation \ - # for a category) \ -20 : 't', # CXCursor_TypedefDecl (A typedef) \ -21 : 'f', # CXCursor_CXXMethod (A C++ class method) \ -22 : 'n', # CXCursor_Namespace (A C++ namespace) \ -23 : '23', # CXCursor_LinkageSpec (A linkage specification, e.g. 'extern "C"') \ -24 : '+', # CXCursor_Constructor (A C++ constructor) \ -25 : '~', # CXCursor_Destructor (A C++ destructor) \ -26 : '26', # CXCursor_ConversionFunction (A C++ conversion function) \ -27 : 'a', # CXCursor_TemplateTypeParameter (A C++ template type parameter) \ -28 : 'a', # CXCursor_NonTypeTemplateParameter (A C++ non-type template \ - # parameter) \ -29 : 'a', # CXCursor_TemplateTemplateParameter (A C++ template template \ - # parameter) \ -30 : 'f', # CXCursor_FunctionTemplate (A C++ function template) \ -31 : 'p', # CXCursor_ClassTemplate (A C++ class template) \ -32 : '32', # CXCursor_ClassTemplatePartialSpecialization (A C++ class template \ - # partial specialization) \ -33 : 'n', # CXCursor_NamespaceAlias (A C++ namespace alias declaration) \ -34 : '34', # CXCursor_UsingDirective (A C++ using directive) \ -35 : '35', # CXCursor_UsingDeclaration (A C++ using declaration) \ -36 : 't', # CXCursor_TypeAliasDecl (A C++ alias declaration) \ -37 : '37', # CXCursor_ObjCSynthesizeDecl (An Objective-C synthesize definition)\ -38 : '38', # CXCursor_ObjCDynamicDecl (An Objective-C dynamic definition) \ -39 : '39', # CXCursor_CXXAccessSpecifier (An access specifier) \ - \ -# References \ -40 : '40', # CXCursor_ObjCSuperClassRef \ -41 : '41', # CXCursor_ObjCProtocolRef \ -42 : '42', # CXCursor_ObjCClassRef \ -43 : '43', # CXCursor_TypeRef \ -44 : '44', # CXCursor_CXXBaseSpecifier \ -45 : '45', # CXCursor_TemplateRef (A reference to a class template, function \ - # template, template template parameter, or class template partial \ - # specialization) \ -46 : '46', # CXCursor_NamespaceRef (A reference to a namespace or namespace \ - # alias) \ -47 : '47', # CXCursor_MemberRef (A reference to a member of a struct, union, \ - # or class that occurs in some non-expression context, e.g., a \ - # designated initializer) \ -48 : '48', # CXCursor_LabelRef (A reference to a labeled statement) \ -49 : '49', # CXCursor_OverloadedDeclRef (A reference to a set of overloaded \ - # functions or function templates that has not yet been resolved to \ - # a specific function or function template) \ -50 : '50', # CXCursor_VariableRef \ - \ -# Error conditions \ -#70 : '70', # CXCursor_FirstInvalid \ -70 : '70', # CXCursor_InvalidFile \ -71 : '71', # CXCursor_NoDeclFound \ -72 : 'u', # CXCursor_NotImplemented \ -73 : '73', # CXCursor_InvalidCode \ - \ -# Expressions \ -100 : '100', # CXCursor_UnexposedExpr (An expression whose specific kind is \ - # not exposed via this interface) \ -101 : '101', # CXCursor_DeclRefExpr (An expression that refers to some value \ - # declaration, such as a function, varible, or enumerator) \ -102 : '102', # CXCursor_MemberRefExpr (An expression that refers to a member \ - # of a struct, union, class, Objective-C class, etc) \ -103 : '103', # CXCursor_CallExpr (An expression that calls a function) \ -104 : '104', # CXCursor_ObjCMessageExpr (An expression that sends a message \ - # to an Objective-C object or class) \ -105 : '105', # CXCursor_BlockExpr (An expression that represents a block \ - # literal) \ -106 : '106', # CXCursor_IntegerLiteral (An integer literal) \ -107 : '107', # CXCursor_FloatingLiteral (A floating point number literal) \ -108 : '108', # CXCursor_ImaginaryLiteral (An imaginary number literal) \ -109 : '109', # CXCursor_StringLiteral (A string literal) \ -110 : '110', # CXCursor_CharacterLiteral (A character literal) \ -111 : '111', # CXCursor_ParenExpr (A parenthesized expression, e.g. "(1)") \ -112 : '112', # CXCursor_UnaryOperator (This represents the unary-expression's \ - # (except sizeof and alignof)) \ -113 : '113', # CXCursor_ArraySubscriptExpr ([C99 6.5.2.1] Array Subscripting) \ -114 : '114', # CXCursor_BinaryOperator (A builtin binary operation expression \ - # such as "x + y" or "x <= y") \ -115 : '115', # CXCursor_CompoundAssignOperator (Compound assignment such as \ - # "+=") \ -116 : '116', # CXCursor_ConditionalOperator (The ?: ternary operator) \ -117 : '117', # CXCursor_CStyleCastExpr (An explicit cast in C (C99 6.5.4) or a\ - # C-style cast in C++ (C++ [expr.cast]), which uses the syntax \ - # (Type)expr) \ -118 : '118', # CXCursor_CompoundLiteralExpr ([C99 6.5.2.5]) \ -119 : '119', # CXCursor_InitListExpr (Describes an C or C++ initializer list) \ -120 : '120', # CXCursor_AddrLabelExpr (The GNU address of label extension, \ - # representing &&label) \ -121 : '121', # CXCursor_StmtExpr (This is the GNU Statement Expression \ - # extension: ({int X=4; X;}) \ -122 : '122', # CXCursor_GenericSelectionExpr (brief Represents a C11 generic \ - # selection) \ -123 : '123', # CXCursor_GNUNullExpr (Implements the GNU __null extension) \ -124 : '124', # CXCursor_CXXStaticCastExpr (C++'s static_cast<> expression) \ -125 : '125', # CXCursor_CXXDynamicCastExpr (C++'s dynamic_cast<> expression) \ -126 : '126', # CXCursor_CXXReinterpretCastExpr (C++'s reinterpret_cast<> \ - # expression) \ -127 : '127', # CXCursor_CXXConstCastExpr (C++'s const_cast<> expression) \ -128 : '128', # CXCursor_CXXFunctionalCastExpr (Represents an explicit C++ type\ - # conversion that uses "functional" notion \ - # (C++ [expr.type.conv])) \ -129 : '129', # CXCursor_CXXTypeidExpr (A C++ typeid expression \ - # (C++ [expr.typeid])) \ -130 : '130', # CXCursor_CXXBoolLiteralExpr (brief [C++ 2.13.5] C++ Boolean \ - # Literal) \ -131 : '131', # CXCursor_CXXNullPtrLiteralExpr ([C++0x 2.14.7] C++ Pointer \ - # Literal) \ -132 : '132', # CXCursor_CXXThisExpr (Represents the "this" expression in C+) \ -133 : '133', # CXCursor_CXXThrowExpr ([C++ 15] C++ Throw Expression) \ -134 : '134', # CXCursor_CXXNewExpr (A new expression for memory allocation \ - # and constructor calls) \ -135 : '135', # CXCursor_CXXDeleteExpr (A delete expression for memory \ - # deallocation and destructor calls) \ -136 : '136', # CXCursor_UnaryExpr (A unary expression) \ -137 : '137', # CXCursor_ObjCStringLiteral (An Objective-C string literal \ - # i.e. @"foo") \ -138 : '138', # CXCursor_ObjCEncodeExpr (An Objective-C \@encode expression) \ -139 : '139', # CXCursor_ObjCSelectorExpr (An Objective-C \@selector expression)\ -140 : '140', # CXCursor_ObjCProtocolExpr (An Objective-C \@protocol expression)\ -141 : '141', # CXCursor_ObjCBridgedCastExpr (An Objective-C "bridged" cast \ - # expression, which casts between Objective-C pointers and C \ - # pointers, transferring ownership in the process) \ -142 : '142', # CXCursor_PackExpansionExpr (Represents a C++0x pack expansion \ - # that produces a sequence of expressions) \ -143 : '143', # CXCursor_SizeOfPackExpr (Represents an expression that computes\ - # the length of a parameter pack) \ -144 : '144', # CXCursor_LambdaExpr (Represents a C++ lambda expression that \ - # produces a local function object) \ -145 : '145', # CXCursor_ObjCBoolLiteralExpr (Objective-c Boolean Literal) \ - \ -# Statements \ -200 : '200', # CXCursor_UnexposedStmt (A statement whose specific kind is not \ - # exposed via this interface) \ -201 : '201', # CXCursor_LabelStmt (A labelled statement in a function) \ -202 : '202', # CXCursor_CompoundStmt (A group of statements like \ - # { stmt stmt }. \ -203 : '203', # CXCursor_CaseStmt (A case statment) \ -204 : '204', # CXCursor_DefaultStmt (A default statement) \ -205 : '205', # CXCursor_IfStmt (An if statemen) \ -206 : '206', # CXCursor_SwitchStmt (A switch statement) \ -207 : '207', # CXCursor_WhileStmt (A while statement) \ -208 : '208', # CXCursor_DoStmt (A do statement) \ -209 : '209', # CXCursor_ForStmt (A for statement) \ -210 : '210', # CXCursor_GotoStmt (A goto statement) \ -211 : '211', # CXCursor_IndirectGotoStmt (An indirect goto statement) \ -212 : '212', # CXCursor_ContinueStmt (A continue statement) \ -213 : '213', # CXCursor_BreakStmt (A break statement) \ -214 : '214', # CXCursor_ReturnStmt (A return statement) \ -215 : '215', # CXCursor_GCCAsmStmt (A GCC inline assembly statement extension)\ -216 : '216', # CXCursor_ObjCAtTryStmt (Objective-C's overall try-catch-finally\ - # statement. \ -217 : '217', # CXCursor_ObjCAtCatchStmt (Objective-C's catch statement) \ -218 : '218', # CXCursor_ObjCAtFinallyStmt (Objective-C's finally statement) \ -219 : '219', # CXCursor_ObjCAtThrowStmt (Objective-C's throw statement) \ -220 : '220', # CXCursor_ObjCAtSynchronizedStmt (Objective-C's synchronized \ - # statement) \ -221 : '221', # CXCursor_ObjCAutoreleasePoolStmt (Objective-C's autorelease \ - # pool statement) \ -222 : '222', # CXCursor_ObjCForCollectionStmt (Objective-C's collection \ - # statement) \ -223 : '223', # CXCursor_CXXCatchStmt (C++'s catch statement) \ -224 : '224', # CXCursor_CXXTryStmt (C++'s try statement) \ -225 : '225', # CXCursor_CXXForRangeStmt (C++'s for (* : *) statement) \ -226 : '226', # CXCursor_SEHTryStmt (Windows Structured Exception Handling's \ - # try statement) \ -227 : '227', # CXCursor_SEHExceptStmt (Windows Structured Exception Handling's\ - # except statement. \ -228 : '228', # CXCursor_SEHFinallyStmt (Windows Structured Exception \ - # Handling's finally statement) \ -229 : '229', # CXCursor_MSAsmStmt (A MS inline assembly statement extension) \ -230 : '230', # CXCursor_NullStmt (The null satement ";": C99 6.8.3p3) \ -231 : '231', # CXCursor_DeclStmt (Adaptor class for mixing declarations with \ - # statements and expressions) \ - \ -# Translation unit \ -300 : '300', # CXCursor_TranslationUnit (Cursor that represents the \ - # translation unit itself) \ - \ -# Attributes \ -400 : '400', # CXCursor_UnexposedAttr (An attribute whose specific kind is \ - # not exposed via this interface) \ -401 : '401', # CXCursor_IBActionAttr \ -402 : '402', # CXCursor_IBOutletAttr \ -403 : '403', # CXCursor_IBOutletCollectionAttr \ -404 : '404', # CXCursor_CXXFinalAttr \ -405 : '405', # CXCursor_CXXOverrideAttr \ -406 : '406', # CXCursor_AnnotateAttr \ -407 : '407', # CXCursor_AsmLabelAttr \ - \ -# Preprocessing \ -500 : '500', # CXCursor_PreprocessingDirective \ -501 : 'd', # CXCursor_MacroDefinition \ -502 : '502', # CXCursor_MacroInstantiation \ -503 : '503', # CXCursor_InclusionDirective \ - \ -# Modules \ -600 : '600', # CXCursor_ModuleImportDecl (A module import declaration) \ -}) - # vim: set ts=2 sts=2 sw=2 expandtab : diff --git a/plugin/snippets/clang_complete.py b/plugin/snippets/clang_complete.py index 3c27e54c..9d852539 100644 --- a/plugin/snippets/clang_complete.py +++ b/plugin/snippets/clang_complete.py @@ -2,8 +2,11 @@ import vim def snippetsInit(): - vim.command("noremap :python updateSnips()") - vim.command("snoremap :python updateSnips()") + python_cmd = vim.eval('s:py_cmd') + + vim.command("noremap :%s updateSnips()" % python_cmd) + vim.command("snoremap :%s updateSnips()" % python_cmd) + if int(vim.eval("g:clang_conceal_snippets")) == 1: vim.command("syntax match placeHolder /\$`[^`]*`/ contains=placeHolderMark") vim.command("syntax match placeHolderMark contained /\$`/ conceal") diff --git a/plugin/snippets/ultisnips.py b/plugin/snippets/ultisnips.py index 5d1130ec..9e822ec7 100644 --- a/plugin/snippets/ultisnips.py +++ b/plugin/snippets/ultisnips.py @@ -29,7 +29,7 @@ def snippetsAddSnippet(fullname, word, abbr): return fullname def snippetsTrigger(): - print vim.current.line + print(vim.current.line) UltiSnips_Manager.expand() def snippetsReset(): diff --git a/rplugin/python3/deoplete/sources/clang_complete.py b/rplugin/python3/deoplete/sources/clang_complete.py index 4a596cd0..4ba27fb7 100644 --- a/rplugin/python3/deoplete/sources/clang_complete.py +++ b/rplugin/python3/deoplete/sources/clang_complete.py @@ -11,9 +11,9 @@ def __init__(self, vim): self.name = 'clang_complete' self.mark = '[clang]' - self.filetypes = ['c', 'cpp'] + self.filetypes = ['c', 'cpp', 'objc', 'objcpp'] self.is_bytepos = True - self.min_pattern_length = 1 + self.input_pattern = '[^. \t0-9]\.\w*' def get_complete_position(self, context): return self.vim.call('ClangComplete', 1, 0)