diff --git a/plugin/clang/cindex.py b/plugin/clang/cindex.py index d265f7e5..edd3e707 100644 --- a/plugin/clang/cindex.py +++ b/plugin/clang/cindex.py @@ -1735,10 +1735,17 @@ def availability(self): res = conf.lib.clang_getCompletionAvailability(self.obj) return availabilityKinds[res] + @property + def briefComment(self): + if conf.function_exists("clang_getCompletionBriefComment"): + return conf.lib.clang_getCompletionBriefComment(self.obj) + return _CXString() + def __repr__(self): return " | ".join([str(a) for a in self]) \ + " || Priority: " + str(self.priority) \ - + " || Availability: " + str(self.availability) + + " || Availability: " + str(self.availability) \ + + " || Brief comment: " + str(self.briefComment.spelling) availabilityKinds = { 0: CompletionChunk.Kind("Available"), @@ -1877,6 +1884,10 @@ class TranslationUnit(ClangObject): # searching for declarations/definitions. PARSE_SKIP_FUNCTION_BODIES = 64 + # Used to indicate that brief documentation comments should be included + # into the set of code completions returned from this translation unit. + PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION = 128 + @classmethod def from_source(cls, filename, args=None, unsaved_files=None, options=0, index=None): @@ -2149,7 +2160,9 @@ def save(self, filename): raise TranslationUnitSaveError(result, 'Error saving TranslationUnit.') - def codeComplete(self, path, line, column, unsaved_files=None, options=0): + def codeComplete(self, path, line, column, unsaved_files=None, + include_macros=False, include_code_patterns=False, + include_brief_comments=False): """ Code complete in this translation unit. @@ -2158,6 +2171,17 @@ def codeComplete(self, path, line, column, unsaved_files=None, options=0): and the second should be the contents to be substituted for the file. The contents may be passed as strings or file objects. """ + options = 0 + + if include_macros: + options += 1 + + if include_code_patterns: + options += 2 + + if include_brief_comments: + options += 4 + if unsaved_files is None: unsaved_files = [] @@ -2556,6 +2580,10 @@ def cursor(self): [c_void_p], c_int), + ("clang_getCompletionBriefComment", + [c_void_p], + _CXString), + ("clang_getCompletionChunkCompletionString", [c_void_p, c_int], c_object_p), @@ -3071,6 +3099,13 @@ def get_cindex_library(self): return library + def function_exists(self, name): + try: + getattr(self.lib, name) + except AttributeError: + return False + + return True def register_enumerations(): for name, value in clang.enumerations.TokenKinds: diff --git a/plugin/clang_complete.vim b/plugin/clang_complete.vim index 363f98cf..f92b7f3d 100644 --- a/plugin/clang_complete.vim +++ b/plugin/clang_complete.vim @@ -84,6 +84,10 @@ function! s:ClangCompleteInit() let g:clang_complete_patterns = 0 endif + if !exists('g:clang_include_brief_comments') + let g:clang_include_brief_comments = 1 + endif + if !exists('g:clang_debug') let g:clang_debug = 0 endif @@ -136,16 +140,12 @@ function! s:ClangCompleteInit() let b:clang_parameters .= '-header' endif - let g:clang_complete_lib_flags = 0 - if g:clang_complete_macros == 1 let b:clang_parameters .= ' -code-completion-macros' - let g:clang_complete_lib_flags = 1 endif if g:clang_complete_patterns == 1 let b:clang_parameters .= ' -code-completion-patterns' - let g:clang_complete_lib_flags += 2 endif setlocal completefunc=ClangComplete @@ -239,9 +239,16 @@ function! s:initClangCompletePython() exe 'python sys.path = ["' . s:plugin_path . '"] + sys.path' exe 'pyfile ' . s:plugin_path . '/libclang.py' if exists('g:clang_library_path') - python initClangComplete(vim.eval('g:clang_complete_lib_flags'), vim.eval('g:clang_library_path')) + python initClangComplete( + \ include_macros=vim.eval('g:clang_complete_macros'), + \ include_code_patterns=vim.eval('g:clang_complete_patterns'), + \ include_brief_comments=vim.eval('g:clang_include_brief_comments'), + \ library_path=vim.eval('g:clang_library_path')) else - python initClangComplete(vim.eval('g:clang_complete_lib_flags')) + python initClangComplete( + \ include_macros=vim.eval('g:clang_complete_macros'), + \ include_code_patterns=vim.eval('g:clang_complete_patterns'), + \ include_brief_comments=vim.eval('g:clang_include_brief_comments')) endif let s:libclang_loaded = 1 endif @@ -571,7 +578,7 @@ function! ClangComplete(findstart, base) if g:clang_use_library == 1 python completions, timer = getCurrentCompletions(vim.eval('a:base')) - python vim.command('let l:res = ' + completions) + python vim.command('let l:res = ' + toVimRepr(completions)) python timer.registerEvent("Load into vimscript") else let l:res = s:ClangCompleteBinary(a:base) @@ -582,6 +589,7 @@ function! ClangComplete(findstart, base) let item['word'] = b:AddSnip(item['info'], item['args_pos']) else let item['word'] = item['abbr'] + let item['info'] = item['info'] . "\n" . item['brief_comment'] endif endfor diff --git a/plugin/libclang.py b/plugin/libclang.py index 8e865db7..fee1cdc7 100644 --- a/plugin/libclang.py +++ b/plugin/libclang.py @@ -3,8 +3,10 @@ import time import re import threading +import types -def initClangComplete(clang_complete_flags, library_path = None): +def initClangComplete(include_macros=False, include_code_patterns=False, + include_brief_comments=False, library_path=None): global index if library_path: Config.set_library_path(library_path) @@ -14,7 +16,11 @@ def initClangComplete(clang_complete_flags, library_path = None): global translationUnits translationUnits = dict() global complete_flags - complete_flags = int(clang_complete_flags) + complete_flags = { + 'include_macros': include_macros, + 'include_code_patterns': include_code_patterns, + 'include_brief_comments': include_brief_comments + } global libclangLock libclangLock = threading.Lock() @@ -88,6 +94,8 @@ def getCurrentTranslationUnit(args, currentFile, fileName, update = False): if debug: start = time.time() flags = TranslationUnit.PARSE_PRECOMPILED_PREAMBLE + if complete_flags['include_brief_comments']: + flags |= TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION tu = index.parse(fileName, args, [currentFile], flags) if debug: elapsed = (time.time() - start) @@ -220,7 +228,7 @@ def getCurrentCompletionResults(line, column, args, currentFile, fileName, timer.registerEvent("Get TU") cr = tu.codeComplete(fileName, line, column, [currentFile], - complete_flags) + **complete_flags) timer.registerEvent("Code Complete") return cr @@ -263,6 +271,7 @@ def formatResult(result): completion['info'] = word completion['args_pos'] = args_pos completion['dup'] = 0 + completion['brief_comment'] = result.string.briefComment.spelling or "" # Replace the number that represents a specific kind with a better # textual representation. @@ -354,7 +363,79 @@ def getCurrentCompletions(base): result = map(formatResult, results) timer.registerEvent("Format") - return (str(result), timer) + return (result, timer) + +class VimReprHelper: + def __init__(self): + self._result = [] + + def getResult(self): + return ''.join(self._result) + + def append(self, v): + t = type(v) + if t in [types.IntType, types.LongType, types.FloatType]: + self._result.append(repr(v)) + if t in [types.StringType, types.UnicodeType]: + self.appendString(v) + if t is types.ListType: + self.appendList(v) + if t is types.DictType: + self.appendDict(v) + + def appendString(self, s): + if '\'' in s: + self._result.append('\'') + self._result.append(s.replace('\'', '\'\'')) + self._result.append('\'') + else: + self._result.append(repr(s)) + + def appendList(self, l): + self._result.append('[') + for i in xrange(len(l)): + self.append(l[i]) + if i != len(l) - 1: + self._result.append(',') + self._result.append(']') + + def appendDict(self, d): + self._result.append('{') + keys = d.keys() + for i in xrange(len(keys)): + k = keys[i] + self.append(k) + self._result.append(':') + self.append(d[k]) + if i != len(keys) - 1: + self._result.append(',') + self._result.append('}') + +def needsSpecialConversion(v): + t = type(v) + if t in [types.IntType, types.LongType, types.FloatType]: + return False + if t in [types.StringType, types.UnicodeType]: + return '\'' in v + if t is types.ListType: + for e in v: + if needsSpecialConversion(e): + return True + if t is types.DictType: + for k, val in v.items(): + if needsSpecialConversion(k): + return True + if needsSpecialConversion(val): + return True + return False + +def toVimRepr(v): + if needsSpecialConversion(v): + helper = VimReprHelper() + helper.append(v) + return helper.getResult() + else: + return repr(v) def getAbbr(strings): tmplst = filter(lambda x: x.isKindTypedText(), strings)