1 from clang
.cindex
import *
7 def initClangComplete(clang_complete_flags
):
10 global translationUnits
11 translationUnits
= dict()
13 complete_flags
= int(clang_complete_flags
)
15 # Get a tuple (fileName, fileContent) for the file opened in the current
16 # vim buffer. The fileContent contains the unsafed buffer content.
18 file = "\n".join(vim
.eval("getline(1, '$')"))
19 return (vim
.current
.buffer.name
, file)
21 def getCurrentTranslationUnit(args
, currentFile
, fileName
, update
= False):
22 if fileName
in translationUnits
:
23 tu
= translationUnits
[fileName
]
27 tu
.reparse([currentFile
])
29 elapsed
= (time
.time() - start
)
30 print "LibClang - Reparsing: " + str(elapsed
)
35 flags
= TranslationUnit
.PrecompiledPreamble | TranslationUnit
.CXXPrecompiledPreamble
# | TranslationUnit.CacheCompletionResults
36 tu
= index
.parse(fileName
, args
, [currentFile
], flags
)
38 elapsed
= (time
.time() - start
)
39 print "LibClang - First parse: " + str(elapsed
)
42 print "Cannot parse this source file. The following arguments " \
43 + "are used for clang: " + " ".join(args
)
46 translationUnits
[fileName
] = tu
48 # Reparse to initialize the PCH cache even for auto completion
49 # This should be done by index.parse(), however it is not.
50 # So we need to reparse ourselves.
53 tu
.reparse([currentFile
])
55 elapsed
= (time
.time() - start
)
56 print "LibClang - First reparse (generate PCH cache): " + str(elapsed
)
59 def splitOptions(options
):
65 if char
== ' ' and not quoted
:
78 def getQuickFix(diagnostic
):
79 # Some diagnostics have no file, e.g. "too many errors emitted, stopping now"
80 if diagnostic
.location
.file:
81 filename
= diagnostic
.location
.file.name
85 if diagnostic
.severity
== diagnostic
.Ignored
:
87 elif diagnostic
.severity
== diagnostic
.Note
:
89 elif diagnostic
.severity
== diagnostic
.Warning:
91 elif diagnostic
.severity
== diagnostic
.Error
:
93 elif diagnostic
.severity
== diagnostic
.Fatal
:
98 return dict({ 'bufnr' : int(vim
.eval("bufnr('" + filename
+ "', 1)")),
99 'lnum' : diagnostic
.location
.line
,
100 'col' : diagnostic
.location
.column
,
101 'text' : diagnostic
.spelling
,
104 def getQuickFixList(tu
):
105 return filter (None, map (getQuickFix
, tu
.diagnostics
))
107 def highlightRange(range, hlGroup
):
108 pattern
= '/\%' + str(range.start
.line
) + 'l' + '\%' \
109 + str(range.start
.column
) + 'c' + '.*' \
110 + '\%' + str(range.end
.column
) + 'c/'
111 command
= "exe 'syntax match' . ' " + hlGroup
+ ' ' + pattern
+ "'"
114 def highlightDiagnostic(diagnostic
):
115 if diagnostic
.severity
== diagnostic
.Warning:
116 hlGroup
= 'SpellLocal'
117 elif diagnostic
.severity
== diagnostic
.Error
:
122 pattern
= '/\%' + str(diagnostic
.location
.line
) + 'l\%' \
123 + str(diagnostic
.location
.column
) + 'c./'
124 command
= "exe 'syntax match' . ' " + hlGroup
+ ' ' + pattern
+ "'"
127 # Use this wired kind of iterator as the python clang libraries
128 # have a bug in the range iterator that stops us to use:
130 # | for range in diagnostic.ranges
132 for i
in range(len(diagnostic
.ranges
)):
133 highlightRange(diagnostic
.ranges
[i
], hlGroup
)
135 def highlightDiagnostics(tu
):
136 map (highlightDiagnostic
, tu
.diagnostics
)
138 def highlightCurrentDiagnostics():
139 if vim
.current
.buffer.name
in translationUnits
:
140 highlightDiagnostics(translationUnits
[vim
.current
.buffer.name
])
142 def getCurrentQuickFixList():
143 if vim
.current
.buffer.name
in translationUnits
:
144 return getQuickFixList(translationUnits
[vim
.current
.buffer.name
])
147 def updateCurrentDiagnostics():
149 debug
= int(vim
.eval("g:clang_debug")) == 1
150 userOptionsGlobal
= splitOptions(vim
.eval("g:clang_user_options"))
151 userOptionsLocal
= splitOptions(vim
.eval("b:clang_user_options"))
152 args
= userOptionsGlobal
+ userOptionsLocal
153 getCurrentTranslationUnit(args
, getCurrentFile(),
154 vim
.current
.buffer.name
, update
= True)
156 def getCurrentCompletionResults(line
, column
, args
, currentFile
, fileName
):
157 tu
= getCurrentTranslationUnit(args
, currentFile
, fileName
)
160 cr
= tu
.codeComplete(fileName
, line
, column
, [currentFile
],
163 elapsed
= (time
.time() - start
)
164 print "LibClang - Code completion time: " + str(elapsed
)
167 def formatResult(result
):
170 abbr
= getAbbr(result
.string
)
171 word
= filter(lambda x
: not x
.isKindInformative() and not x
.isKindResultType(), result
.string
)
176 chunk_len
= len(chunk
.spelling
)
177 if chunk
.isKindPlaceHolder():
178 args_pos
+= [[ cur_pos
, cur_pos
+ chunk_len
]]
181 word
= "".join(map(lambda x
: x
.spelling
, word
))
183 completion
['word'] = word
184 completion
['abbr'] = abbr
185 completion
['menu'] = word
186 completion
['info'] = word
187 completion
['args_pos'] = args_pos
188 completion
['dup'] = 0
190 # Replace the number that represents a specific kind with a better
191 # textual representation.
192 completion
['kind'] = kinds
[result
.cursorKind
]
197 class CompleteThread(threading
.Thread
):
198 lock
= threading
.Lock()
200 def __init__(self
, line
, column
, currentFile
, fileName
):
201 threading
.Thread
.__init
__(self
)
204 self
.currentFile
= currentFile
205 self
.fileName
= fileName
207 userOptionsGlobal
= splitOptions(vim
.eval("g:clang_user_options"))
208 userOptionsLocal
= splitOptions(vim
.eval("b:clang_user_options"))
209 self
.args
= userOptionsGlobal
+ userOptionsLocal
213 CompleteThread
.lock
.acquire()
215 # Warm up the caches. For this it is sufficient to get the current
216 # translation unit. No need to retrieve completion results.
217 # This short pause is necessary to allow vim to initialize itself.
218 # Otherwise we would get: E293: block was not locked
219 # The user does not see any delay, as we just pause a background thread.
221 getCurrentTranslationUnit(self
.args
, self
.currentFile
, self
.fileName
)
223 self
.result
= getCurrentCompletionResults(self
.line
, self
.column
,
224 self
.args
, self
.currentFile
, self
.fileName
)
227 CompleteThread
.lock
.release()
231 debug
= int(vim
.eval("g:clang_debug")) == 1
232 t
= CompleteThread(-1, -1, getCurrentFile(), vim
.current
.buffer.name
)
237 def getCurrentCompletions(base
):
239 debug
= int(vim
.eval("g:clang_debug")) == 1
240 priority
= vim
.eval("g:clang_sort_algo") == 'priority'
241 line
= int(vim
.eval("line('.')"))
242 column
= int(vim
.eval("b:col"))
244 t
= CompleteThread(line
, column
, getCurrentFile(), vim
.current
.buffer.name
)
248 cancel
= int(vim
.eval('complete_check()'))
255 regexp
= re
.compile("^" + base
)
256 filteredResult
= filter(lambda x
: regexp
.match(getAbbr(x
.string
)), cr
.results
)
258 getPriority
= lambda x
: x
.string
.priority
259 getAbbrevation
= lambda x
: getAbbr(x
.string
).lower()
264 sortedResult
= sorted(filteredResult
, None, key
)
265 return map(formatResult
, sortedResult
)
267 def getAbbr(strings
):
268 tmplst
= filter(lambda x
: x
.isKindTypedText(), strings
)
272 return tmplst
[0].spelling
276 1 : 't', # CXCursor_UnexposedDecl (A declaration whose specific kind is not \
277 # exposed via this interface) \
278 2 : 't', # CXCursor_StructDecl (A C or C++ struct) \
279 3 : 't', # CXCursor_UnionDecl (A C or C++ union) \
280 4 : 't', # CXCursor_ClassDecl (A C++ class) \
281 5 : 't', # CXCursor_EnumDecl (An enumeration) \
282 6 : 'm', # CXCursor_FieldDecl (A field (in C) or non-static data member \
283 # (in C++) in a struct, union, or C++ class) \
284 7 : 'e', # CXCursor_EnumConstantDecl (An enumerator constant) \
285 8 : 'f', # CXCursor_FunctionDecl (A function) \
286 9 : 'v', # CXCursor_VarDecl (A variable) \
287 10 : 'a', # CXCursor_ParmDecl (A function or method parameter) \
288 11 : '11', # CXCursor_ObjCInterfaceDecl (An Objective-C @interface) \
289 12 : '12', # CXCursor_ObjCCategoryDecl (An Objective-C @interface for a \
291 13 : '13', # CXCursor_ObjCProtocolDecl (An Objective-C @protocol declaration) \
292 14 : '14', # CXCursor_ObjCPropertyDecl (An Objective-C @property declaration) \
293 15 : '15', # CXCursor_ObjCIvarDecl (An Objective-C instance variable) \
294 16 : '16', # CXCursor_ObjCInstanceMethodDecl (An Objective-C instance method) \
295 17 : '17', # CXCursor_ObjCClassMethodDecl (An Objective-C class method) \
296 18 : '18', # CXCursor_ObjCImplementationDec (An Objective-C @implementation) \
297 19 : '19', # CXCursor_ObjCCategoryImplDecll (An Objective-C @implementation \
299 20 : 't', # CXCursor_TypedefDecl (A typedef) \
300 21 : 'f', # CXCursor_CXXMethod (A C++ class method) \
301 22 : 'n', # CXCursor_Namespace (A C++ namespace) \
302 23 : '23', # CXCursor_LinkageSpec (A linkage specification, e.g. 'extern "C"') \
303 24 : '+', # CXCursor_Constructor (A C++ constructor) \
304 25 : '~', # CXCursor_Destructor (A C++ destructor) \
305 26 : '26', # CXCursor_ConversionFunction (A C++ conversion function) \
306 27 : 'a', # CXCursor_TemplateTypeParameter (A C++ template type parameter) \
307 28 : 'a', # CXCursor_NonTypeTemplateParameter (A C++ non-type template \
309 29 : 'a', # CXCursor_TemplateTemplateParameter (A C++ template template \
311 30 : 'f', # CXCursor_FunctionTemplate (A C++ function template) \
312 31 : 'p', # CXCursor_ClassTemplate (A C++ class template) \
313 32 : '32', # CXCursor_ClassTemplatePartialSpecialization (A C++ class template \
314 # partial specialization) \
315 33 : 'n', # CXCursor_NamespaceAlias (A C++ namespace alias declaration) \
316 34 : '34', # CXCursor_UsingDirective (A C++ using directive) \
317 35 : '35', # CXCursor_UsingDeclaration (A using declaration) \
320 40 : '40', # CXCursor_ObjCSuperClassRef \
321 41 : '41', # CXCursor_ObjCProtocolRef \
322 42 : '42', # CXCursor_ObjCClassRef \
323 43 : '43', # CXCursor_TypeRef \
324 44 : '44', # CXCursor_CXXBaseSpecifier \
325 45 : '45', # CXCursor_TemplateRef (A reference to a class template, function \
326 # template, template template parameter, or class template partial \
328 46 : '46', # CXCursor_NamespaceRef (A reference to a namespace or namespace \
330 47 : '47', # CXCursor_MemberRef (A reference to a member of a struct, union, \
331 # or class that occurs in some non-expression context, e.g., a \
332 # designated initializer) \
333 48 : '48', # CXCursor_LabelRef (A reference to a labeled statement) \
334 49 : '49', # CXCursor_OverloadedDeclRef (A reference to a set of overloaded \
335 # functions or function templates that has not yet been resolved to \
336 # a specific function or function template) \
339 #70 : '70', # CXCursor_FirstInvalid \
340 70 : '70', # CXCursor_InvalidFile \
341 71 : '71', # CXCursor_NoDeclFound \
342 72 : 'u', # CXCursor_NotImplemented \
343 73 : '73', # CXCursor_InvalidCode \
346 100 : '100', # CXCursor_UnexposedExpr (An expression whose specific kind is \
347 # not exposed via this interface) \
348 101 : '101', # CXCursor_DeclRefExpr (An expression that refers to some value \
349 # declaration, such as a function, varible, or enumerator) \
350 102 : '102', # CXCursor_MemberRefExpr (An expression that refers to a member \
351 # of a struct, union, class, Objective-C class, etc) \
352 103 : '103', # CXCursor_CallExpr (An expression that calls a function) \
353 104 : '104', # CXCursor_ObjCMessageExpr (An expression that sends a message \
354 # to an Objective-C object or class) \
355 105 : '105', # CXCursor_BlockExpr (An expression that represents a block \
359 200 : '200', # CXCursor_UnexposedStmt (A statement whose specific kind is not \
360 # exposed via this interface) \
361 201 : '201', # CXCursor_LabelStmt (A labelled statement in a function) \
364 300 : '300', # CXCursor_TranslationUnit (Cursor that represents the \
365 # translation unit itself) \
368 400 : '400', # CXCursor_UnexposedAttr (An attribute whose specific kind is \
369 # not exposed via this interface) \
370 401 : '401', # CXCursor_IBActionAttr \
371 402 : '402', # CXCursor_IBOutletAttr \
372 403 : '403', # CXCursor_IBOutletCollectionAttr \
375 500 : '500', # CXCursor_PreprocessingDirective \
376 501 : 'd', # CXCursor_MacroDefinition \
377 502 : '502', # CXCursor_MacroInstantiation \
378 503 : '503' # CXCursor_InclusionDirective \
381 # vim: set ts=2 sts=2 sw=2 expandtab :