@@ -98,6 +98,8 @@ void DecorateIncludePaths(const std::smatch& match,
9898
9999struct ParseIncludeLineResult {
100100 bool ok;
101+ std::string keyword;
102+ std::string quote;
101103 std::string pattern;
102104 std::smatch match;
103105};
@@ -115,8 +117,28 @@ ParseIncludeLineResult ParseIncludeLine(const std::string& line) {
115117 " (.*)" ); // [7]: suffix after quote char
116118 std::smatch match;
117119 bool ok = std::regex_match (line, match, pattern);
118- std::string text = match[3 ].str () + match[6 ].str ();
119- return {ok, text, match};
120+ return {ok, match[3 ], match[5 ], match[6 ], match};
121+ }
122+
123+ static const std::vector<std::string> preprocessorKeywords = {
124+ " define" , " undef" , " include" , " if" , " ifdef" , " ifndef" ,
125+ " else" , " elif" , " endif" , " line" , " error" , " pragma" };
126+
127+ std::vector<lsCompletionItem> preprocessorKeywordCompletionItems (
128+ const std::smatch& match) {
129+ std::vector<lsCompletionItem> items;
130+ for (auto & keyword : preprocessorKeywords) {
131+ lsCompletionItem item;
132+ item.label = keyword;
133+ item.priority_ = (keyword == " include" ? 2 : 1 );
134+ item.textEdit = lsTextEdit ();
135+ std::string space = (keyword == " else" || keyword == " endif" ) ? " " : " " ;
136+ item.textEdit ->newText = match[1 ].str () + " #" + match[2 ].str () + keyword +
137+ space + match[6 ].str ();
138+ item.insertTextFormat = lsInsertTextFormat::PlainText;
139+ items.push_back (item);
140+ }
141+ return items;
120142}
121143
122144template <typename T>
@@ -298,22 +320,31 @@ struct Handler_TextDocumentCompletion : MessageHandler {
298320 Out_TextDocumentComplete out;
299321 out.id = request->id ;
300322
301- {
302- std::unique_lock<std::mutex> lock (
303- include_complete->completion_items_mutex , std::defer_lock);
304- if (include_complete->is_scanning )
305- lock.lock ();
306- out.result .items = include_complete->completion_items ;
323+ if (result.quote .empty () && result.pattern .empty ()) {
324+ // no quote or path of file, do preprocessor keyword completion
325+ if (!std::any_of (preprocessorKeywords.begin (),
326+ preprocessorKeywords.end (),
327+ [&result](std::string_view k) {
328+ return k == result.keyword ;
329+ })) {
330+ out.result .items = preprocessorKeywordCompletionItems (result.match );
331+ FilterAndSortCompletionResponse (&out, result.keyword ,
332+ config->completion .filterAndSort );
333+ }
334+ } else if (result.keyword .compare (" include" ) == 0 ) {
335+ {
336+ // do include completion
337+ std::unique_lock<std::mutex> lock (
338+ include_complete->completion_items_mutex , std::defer_lock);
339+ if (include_complete->is_scanning )
340+ lock.lock ();
341+ out.result .items = include_complete->completion_items ;
342+ }
343+ FilterAndSortCompletionResponse (&out, result.pattern ,
344+ config->completion .filterAndSort );
345+ DecorateIncludePaths (result.match , &out.result .items );
307346 }
308347
309- // Needed by |FilterAndSortCompletionResponse|.
310- for (lsCompletionItem& item : out.result .items )
311- item.filterText = " include" + item.label ;
312-
313- FilterAndSortCompletionResponse (&out, result.pattern ,
314- config->completion .filterAndSort );
315- DecorateIncludePaths (result.match , &out.result .items );
316-
317348 for (lsCompletionItem& item : out.result .items ) {
318349 item.textEdit ->range .start .line = request->params .position .line ;
319350 item.textEdit ->range .start .character = 0 ;
0 commit comments