mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-22 23:55: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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<bool, std::string, std::string> ShouldRunIncludeCompletion(
|
ParseIncludeLineResult ParseIncludeLine(const std::string& line) {
|
||||||
const std::string& line) {
|
static const std::regex pattern(
|
||||||
size_t start = 0;
|
"(\\s*)" // [1]: spaces before '#'
|
||||||
while (start < line.size() && isspace(line[start]))
|
"#" //
|
||||||
++start;
|
"(\\s*)" // [2]: spaces after '#'
|
||||||
// Must start with '#'.
|
"([^\\s\"<]*)" // [3]: "include"
|
||||||
if (start >= line.size() || line[start] != '#')
|
"(\\s*)" // [4]: spaces before quote
|
||||||
return std::make_tuple(false, "", "");
|
"([\"<])?" // [5]: the first quote char
|
||||||
++start;
|
"([^\\s\">]*)" // [6]: path of file
|
||||||
// Ingore "include" and following spaces.
|
"[\">]?" //
|
||||||
if (line.compare(start, 7, "include") == 0) {
|
"(.*)"); // [7]: suffix after quote char
|
||||||
start += 7;
|
std::smatch match;
|
||||||
while (start < line.size() && isspace(line[start]))
|
bool ok = std::regex_match(line, match, pattern);
|
||||||
++start;
|
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.
|
// TODO: eliminate |line_number| param.
|
||||||
@ -229,6 +233,8 @@ bool SubsequenceMatch(std::string_view search, std::string_view content) {
|
|||||||
return true;
|
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::tuple<bool, int> SubsequenceCountSkip(std::string_view search,
|
||||||
std::string_view content) {
|
std::string_view content) {
|
||||||
bool hasUppercaseLetter = std::any_of(search.begin(), search.end(), isupper);
|
bool hasUppercaseLetter = std::any_of(search.begin(), search.end(), isupper);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <string_view.h>
|
#include <string_view.h>
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
@ -14,8 +15,17 @@ lsPosition CharPos(std::string_view search,
|
|||||||
char character,
|
char character,
|
||||||
int character_offset = 0);
|
int character_offset = 0);
|
||||||
|
|
||||||
std::tuple<bool, std::string, std::string> ShouldRunIncludeCompletion(
|
struct ParseIncludeLineResult
|
||||||
const std::string& line);
|
{
|
||||||
|
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.
|
// 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);
|
||||||
|
@ -233,11 +233,9 @@ struct TextDocumentCompletionHandler : MessageHandler {
|
|||||||
&existing_completion);
|
&existing_completion);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool yes;
|
ParseIncludeLineResult result = ParseIncludeLine(buffer_line);
|
||||||
std::string surround, prefix;
|
|
||||||
std::tie(yes, surround, prefix) = ShouldRunIncludeCompletion(buffer_line);
|
|
||||||
|
|
||||||
if (yes) {
|
if (result.ok) {
|
||||||
Out_TextDocumentComplete out;
|
Out_TextDocumentComplete out;
|
||||||
out.id = request->id;
|
out.id = request->id;
|
||||||
|
|
||||||
@ -252,22 +250,20 @@ struct TextDocumentCompletionHandler : MessageHandler {
|
|||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterAndSortCompletionResponse(&out, prefix,
|
// Needed by |FilterAndSortCompletionResponse|.
|
||||||
config->completion.filterAndSort);
|
// 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) {
|
for (lsCompletionItem& item : out.result.items) {
|
||||||
item.textEdit->range.start.line = request->params.position.line;
|
item.textEdit->range.start.line = request->params.position.line;
|
||||||
item.textEdit->range.start.character = 0;
|
item.textEdit->range.start.character = 0;
|
||||||
item.textEdit->range.end.line = request->params.position.line;
|
item.textEdit->range.end.line = request->params.position.line;
|
||||||
item.textEdit->range.end.character = (int)buffer_line.size();
|
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user