@@ -29,15 +29,16 @@ unsigned Flags() {
29
29
30
30
unsigned GetCompletionPriority (const CXCompletionString& str,
31
31
CXCursorKind result_kind,
32
- const std::string& label ) {
32
+ const std::string& typedText ) {
33
33
unsigned priority = clang_getCompletionPriority (str);
34
34
35
35
// XXX: What happens if priority overflows?
36
36
if (result_kind == CXCursor_Destructor) {
37
37
priority *= 100 ;
38
38
}
39
39
if (result_kind == CXCursor_ConversionFunction ||
40
- (result_kind == CXCursor_CXXMethod && StartsWith (label, " operator" ))) {
40
+ (result_kind == CXCursor_CXXMethod &&
41
+ StartsWith (typedText, " operator" ))) {
41
42
priority *= 100 ;
42
43
}
43
44
if (clang_getCompletionAvailability (str) != CXAvailability_Available) {
@@ -149,6 +150,103 @@ lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) {
149
150
}
150
151
}
151
152
153
+ void BuildCompletionItemTexts (std::vector<lsCompletionItem>& out,
154
+ CXCompletionString completion_string,
155
+ bool include_snippets) {
156
+ assert (!out.empty ());
157
+ auto out_first = out.size () - 1 ;
158
+
159
+ std::string result_type;
160
+
161
+ int num_chunks = clang_getNumCompletionChunks (completion_string);
162
+ for (int i = 0 ; i < num_chunks; ++i) {
163
+ CXCompletionChunkKind kind =
164
+ clang_getCompletionChunkKind (completion_string, i);
165
+
166
+ std::string text;
167
+ switch (kind) {
168
+ case CXCompletionChunk_LeftParen: text = ' (' ; break ;
169
+ case CXCompletionChunk_RightParen: text = ' )' ; break ;
170
+ case CXCompletionChunk_LeftBracket: text = ' [' ; break ;
171
+ case CXCompletionChunk_RightBracket: text = ' ]' ; break ;
172
+ case CXCompletionChunk_LeftBrace: text = ' {' ; break ;
173
+ case CXCompletionChunk_RightBrace: text = ' }' ; break ;
174
+ case CXCompletionChunk_LeftAngle: text = ' <' ; break ;
175
+ case CXCompletionChunk_RightAngle: text = ' >' ; break ;
176
+ case CXCompletionChunk_Comma: text = " , " ; break ;
177
+ case CXCompletionChunk_Colon: text = ' :' ; break ;
178
+ case CXCompletionChunk_SemiColon: text = ' ;' ; break ;
179
+ case CXCompletionChunk_Equal: text = ' =' ; break ;
180
+ case CXCompletionChunk_HorizontalSpace: text = ' ' ; break ;
181
+ case CXCompletionChunk_VerticalSpace: text = ' ' ; break ;
182
+
183
+ case CXCompletionChunk_ResultType:
184
+ result_type =
185
+ ToString (clang_getCompletionChunkText (completion_string, i));
186
+ continue ;
187
+
188
+ case CXCompletionChunk_TypedText:
189
+ case CXCompletionChunk_Placeholder:
190
+ case CXCompletionChunk_Text:
191
+ case CXCompletionChunk_Informative:
192
+ text = ToString (clang_getCompletionChunkText (completion_string, i));
193
+
194
+ for (auto i = out_first; i < out.size (); ++i) {
195
+ // first typed text is used for filtering
196
+ if (kind == CXCompletionChunk_TypedText && out[i].filterText .empty ())
197
+ out[i].filterText = text;
198
+
199
+ if (kind == CXCompletionChunk_Placeholder)
200
+ out[i].parameters_ .push_back (text);
201
+ }
202
+ break ;
203
+
204
+ case CXCompletionChunk_CurrentParameter:
205
+ // We have our own parsing logic for active parameter. This doesn't seem
206
+ // to be very reliable.
207
+ continue ;
208
+
209
+ case CXCompletionChunk_Optional: {
210
+ CXCompletionString nested =
211
+ clang_getCompletionChunkCompletionString (completion_string, i);
212
+ // duplicate last element, the recursive call will complete it
213
+ out.push_back (out.back ());
214
+ BuildCompletionItemTexts (out, nested, include_snippets);
215
+ continue ;
216
+ }
217
+ }
218
+
219
+ for (auto i = out_first; i < out.size (); ++i)
220
+ out[i].label += text;
221
+
222
+ if (kind == CXCompletionChunk_Informative)
223
+ continue ;
224
+
225
+ for (auto i = out_first; i < out.size (); ++i) {
226
+ if (!include_snippets && !out[i].parameters_ .empty ())
227
+ continue ;
228
+
229
+ if (kind == CXCompletionChunk_Placeholder) {
230
+ out[i].insertText +=
231
+ " ${" + std::to_string (out[i].parameters_ .size ()) + " :" + text + " }" ;
232
+ out[i].insertTextFormat = lsInsertTextFormat::Snippet;
233
+ } else {
234
+ out[i].insertText += text;
235
+ }
236
+ }
237
+ }
238
+
239
+ if (result_type.empty ())
240
+ return ;
241
+
242
+ for (auto i = out_first; i < out.size (); ++i) {
243
+ // ' : ' for variables,
244
+ // ' -> ' (trailing return type-like) for functions
245
+ out[i].label += (out[i].label == out[i].filterText ? " : " : " -> " );
246
+ out[i].label += result_type;
247
+ }
248
+ }
249
+
152
250
// |do_insert|: if |!do_insert|, do not append strings to |insert| after
153
251
// a placeholder.
154
252
void BuildDetailString (CXCompletionString completion_string,
@@ -387,6 +485,8 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
387
485
{
388
486
if (request->on_complete ) {
389
487
std::vector<lsCompletionItem> ls_result;
488
+ // this is a guess but can be larger in case of optional parameters,
489
+ // as they may be expanded into multiple items
390
490
ls_result.reserve (cx_results->NumResults );
391
491
392
492
timer.Reset ();
@@ -407,29 +507,52 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
407
507
// TODO: fill in more data
408
508
lsCompletionItem ls_completion_item;
409
509
410
- bool do_insert = true ;
411
- // kind/label/detail/docs/sortText
412
510
ls_completion_item.kind = GetCompletionKind (result.CursorKind );
413
- BuildDetailString (
414
- result.CompletionString , ls_completion_item.label ,
415
- ls_completion_item.detail , ls_completion_item.insertText ,
416
- do_insert, ls_completion_item.insertTextFormat ,
417
- &ls_completion_item.parameters_ ,
418
- completion_manager->config_ ->client .snippetSupport );
419
- if (completion_manager->config_ ->client .snippetSupport &&
420
- ls_completion_item.insertTextFormat ==
421
- lsInsertTextFormat::Snippet) {
422
- ls_completion_item.insertText += " $0" ;
423
- }
424
-
425
511
ls_completion_item.documentation = ToString (
426
512
clang_getCompletionBriefComment (result.CompletionString ));
427
513
428
- ls_completion_item.priority_ = GetCompletionPriority (
429
- result.CompletionString , result.CursorKind ,
430
- ls_completion_item.label );
431
-
432
- ls_result.push_back (ls_completion_item);
514
+ // label/detail/filterText/insertText/priority
515
+ if (completion_manager->config_ ->completion .detailedLabel ) {
516
+ ls_completion_item.detail = ToString (
517
+ clang_getCompletionParent (result.CompletionString , nullptr ));
518
+
519
+ auto first_idx = ls_result.size ();
520
+ ls_result.push_back (ls_completion_item);
521
+
522
+ // label/filterText/insertText
523
+ BuildCompletionItemTexts (
524
+ ls_result, result.CompletionString ,
525
+ completion_manager->config_ ->client .snippetSupport );
526
+
527
+ for (auto i = first_idx; i < ls_result.size (); ++i) {
528
+ if (completion_manager->config_ ->client .snippetSupport &&
529
+ ls_result[i].insertTextFormat ==
530
+ lsInsertTextFormat::Snippet) {
531
+ ls_result[i].insertText += " $0" ;
532
+ }
533
+
534
+ ls_result[i].priority_ = GetCompletionPriority (
535
+ result.CompletionString , result.CursorKind ,
536
+ ls_result[i].filterText );
537
+ }
538
+ } else {
539
+ bool do_insert = true ;
540
+ BuildDetailString (
541
+ result.CompletionString , ls_completion_item.label ,
542
+ ls_completion_item.detail , ls_completion_item.insertText ,
543
+ do_insert, ls_completion_item.insertTextFormat ,
544
+ &ls_completion_item.parameters_ ,
545
+ completion_manager->config_ ->client .snippetSupport );
546
+ if (completion_manager->config_ ->client .snippetSupport &&
547
+ ls_completion_item.insertTextFormat ==
548
+ lsInsertTextFormat::Snippet) {
549
+ ls_completion_item.insertText += " $0" ;
550
+ }
551
+ ls_completion_item.priority_ = GetCompletionPriority (
552
+ result.CompletionString , result.CursorKind ,
553
+ ls_completion_item.label );
554
+ ls_result.push_back (ls_completion_item);
555
+ }
433
556
}
434
557
435
558
timer.ResetAndPrint (" [complete] Building " +
0 commit comments