Skip to content

Commit 699d2f3

Browse files
committed
Fix completion of headers.
1 parent 5d88eb9 commit 699d2f3

File tree

6 files changed

+76
-36
lines changed

6 files changed

+76
-36
lines changed

src/config.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ struct Config {
101101
// An example value is { ".h", ".hpp" }
102102
//
103103
// This is significantly faster than using a regex.
104-
std::vector<std::string> includeCompletionWhitelistLiteralEnding;
104+
std::vector<std::string> includeCompletionWhitelistLiteralEnding = {
105+
".h", ".hpp", ".hh"};
105106
// Regex patterns to match include completion candidates against. They
106107
// receive the absolute file path.
107108
//

src/include_complete.cc

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -78,30 +78,21 @@ bool TrimPath(Project* project,
7878

7979
lsCompletionItem BuildCompletionItem(Config* config,
8080
const std::string& path,
81-
bool use_angle_brackets,
81+
bool /*use_angle_brackets*/,
8282
bool is_stl) {
8383
lsCompletionItem item;
84-
if (use_angle_brackets)
85-
item.label = "#include <" + ElideLongPath(config, path) + ">";
86-
else
87-
item.label = "#include \"" + ElideLongPath(config, path) + "\"";
88-
84+
item.label = ElideLongPath(config, path);
8985
item.detail = path;
90-
91-
// Replace the entire existing content.
92-
// NOTE: When submitting completion items, textEdit->range must be updated.
9386
item.textEdit = lsTextEdit();
94-
if (use_angle_brackets)
95-
item.textEdit->newText = "#include <" + path + ">";
96-
else
97-
item.textEdit->newText = "#include \"" + path + "\"";
98-
87+
item.textEdit->newText = path;
9988
item.insertTextFormat = lsInsertTextFormat::PlainText;
100-
if (is_stl)
89+
if (is_stl) {
10190
item.kind = lsCompletionItemKind::Module;
102-
else
91+
item.priority_ = 2;
92+
} else {
10393
item.kind = lsCompletionItemKind::File;
104-
94+
item.priority_ = 1;
95+
}
10596
return item;
10697
}
10798

@@ -127,8 +118,8 @@ void IncludeComplete::Rescan() {
127118
Timer timer;
128119

129120
InsertStlIncludes();
130-
InsertIncludesFromDirectory(config_->projectRoot,
131-
false /*use_angle_brackets*/);
121+
// InsertIncludesFromDirectory(config_->projectRoot,
122+
// false /*use_angle_brackets*/);
132123
for (const std::string& dir : project_->quote_include_directories)
133124
InsertIncludesFromDirectory(dir, false /*use_angle_brackets*/);
134125
for (const std::string& dir : project_->angle_include_directories)

src/lex_utils.cc

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,38 @@ lsPosition CharPos(const std::string& search,
4545
return result;
4646
}
4747

48-
bool ShouldRunIncludeCompletion(const std::string& line) {
48+
std::tuple<bool, std::string, std::string> ShouldRunIncludeCompletion(
49+
const std::string& line) {
4950
size_t start = 0;
5051
while (start < line.size() && isspace(line[start]))
5152
++start;
52-
return start < line.size() && line[start] == '#';
53+
// Must start with '#'.
54+
if (start >= line.size() || line[start] != '#')
55+
return std::make_tuple(false, "", "");
56+
++start;
57+
// Ingore "include" and following spaces.
58+
if (line.compare(start, 7, "include") == 0) {
59+
start += 7;
60+
while (start < line.size() && isspace(line[start]))
61+
++start;
62+
}
63+
// Determine the surrounding characters.
64+
std::string surround;
65+
if (line[start] == '"') {
66+
surround = "\"\"";
67+
++start;
68+
} else if (line[start] == '<') {
69+
surround = "<>";
70+
++start;
71+
} else
72+
surround = "<>";
73+
// Fix the prefix for completion.
74+
size_t end = start;
75+
while (end < line.size() && line[end] != '\"' && line[end] != '>')
76+
++end;
77+
std::string prefix = line.substr(start, end - start);
78+
79+
return std::make_tuple(true, surround, prefix);
5380
}
5481

5582
// TODO: eliminate |line_number| param.

src/lex_utils.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "language_server_api.h"
44

55
#include <string>
6+
#include <tuple>
67

78
// Utility method to map |position| to an offset inside of |content|.
89
int GetOffsetForPosition(lsPosition position, const std::string& content);
@@ -11,7 +12,8 @@ lsPosition CharPos(const std::string& search,
1112
char character,
1213
int character_offset = 0);
1314

14-
bool ShouldRunIncludeCompletion(const std::string& line);
15+
std::tuple<bool, std::string, std::string> ShouldRunIncludeCompletion(
16+
const std::string& line);
1517

1618
// TODO: eliminate |line_number| param.
1719
optional<lsRange> ExtractQuotedRange(int line_number, const std::string& line);

src/messages/initialize.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ struct lsCompletionOptions {
3838
// for
3939
// '::' and '>' for '->'. See
4040
// https://github.com/Microsoft/language-server-protocol/issues/138.
41-
std::vector<std::string> triggerCharacters = {".", ":", ">", "#"};
41+
std::vector<std::string> triggerCharacters = {".", ":", ">", "#", "<", "\""};
4242
};
4343
MAKE_REFLECT_STRUCT(lsCompletionOptions, resolveProvider, triggerCharacters);
4444

src/messages/text_document_completion.cc

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,17 @@ struct TextDocumentCompletionHandler : MessageHandler {
256256
std::string character = *request->params.context->triggerCharacter;
257257
char preceding_index = request->params.position.character - 2;
258258

259+
// If the character is '"' or '<', make sure the line is start with '#'.
260+
if (character == "\"" || character == "<") {
261+
size_t i = 0;
262+
while (i < buffer_line.size() && isspace(buffer_line[i]))
263+
++i;
264+
if (i >= buffer_line.size() || buffer_line[i] != '#')
265+
did_fail_check = true;
266+
}
259267
// If the character is > or : and we are at the start of the line, do not
260268
// show completion results.
261-
if ((character == ">" || character == ":") && preceding_index < 0) {
269+
else if ((character == ">" || character == ":") && preceding_index < 0) {
262270
did_fail_check = true;
263271
}
264272
// If the character is > but - does not preced it, or if it is : and :
@@ -283,7 +291,11 @@ struct TextDocumentCompletionHandler : MessageHandler {
283291
&existing_completion);
284292
}
285293

286-
if (ShouldRunIncludeCompletion(buffer_line)) {
294+
bool yes;
295+
std::string surround, prefix;
296+
std::tie(yes, surround, prefix) = ShouldRunIncludeCompletion(buffer_line);
297+
298+
if (yes) {
287299
Out_TextDocumentComplete out;
288300
out.id = request->id;
289301

@@ -296,19 +308,26 @@ struct TextDocumentCompletionHandler : MessageHandler {
296308
include_complete->completion_items.end());
297309
if (lock)
298310
lock.unlock();
299-
300-
// Update textEdit params.
301-
for (lsCompletionItem& item : out.result.items) {
302-
item.textEdit->range.start.line = request->params.position.line;
303-
item.textEdit->range.start.character = 0;
304-
item.textEdit->range.end.line = request->params.position.line;
305-
item.textEdit->range.end.character = (int)buffer_line.size();
306-
}
307311
}
308312

309-
TrimInPlace(buffer_line);
310-
FilterAndSortCompletionResponse(&out, buffer_line,
313+
FilterAndSortCompletionResponse(&out, prefix,
311314
config->completion.filterAndSort);
315+
316+
auto decorator = [&](std::string& text) {
317+
std::string result = "#include ";
318+
result += surround[0] + text + surround[1];
319+
text = result;
320+
};
321+
LOG_S(INFO) << "DEBUG prefix " << prefix;
322+
for (lsCompletionItem& item : out.result.items) {
323+
item.textEdit->range.start.line = request->params.position.line;
324+
item.textEdit->range.start.character = 0;
325+
item.textEdit->range.end.line = request->params.position.line;
326+
item.textEdit->range.end.character = (int)buffer_line.size();
327+
decorator(item.textEdit->newText);
328+
decorator(item.label);
329+
}
330+
312331
QueueManager::WriteStdout(IpcId::TextDocumentCompletion, out);
313332
} else {
314333
// If existing completion is empty, dont return clang-based completion

0 commit comments

Comments
 (0)