1use std::fmt;
18use std::mem;
19use std::ptr;
20use std::slice;
21use std::cmp::{self, Ordering};
22use std::marker::{PhantomData};
23use std::path::{PathBuf};
24
25use clang_sys::*;
26
27use libc::{c_uint};
28
29use utility;
30use super::{Availability, EntityKind, TranslationUnit, Unsaved, Usr};
31use super::diagnostic::{Diagnostic};
32
33#[derive(Clone, Debug, PartialEq, Eq)]
41pub enum CompletionChunk<'r> {
42 Colon,
44 Comma,
46 Equals,
48 Semicolon,
50 LeftAngleBracket,
52 RightAngleBracket,
54 LeftBrace,
56 RightBrace,
58 LeftParenthesis,
60 RightParenthesis,
62 LeftSquareBracket,
64 RightSquareBracket,
66 HorizontalSpace(String),
68 VerticalSpace(String),
70 CurrentParameter(String),
73 Informative(String),
75 Placeholder(String),
77 ResultType(String),
79 Text(String),
81 TypedText(String),
83 Optional(CompletionString<'r>),
85}
86
87impl<'r> CompletionChunk<'r> {
88 pub fn get_text(&self) -> Option<String> {
92 match *self {
93 CompletionChunk::Colon => Some(":".into()),
94 CompletionChunk::Comma => Some(",".into()),
95 CompletionChunk::Equals => Some("=".into()),
96 CompletionChunk::Semicolon => Some(";".into()),
97 CompletionChunk::LeftAngleBracket => Some("<".into()),
98 CompletionChunk::RightAngleBracket => Some(">".into()),
99 CompletionChunk::LeftBrace => Some("{".into()),
100 CompletionChunk::RightBrace => Some("}".into()),
101 CompletionChunk::LeftParenthesis => Some("(".into()),
102 CompletionChunk::RightParenthesis => Some(")".into()),
103 CompletionChunk::LeftSquareBracket => Some("[".into()),
104 CompletionChunk::RightSquareBracket => Some("]".into()),
105 CompletionChunk::CurrentParameter(ref text) |
106 CompletionChunk::Informative(ref text) |
107 CompletionChunk::Placeholder(ref text) |
108 CompletionChunk::ResultType(ref text) |
109 CompletionChunk::TypedText(ref text) |
110 CompletionChunk::Text(ref text) |
111 CompletionChunk::HorizontalSpace(ref text) |
112 CompletionChunk::VerticalSpace(ref text) => Some(text.clone()),
113 CompletionChunk::Optional(_) => None,
114 }
115 }
116
117 pub fn is_optional(&self) -> bool {
119 matches!(*self, CompletionChunk::Optional(_))
120 }
121}
122
123builder! {
130 builder Completer: CXCodeComplete_Flags {
132 tu: &'tu TranslationUnit<'tu>,
133 file: PathBuf,
134 line: u32,
135 column: u32,
136 unsaved: Vec<Unsaved>;
137 OPTIONS:
138 pub macros: CXCodeComplete_IncludeMacros,
140 pub code_patterns: CXCodeComplete_IncludeCodePatterns,
143 pub briefs: CXCodeComplete_IncludeBriefComments,
145 }
146}
147
148impl<'tu> Completer<'tu> {
149 #[doc(hidden)]
152 pub fn new<F: Into<PathBuf>>(
153 tu: &'tu TranslationUnit<'tu>, file: F, line: u32, column: u32
154 ) -> Completer<'tu> {
155 let file = file.into();
156 let flags = unsafe { clang_defaultCodeCompleteOptions() };
157 Completer { tu, file, line, column, unsaved: vec![], flags }
158 }
159
160 pub fn unsaved(&mut self, unsaved: &[Unsaved]) -> &mut Completer<'tu> {
164 self.unsaved = unsaved.into();
165 self
166 }
167
168 pub fn complete(&self) -> CompletionResults {
172 unsafe {
173 let ptr = clang_codeCompleteAt(
174 self.tu.ptr,
175 utility::from_path(&self.file).as_ptr(),
176 self.line as c_uint,
177 self.column as c_uint,
178 self.unsaved.as_ptr() as *mut CXUnsavedFile,
179 self.unsaved.len() as c_uint,
180 self.flags,
181 );
182 CompletionResults::from_ptr(ptr)
183 }
184 }
185}
186
187options! {
190 options CompletionContext: CXCompletionContext {
192 pub all_types: CXCompletionContext_AnyType,
194 pub all_values: CXCompletionContext_AnyValue,
196 pub class_type_values: CXCompletionContext_CXXClassTypeValue,
198 pub dot_members: CXCompletionContext_DotMemberAccess,
201 pub arrow_members: CXCompletionContext_ArrowMemberAccess,
204 pub enum_tags: CXCompletionContext_EnumTag,
206 pub union_tags: CXCompletionContext_UnionTag,
208 pub struct_tags: CXCompletionContext_StructTag,
210 pub class_names: CXCompletionContext_ClassTag,
212 pub namespaces: CXCompletionContext_Namespace,
214 pub nested_name_specifiers: CXCompletionContext_NestedNameSpecifier,
216 pub macro_names: CXCompletionContext_MacroName,
218 pub natural_language: CXCompletionContext_NaturalLanguage,
220 pub objc_object_values: CXCompletionContext_ObjCObjectValue,
222 pub objc_selector_values: CXCompletionContext_ObjCSelectorValue,
224 pub objc_property_members: CXCompletionContext_ObjCPropertyAccess,
227 pub objc_interfaces: CXCompletionContext_ObjCInterface,
229 pub objc_protocols: CXCompletionContext_ObjCProtocol,
231 pub objc_categories: CXCompletionContext_ObjCCategory,
233 pub objc_instance_messages: CXCompletionContext_ObjCInstanceMessage,
235 pub objc_class_messages: CXCompletionContext_ObjCClassMessage,
237 pub objc_selector_names: CXCompletionContext_ObjCSelectorName,
239 }
240}
241
242#[derive(Copy, Clone, Debug, PartialEq, Eq)]
246pub struct CompletionResult<'r> {
247 pub kind: EntityKind,
249 pub string: CompletionString<'r>,
251}
252
253impl<'r> CompletionResult<'r> {
254 fn from_raw(raw: CXCompletionResult) -> CompletionResult<'r> {
257 let kind = unsafe { mem::transmute(raw.CursorKind) };
258 CompletionResult { kind, string: CompletionString::from_ptr(raw.CompletionString) }
259 }
260}
261
262impl<'r> cmp::PartialOrd for CompletionResult<'r> {
263 fn partial_cmp(&self, other: &CompletionResult<'r>) -> Option<Ordering> {
264 Some(self.cmp(other))
265 }
266}
267
268impl<'r> cmp::Ord for CompletionResult<'r> {
269 fn cmp(&self, other: &CompletionResult<'r>) -> Ordering {
270 self.string.cmp(&other.string)
271 }
272}
273
274pub struct CompletionResults {
278 ptr: *mut CXCodeCompleteResults,
279}
280
281impl CompletionResults {
282 fn from_ptr(ptr: *mut CXCodeCompleteResults) -> CompletionResults {
285 assert!(!ptr.is_null());
286 CompletionResults { ptr }
287 }
288
289 pub fn get_diagnostics<'tu>(&self, tu: &'tu TranslationUnit<'tu>) -> Vec<Diagnostic<'tu>> {
294 iter!(
295 clang_codeCompleteGetNumDiagnostics(self.ptr),
296 clang_codeCompleteGetDiagnostic(self.ptr),
297 ).map(|d| Diagnostic::from_ptr(d, tu)).collect()
298 }
299
300 pub fn get_context(&self) -> Option<CompletionContext> {
302 let contexts = unsafe { clang_codeCompleteGetContexts(self.ptr) as CXCompletionContext };
303 if contexts != 0 && contexts != CXCompletionContext_Unknown {
304 Some(CompletionContext::from(contexts))
305 } else {
306 None
307 }
308 }
309
310 pub fn get_container_kind(&self) -> Option<(EntityKind, bool)> {
313 unsafe {
314 let mut incomplete = mem::MaybeUninit::uninit();
315 match clang_codeCompleteGetContainerKind(self.ptr, incomplete.as_mut_ptr()) {
316 CXCursor_InvalidCode => None,
317 other => Some((mem::transmute(other), incomplete.assume_init() != 0)),
318 }
319 }
320 }
321
322 pub fn get_objc_selector(&self) -> Option<String> {
325 unsafe { utility::to_string_option(clang_codeCompleteGetObjCSelector(self.ptr)) }
326 }
327
328 pub fn get_usr(&self) -> Option<Usr> {
331 unsafe { utility::to_string_option(clang_codeCompleteGetContainerUSR(self.ptr)).map(Usr) }
332 }
333
334 pub fn get_results(&self) -> Vec<CompletionResult> {
336 unsafe {
337 let raws = slice::from_raw_parts((*self.ptr).Results, (*self.ptr).NumResults as usize);
338 raws.iter().cloned().map(CompletionResult::from_raw).collect()
339 }
340 }
341}
342
343impl Drop for CompletionResults {
344 fn drop(&mut self) {
345 unsafe { clang_disposeCodeCompleteResults(self.ptr); }
346 }
347}
348
349impl fmt::Debug for CompletionResults {
350 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
351 formatter.debug_struct("CompletionResults")
352 .field("results", &self.get_results())
353 .finish()
354 }
355}
356
357#[derive(Copy, Clone)]
361pub struct CompletionString<'r> {
362 ptr: CXCompletionString,
363 _marker: PhantomData<&'r CompletionResults>
364}
365
366impl<'r> CompletionString<'r> {
367 #[doc(hidden)]
370 pub fn from_ptr(ptr: CXCompletionString) -> CompletionString<'r> {
371 assert!(!ptr.is_null());
372 CompletionString { ptr, _marker: PhantomData }
373 }
374
375 pub fn get_priority(&self) -> usize {
380 unsafe { clang_getCompletionPriority(self.ptr) as usize }
381 }
382
383 pub fn get_annotations(&self) -> Vec<String> {
385 iter!(
386 clang_getCompletionNumAnnotations(self.ptr),
387 clang_getCompletionAnnotation(self.ptr),
388 ).map(utility::to_string).collect()
389 }
390
391 pub fn get_availability(&self) -> Availability {
393 unsafe { mem::transmute(clang_getCompletionAvailability(self.ptr)) }
394 }
395
396 pub fn get_comment_brief(&self) -> Option<String> {
399 unsafe { utility::to_string_option(clang_getCompletionBriefComment(self.ptr)) }
400 }
401
402 pub fn get_parent_name(&self) -> Option<String> {
405 unsafe { utility::to_string_option(clang_getCompletionParent(self.ptr, ptr::null_mut())) }
406 }
407
408 pub fn get_typed_text(&self) -> Option<String> {
410 for chunk in self.get_chunks() {
411 if let CompletionChunk::TypedText(text) = chunk {
412 return Some(text);
413 }
414 }
415 None
416 }
417
418 pub fn get_chunks(&self) -> Vec<CompletionChunk> {
420 iter!(
421 clang_getNumCompletionChunks(self.ptr),
422 clang_getCompletionChunkKind(self.ptr),
423 ).enumerate().map(|(i, k)| {
424 macro_rules! text {
425 ($variant:ident) => ({
426 let text = unsafe { clang_getCompletionChunkText(self.ptr, i as c_uint) };
427 CompletionChunk::$variant(utility::to_string(text))
428 });
429 }
430
431 match k {
432 CXCompletionChunk_Colon => CompletionChunk::Colon,
433 CXCompletionChunk_Comma => CompletionChunk::Comma,
434 CXCompletionChunk_Equal => CompletionChunk::Equals,
435 CXCompletionChunk_SemiColon => CompletionChunk::Semicolon,
436 CXCompletionChunk_LeftAngle => CompletionChunk::LeftAngleBracket,
437 CXCompletionChunk_RightAngle => CompletionChunk::RightAngleBracket,
438 CXCompletionChunk_LeftBrace => CompletionChunk::LeftBrace,
439 CXCompletionChunk_RightBrace => CompletionChunk::RightBrace,
440 CXCompletionChunk_LeftParen => CompletionChunk::LeftParenthesis,
441 CXCompletionChunk_RightParen => CompletionChunk::RightParenthesis,
442 CXCompletionChunk_LeftBracket => CompletionChunk::LeftSquareBracket,
443 CXCompletionChunk_RightBracket => CompletionChunk::RightSquareBracket,
444 CXCompletionChunk_HorizontalSpace => text!(HorizontalSpace),
445 CXCompletionChunk_VerticalSpace => text!(VerticalSpace),
446 CXCompletionChunk_CurrentParameter => text!(CurrentParameter),
447 CXCompletionChunk_TypedText => text!(TypedText),
448 CXCompletionChunk_Text => text!(Text),
449 CXCompletionChunk_Placeholder => text!(Placeholder),
450 CXCompletionChunk_Informative => text!(Informative),
451 CXCompletionChunk_ResultType => text!(ResultType),
452 CXCompletionChunk_Optional => {
453 let i = i as c_uint;
454 let ptr = unsafe { clang_getCompletionChunkCompletionString(self.ptr, i) };
455 CompletionChunk::Optional(CompletionString::from_ptr(ptr))
456 },
457 _ => panic!("unexpected completion chunk kind: {:?}", k),
458 }
459 }).collect()
460 }
461}
462
463impl<'r> fmt::Debug for CompletionString<'r> {
464 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
465 formatter.debug_struct("CompletionString")
466 .field("chunks", &self.get_chunks())
467 .finish()
468 }
469}
470
471impl<'r> cmp::PartialEq for CompletionString<'r> {
472 fn eq(&self, other: &CompletionString<'r>) -> bool {
473 self.get_chunks() == other.get_chunks()
474 }
475}
476
477impl<'r> cmp::Eq for CompletionString<'r> { }
478
479impl<'r> cmp::PartialOrd for CompletionString<'r> {
480 fn partial_cmp(&self, other: &CompletionString<'r>) -> Option<Ordering> {
481 Some(self.cmp(other))
482 }
483}
484
485impl<'r> cmp::Ord for CompletionString<'r> {
486 fn cmp(&self, other: &CompletionString<'r>) -> Ordering {
487 match self.get_priority().cmp(&other.get_priority()) {
488 Ordering::Equal => self.get_typed_text().cmp(&other.get_typed_text()),
489 other => other,
490 }
491 }
492}