mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-22 15:45:08 +00:00
Complex include completion.
This commit is contained in:
parent
e16753d261
commit
15dd552610
@ -45,38 +45,42 @@ lsPosition CharPos(std::string_view search,
|
||||
return result;
|
||||
}
|
||||
|
||||
std::tuple<bool, std::string, std::string> ShouldRunIncludeCompletion(
|
||||
const std::string& line) {
|
||||
size_t start = 0;
|
||||
while (start < line.size() && isspace(line[start]))
|
||||
++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;
|
||||
ParseIncludeLineResult ParseIncludeLine(const std::string& line) {
|
||||
static const std::regex pattern(
|
||||
"(\\s*)" // [1]: spaces before '#'
|
||||
"#" //
|
||||
"(\\s*)" // [2]: spaces after '#'
|
||||
"([^\\s\"<]*)" // [3]: "include"
|
||||
"(\\s*)" // [4]: spaces before quote
|
||||
"([\"<])?" // [5]: the first quote char
|
||||
"([^\\s\">]*)" // [6]: path of file
|
||||
"[\">]?" //
|
||||
"(.*)"); // [7]: suffix after quote char
|
||||
std::smatch match;
|
||||
bool ok = std::regex_match(line, match, pattern);
|
||||
std::string text = match[3].str() + match[6].str();
|
||||
return {ok, text, match};
|
||||
}
|
||||
// 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);
|
||||
void DecorateIncludePaths(const std::smatch& match,
|
||||
std::vector<lsCompletionItem>* items) {
|
||||
char quote0, quote1;
|
||||
if (match[5].compare("\"") == 0)
|
||||
quote0 = quote1 = '"';
|
||||
else
|
||||
quote0 = '<', quote1 = '>';
|
||||
|
||||
std::string spaces_between_include_and_quote =
|
||||
match[3].compare("include") == 0 ? match[4].str() : " ";
|
||||
|
||||
std::string prefix = match[1].str() + '#' + match[2].str() + "include" +
|
||||
spaces_between_include_and_quote + quote0;
|
||||
std::string suffix = std::string(1, quote1) + match[7].str();
|
||||
|
||||
for (lsCompletionItem& item : *items) {
|
||||
item.textEdit->newText = prefix + item.textEdit->newText + suffix;
|
||||
item.label = prefix + item.label.substr(7) + suffix;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: eliminate |line_number| param.
|
||||
@ -229,6 +233,8 @@ bool SubsequenceMatch(std::string_view search, std::string_view content) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find discontinous |search| in |content|.
|
||||
// Return |found| and the count of skipped chars before found.
|
||||
std::tuple<bool, int> SubsequenceCountSkip(std::string_view search,
|
||||
std::string_view content) {
|
||||
bool hasUppercaseLetter = std::any_of(search.begin(), search.end(), isupper);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <string_view.h>
|
||||
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
@ -14,8 +15,17 @@ lsPosition CharPos(std::string_view search,
|
||||
char character,
|
||||
int character_offset = 0);
|
||||
|
||||
std::tuple<bool, std::string, std::string> ShouldRunIncludeCompletion(
|
||||
const std::string& line);
|
||||
struct ParseIncludeLineResult
|
||||
{
|
||||
bool ok;
|
||||
std::string text; // include the "include" part
|
||||
std::smatch match;
|
||||
};
|
||||
|
||||
ParseIncludeLineResult ParseIncludeLine(const std::string& line);
|
||||
|
||||
void DecorateIncludePaths(const std::smatch& match,
|
||||
std::vector<lsCompletionItem>* items);
|
||||
|
||||
// TODO: eliminate |line_number| param.
|
||||
optional<lsRange> ExtractQuotedRange(int line_number, const std::string& line);
|
||||
|
@ -233,11 +233,9 @@ struct TextDocumentCompletionHandler : MessageHandler {
|
||||
&existing_completion);
|
||||
}
|
||||
|
||||
bool yes;
|
||||
std::string surround, prefix;
|
||||
std::tie(yes, surround, prefix) = ShouldRunIncludeCompletion(buffer_line);
|
||||
ParseIncludeLineResult result = ParseIncludeLine(buffer_line);
|
||||
|
||||
if (yes) {
|
||||
if (result.ok) {
|
||||
Out_TextDocumentComplete out;
|
||||
out.id = request->id;
|
||||
|
||||
@ -252,22 +250,20 @@ struct TextDocumentCompletionHandler : MessageHandler {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
FilterAndSortCompletionResponse(&out, prefix,
|
||||
config->completion.filterAndSort);
|
||||
// Needed by |FilterAndSortCompletionResponse|.
|
||||
// Will be removed in |DecorateIncludePaths|.
|
||||
for (lsCompletionItem& item : out.result.items)
|
||||
item.label = "include" + item.label;
|
||||
|
||||
FilterAndSortCompletionResponse(&out, result.text,
|
||||
config->completion.filterAndSort);
|
||||
DecorateIncludePaths(result.match, &out.result.items);
|
||||
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user