mirror of
https://github.com/MaskRay/ccls.git
synced 2025-02-22 00:19:28 +00:00
Fix completion of headers.
This commit is contained in:
parent
5d88eb959d
commit
699d2f3655
@ -101,7 +101,8 @@ struct Config {
|
|||||||
// An example value is { ".h", ".hpp" }
|
// An example value is { ".h", ".hpp" }
|
||||||
//
|
//
|
||||||
// This is significantly faster than using a regex.
|
// This is significantly faster than using a regex.
|
||||||
std::vector<std::string> includeCompletionWhitelistLiteralEnding;
|
std::vector<std::string> includeCompletionWhitelistLiteralEnding = {
|
||||||
|
".h", ".hpp", ".hh"};
|
||||||
// Regex patterns to match include completion candidates against. They
|
// Regex patterns to match include completion candidates against. They
|
||||||
// receive the absolute file path.
|
// receive the absolute file path.
|
||||||
//
|
//
|
||||||
|
@ -78,30 +78,21 @@ bool TrimPath(Project* project,
|
|||||||
|
|
||||||
lsCompletionItem BuildCompletionItem(Config* config,
|
lsCompletionItem BuildCompletionItem(Config* config,
|
||||||
const std::string& path,
|
const std::string& path,
|
||||||
bool use_angle_brackets,
|
bool /*use_angle_brackets*/,
|
||||||
bool is_stl) {
|
bool is_stl) {
|
||||||
lsCompletionItem item;
|
lsCompletionItem item;
|
||||||
if (use_angle_brackets)
|
item.label = ElideLongPath(config, path);
|
||||||
item.label = "#include <" + ElideLongPath(config, path) + ">";
|
|
||||||
else
|
|
||||||
item.label = "#include \"" + ElideLongPath(config, path) + "\"";
|
|
||||||
|
|
||||||
item.detail = path;
|
item.detail = path;
|
||||||
|
|
||||||
// Replace the entire existing content.
|
|
||||||
// NOTE: When submitting completion items, textEdit->range must be updated.
|
|
||||||
item.textEdit = lsTextEdit();
|
item.textEdit = lsTextEdit();
|
||||||
if (use_angle_brackets)
|
item.textEdit->newText = path;
|
||||||
item.textEdit->newText = "#include <" + path + ">";
|
|
||||||
else
|
|
||||||
item.textEdit->newText = "#include \"" + path + "\"";
|
|
||||||
|
|
||||||
item.insertTextFormat = lsInsertTextFormat::PlainText;
|
item.insertTextFormat = lsInsertTextFormat::PlainText;
|
||||||
if (is_stl)
|
if (is_stl) {
|
||||||
item.kind = lsCompletionItemKind::Module;
|
item.kind = lsCompletionItemKind::Module;
|
||||||
else
|
item.priority_ = 2;
|
||||||
|
} else {
|
||||||
item.kind = lsCompletionItemKind::File;
|
item.kind = lsCompletionItemKind::File;
|
||||||
|
item.priority_ = 1;
|
||||||
|
}
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,8 +118,8 @@ void IncludeComplete::Rescan() {
|
|||||||
Timer timer;
|
Timer timer;
|
||||||
|
|
||||||
InsertStlIncludes();
|
InsertStlIncludes();
|
||||||
InsertIncludesFromDirectory(config_->projectRoot,
|
// InsertIncludesFromDirectory(config_->projectRoot,
|
||||||
false /*use_angle_brackets*/);
|
// false /*use_angle_brackets*/);
|
||||||
for (const std::string& dir : project_->quote_include_directories)
|
for (const std::string& dir : project_->quote_include_directories)
|
||||||
InsertIncludesFromDirectory(dir, false /*use_angle_brackets*/);
|
InsertIncludesFromDirectory(dir, false /*use_angle_brackets*/);
|
||||||
for (const std::string& dir : project_->angle_include_directories)
|
for (const std::string& dir : project_->angle_include_directories)
|
||||||
|
@ -45,11 +45,38 @@ lsPosition CharPos(const std::string& search,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShouldRunIncludeCompletion(const std::string& line) {
|
std::tuple<bool, std::string, std::string> ShouldRunIncludeCompletion(
|
||||||
|
const std::string& line) {
|
||||||
size_t start = 0;
|
size_t start = 0;
|
||||||
while (start < line.size() && isspace(line[start]))
|
while (start < line.size() && isspace(line[start]))
|
||||||
++start;
|
++start;
|
||||||
return start < line.size() && line[start] == '#';
|
// Must start with '#'.
|
||||||
|
if (start >= line.size() || line[start] != '#')
|
||||||
|
return std::make_tuple(false, "", "");
|
||||||
|
++start;
|
||||||
|
// Ingore "include" and following spaces.
|
||||||
|
if (line.compare(start, 7, "include") == 0) {
|
||||||
|
start += 7;
|
||||||
|
while (start < line.size() && isspace(line[start]))
|
||||||
|
++start;
|
||||||
|
}
|
||||||
|
// Determine the surrounding characters.
|
||||||
|
std::string surround;
|
||||||
|
if (line[start] == '"') {
|
||||||
|
surround = "\"\"";
|
||||||
|
++start;
|
||||||
|
} else if (line[start] == '<') {
|
||||||
|
surround = "<>";
|
||||||
|
++start;
|
||||||
|
} else
|
||||||
|
surround = "<>";
|
||||||
|
// Fix the prefix for completion.
|
||||||
|
size_t end = start;
|
||||||
|
while (end < line.size() && line[end] != '\"' && line[end] != '>')
|
||||||
|
++end;
|
||||||
|
std::string prefix = line.substr(start, end - start);
|
||||||
|
|
||||||
|
return std::make_tuple(true, surround, prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: eliminate |line_number| param.
|
// TODO: eliminate |line_number| param.
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "language_server_api.h"
|
#include "language_server_api.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
// Utility method to map |position| to an offset inside of |content|.
|
// Utility method to map |position| to an offset inside of |content|.
|
||||||
int GetOffsetForPosition(lsPosition position, const std::string& content);
|
int GetOffsetForPosition(lsPosition position, const std::string& content);
|
||||||
@ -11,7 +12,8 @@ lsPosition CharPos(const std::string& search,
|
|||||||
char character,
|
char character,
|
||||||
int character_offset = 0);
|
int character_offset = 0);
|
||||||
|
|
||||||
bool ShouldRunIncludeCompletion(const std::string& line);
|
std::tuple<bool, std::string, std::string> ShouldRunIncludeCompletion(
|
||||||
|
const std::string& line);
|
||||||
|
|
||||||
// TODO: eliminate |line_number| param.
|
// TODO: eliminate |line_number| param.
|
||||||
optional<lsRange> ExtractQuotedRange(int line_number, const std::string& line);
|
optional<lsRange> ExtractQuotedRange(int line_number, const std::string& line);
|
||||||
|
@ -38,7 +38,7 @@ struct lsCompletionOptions {
|
|||||||
// for
|
// for
|
||||||
// '::' and '>' for '->'. See
|
// '::' and '>' for '->'. See
|
||||||
// https://github.com/Microsoft/language-server-protocol/issues/138.
|
// https://github.com/Microsoft/language-server-protocol/issues/138.
|
||||||
std::vector<std::string> triggerCharacters = {".", ":", ">", "#"};
|
std::vector<std::string> triggerCharacters = {".", ":", ">", "#", "<", "\""};
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsCompletionOptions, resolveProvider, triggerCharacters);
|
MAKE_REFLECT_STRUCT(lsCompletionOptions, resolveProvider, triggerCharacters);
|
||||||
|
|
||||||
|
@ -256,9 +256,17 @@ struct TextDocumentCompletionHandler : MessageHandler {
|
|||||||
std::string character = *request->params.context->triggerCharacter;
|
std::string character = *request->params.context->triggerCharacter;
|
||||||
char preceding_index = request->params.position.character - 2;
|
char preceding_index = request->params.position.character - 2;
|
||||||
|
|
||||||
|
// If the character is '"' or '<', make sure the line is start with '#'.
|
||||||
|
if (character == "\"" || character == "<") {
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < buffer_line.size() && isspace(buffer_line[i]))
|
||||||
|
++i;
|
||||||
|
if (i >= buffer_line.size() || buffer_line[i] != '#')
|
||||||
|
did_fail_check = true;
|
||||||
|
}
|
||||||
// If the character is > or : and we are at the start of the line, do not
|
// If the character is > or : and we are at the start of the line, do not
|
||||||
// show completion results.
|
// show completion results.
|
||||||
if ((character == ">" || character == ":") && preceding_index < 0) {
|
else if ((character == ">" || character == ":") && preceding_index < 0) {
|
||||||
did_fail_check = true;
|
did_fail_check = true;
|
||||||
}
|
}
|
||||||
// If the character is > but - does not preced it, or if it is : and :
|
// If the character is > but - does not preced it, or if it is : and :
|
||||||
@ -283,7 +291,11 @@ struct TextDocumentCompletionHandler : MessageHandler {
|
|||||||
&existing_completion);
|
&existing_completion);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldRunIncludeCompletion(buffer_line)) {
|
bool yes;
|
||||||
|
std::string surround, prefix;
|
||||||
|
std::tie(yes, surround, prefix) = ShouldRunIncludeCompletion(buffer_line);
|
||||||
|
|
||||||
|
if (yes) {
|
||||||
Out_TextDocumentComplete out;
|
Out_TextDocumentComplete out;
|
||||||
out.id = request->id;
|
out.id = request->id;
|
||||||
|
|
||||||
@ -296,19 +308,26 @@ struct TextDocumentCompletionHandler : MessageHandler {
|
|||||||
include_complete->completion_items.end());
|
include_complete->completion_items.end());
|
||||||
if (lock)
|
if (lock)
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
// Update textEdit params.
|
|
||||||
for (lsCompletionItem& item : out.result.items) {
|
|
||||||
item.textEdit->range.start.line = request->params.position.line;
|
|
||||||
item.textEdit->range.start.character = 0;
|
|
||||||
item.textEdit->range.end.line = request->params.position.line;
|
|
||||||
item.textEdit->range.end.character = (int)buffer_line.size();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TrimInPlace(buffer_line);
|
FilterAndSortCompletionResponse(&out, prefix,
|
||||||
FilterAndSortCompletionResponse(&out, buffer_line,
|
|
||||||
config->completion.filterAndSort);
|
config->completion.filterAndSort);
|
||||||
|
|
||||||
|
auto decorator = [&](std::string& text) {
|
||||||
|
std::string result = "#include ";
|
||||||
|
result += surround[0] + text + surround[1];
|
||||||
|
text = result;
|
||||||
|
};
|
||||||
|
LOG_S(INFO) << "DEBUG prefix " << prefix;
|
||||||
|
for (lsCompletionItem& item : out.result.items) {
|
||||||
|
item.textEdit->range.start.line = request->params.position.line;
|
||||||
|
item.textEdit->range.start.character = 0;
|
||||||
|
item.textEdit->range.end.line = request->params.position.line;
|
||||||
|
item.textEdit->range.end.character = (int)buffer_line.size();
|
||||||
|
decorator(item.textEdit->newText);
|
||||||
|
decorator(item.label);
|
||||||
|
}
|
||||||
|
|
||||||
QueueManager::WriteStdout(IpcId::TextDocumentCompletion, out);
|
QueueManager::WriteStdout(IpcId::TextDocumentCompletion, out);
|
||||||
} else {
|
} else {
|
||||||
// If existing completion is empty, dont return clang-based completion
|
// If existing completion is empty, dont return clang-based completion
|
||||||
|
Loading…
Reference in New Issue
Block a user