mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-28 02:21:57 +00:00
Improve completion
blacklist some undesired candidates additionalTextEdits if clang>=7 Use CodePatterns for preprocessor directive completion if there is a # Prefer textEdit over insertText
This commit is contained in:
parent
10c1c28dd1
commit
de9c77e1cc
@ -71,6 +71,18 @@ struct ProxyFileSystem : FileSystem {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace ccls {
|
namespace ccls {
|
||||||
|
|
||||||
|
lsTextEdit ToTextEdit(const clang::SourceManager &SM,
|
||||||
|
const clang::LangOptions &L,
|
||||||
|
const clang::FixItHint &FixIt) {
|
||||||
|
lsTextEdit edit;
|
||||||
|
edit.newText = FixIt.CodeToInsert;
|
||||||
|
auto r = FromCharSourceRange(SM, L, FixIt.RemoveRange);
|
||||||
|
edit.range =
|
||||||
|
lsRange{{r.start.line, r.start.column}, {r.end.line, r.end.column}};
|
||||||
|
return edit;
|
||||||
|
}
|
||||||
|
|
||||||
struct PreambleStatCache {
|
struct PreambleStatCache {
|
||||||
llvm::StringMap<ErrorOr<vfs::Status>> Cache;
|
llvm::StringMap<ErrorOr<vfs::Status>> Cache;
|
||||||
|
|
||||||
@ -235,12 +247,7 @@ public:
|
|||||||
for (const FixItHint &FixIt : Info.getFixItHints()) {
|
for (const FixItHint &FixIt : Info.getFixItHints()) {
|
||||||
if (!IsConcerned(SM, FixIt.RemoveRange.getBegin()))
|
if (!IsConcerned(SM, FixIt.RemoveRange.getBegin()))
|
||||||
return false;
|
return false;
|
||||||
lsTextEdit edit;
|
last->edits.push_back(ToTextEdit(SM, *LangOpts, FixIt));
|
||||||
edit.newText = FixIt.CodeToInsert;
|
|
||||||
auto r = FromCharSourceRange(SM, *LangOpts, FixIt.RemoveRange);
|
|
||||||
edit.range =
|
|
||||||
lsRange{{r.start.line, r.start.column}, {r.end.line, r.end.column}};
|
|
||||||
last->edits.push_back(std::move(edit));
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -49,6 +49,10 @@ struct Diag : DiagBase {
|
|||||||
std::vector<lsTextEdit> edits;
|
std::vector<lsTextEdit> edits;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
lsTextEdit ToTextEdit(const clang::SourceManager &SM,
|
||||||
|
const clang::LangOptions &L,
|
||||||
|
const clang::FixItHint &FixIt);
|
||||||
|
|
||||||
struct CompletionSession
|
struct CompletionSession
|
||||||
: public std::enable_shared_from_this<CompletionSession> {
|
: public std::enable_shared_from_this<CompletionSession> {
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
@ -184,9 +188,8 @@ struct CompleteConsumerCache {
|
|||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
bool IsCacheValid(const lsTextDocumentPositionParams ¶ms) {
|
bool IsCacheValid(const std::string path, lsPosition position) {
|
||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
return path == params.textDocument.uri.GetPath() &&
|
return this->path == path && this->position == position;
|
||||||
position == params.position;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -84,8 +84,7 @@ lsCompletionItem BuildCompletionItem(const std::string &path,
|
|||||||
lsCompletionItem item;
|
lsCompletionItem item;
|
||||||
item.label = ElideLongPath(path);
|
item.label = ElideLongPath(path);
|
||||||
item.detail = path; // the include path, used in de-duplicating
|
item.detail = path; // the include path, used in de-duplicating
|
||||||
item.textEdit = lsTextEdit();
|
item.textEdit.newText = path;
|
||||||
item.textEdit->newText = path;
|
|
||||||
item.insertTextFormat = lsInsertTextFormat::PlainText;
|
item.insertTextFormat = lsInsertTextFormat::PlainText;
|
||||||
item.use_angle_brackets_ = use_angle_brackets;
|
item.use_angle_brackets_ = use_angle_brackets;
|
||||||
if (is_stl) {
|
if (is_stl) {
|
||||||
|
@ -114,12 +114,12 @@ struct lsCompletionItem {
|
|||||||
//
|
//
|
||||||
// *Note:* The range of the edit must be a single line range and it must
|
// *Note:* The range of the edit must be a single line range and it must
|
||||||
// contain the position at which completion has been requested.
|
// contain the position at which completion has been requested.
|
||||||
std::optional<lsTextEdit> textEdit;
|
lsTextEdit textEdit;
|
||||||
|
|
||||||
// An std::optional array of additional text edits that are applied when
|
// An std::optional array of additional text edits that are applied when
|
||||||
// selecting this completion. Edits must not overlap with the main edit
|
// selecting this completion. Edits must not overlap with the main edit
|
||||||
// nor with themselves.
|
// nor with themselves.
|
||||||
// std::vector<TextEdit> additionalTextEdits;
|
std::vector<lsTextEdit> additionalTextEdits;
|
||||||
|
|
||||||
// An std::optional command that is executed *after* inserting this
|
// An std::optional command that is executed *after* inserting this
|
||||||
// completion. *Note* that additional modifications to the current document
|
// completion. *Note* that additional modifications to the current document
|
||||||
@ -128,18 +128,7 @@ struct lsCompletionItem {
|
|||||||
// An data entry field that is preserved on a completion item between
|
// An data entry field that is preserved on a completion item between
|
||||||
// a completion and a completion resolve request.
|
// a completion and a completion resolve request.
|
||||||
// data ? : any
|
// data ? : any
|
||||||
|
|
||||||
// Use this helper to figure out what content the completion item will insert
|
|
||||||
// into the document, as it could live in either |textEdit|, |insertText|, or
|
|
||||||
// |label|.
|
|
||||||
const std::string &InsertedContent() const {
|
|
||||||
if (textEdit)
|
|
||||||
return textEdit->newText;
|
|
||||||
if (!insertText.empty())
|
|
||||||
return insertText;
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsCompletionItem, label, kind, detail, documentation,
|
MAKE_REFLECT_STRUCT(lsCompletionItem, label, kind, detail, documentation,
|
||||||
sortText, insertText, filterText, insertTextFormat,
|
sortText, filterText, insertText, insertTextFormat,
|
||||||
textEdit);
|
textEdit, additionalTextEdits);
|
||||||
|
@ -107,8 +107,8 @@ void DecorateIncludePaths(const std::smatch &match,
|
|||||||
else
|
else
|
||||||
quote0 = quote1 = '"';
|
quote0 = quote1 = '"';
|
||||||
|
|
||||||
item.textEdit->newText =
|
item.textEdit.newText =
|
||||||
prefix + quote0 + item.textEdit->newText + quote1 + suffix;
|
prefix + quote0 + item.textEdit.newText + quote1 + suffix;
|
||||||
item.label = prefix + quote0 + item.label + quote1 + suffix;
|
item.label = prefix + quote0 + item.label + quote1 + suffix;
|
||||||
item.filterText = std::nullopt;
|
item.filterText = std::nullopt;
|
||||||
}
|
}
|
||||||
@ -137,27 +137,6 @@ ParseIncludeLineResult ParseIncludeLine(const std::string &line) {
|
|||||||
return {ok, match[3], match[5], match[6], match};
|
return {ok, match[3], match[5], match[6], match};
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::vector<std::string> preprocessorKeywords = {
|
|
||||||
"define", "undef", "include", "if", "ifdef", "ifndef",
|
|
||||||
"else", "elif", "endif", "line", "error", "pragma"};
|
|
||||||
|
|
||||||
std::vector<lsCompletionItem>
|
|
||||||
PreprocessorKeywordCompletionItems(const std::smatch &match) {
|
|
||||||
std::vector<lsCompletionItem> items;
|
|
||||||
for (auto &keyword : preprocessorKeywords) {
|
|
||||||
lsCompletionItem item;
|
|
||||||
item.label = keyword;
|
|
||||||
item.priority_ = (keyword == "include" ? 2 : 1);
|
|
||||||
item.textEdit = lsTextEdit();
|
|
||||||
std::string space = (keyword == "else" || keyword == "endif") ? "" : " ";
|
|
||||||
item.textEdit->newText = match[1].str() + "#" + match[2].str() + keyword +
|
|
||||||
space + match[6].str();
|
|
||||||
item.insertTextFormat = lsInsertTextFormat::PlainText;
|
|
||||||
items.push_back(item);
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> char *tofixedbase64(T input, char *out) {
|
template <typename T> char *tofixedbase64(T input, char *out) {
|
||||||
const char *digits = "./0123456789"
|
const char *digits = "./0123456789"
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
@ -174,11 +153,9 @@ template <typename T> char *tofixedbase64(T input, char *out) {
|
|||||||
// Pre-filters completion responses before sending to vscode. This results in a
|
// Pre-filters completion responses before sending to vscode. This results in a
|
||||||
// significantly snappier completion experience as vscode is easily overloaded
|
// significantly snappier completion experience as vscode is easily overloaded
|
||||||
// when given 1000+ completion items.
|
// when given 1000+ completion items.
|
||||||
void FilterAndSortCompletionResponse(
|
void FilterCandidates(Out_TextDocumentComplete *complete_response,
|
||||||
Out_TextDocumentComplete *complete_response,
|
const std::string &complete_text, lsPosition begin_pos,
|
||||||
const std::string &complete_text, bool has_open_paren) {
|
lsPosition end_pos, bool has_open_paren) {
|
||||||
if (!g_config->completion.filterAndSort)
|
|
||||||
return;
|
|
||||||
auto &items = complete_response->result.items;
|
auto &items = complete_response->result.items;
|
||||||
|
|
||||||
auto finalize = [&]() {
|
auto finalize = [&]() {
|
||||||
@ -188,9 +165,21 @@ void FilterAndSortCompletionResponse(
|
|||||||
complete_response->result.isIncomplete = true;
|
complete_response->result.isIncomplete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_open_paren)
|
for (auto &item : items) {
|
||||||
for (auto &item : items)
|
item.textEdit.range = lsRange{begin_pos, end_pos};
|
||||||
item.insertText = item.label;
|
if (has_open_paren)
|
||||||
|
item.textEdit.newText = item.label;
|
||||||
|
// https://github.com/Microsoft/language-server-protocol/issues/543
|
||||||
|
// Order of textEdit and additionalTextEdits is unspecified.
|
||||||
|
auto &edits = item.additionalTextEdits;
|
||||||
|
if (edits.size() && edits[0].range.end == begin_pos) {
|
||||||
|
item.textEdit.range.start = edits[0].range.start;
|
||||||
|
item.textEdit.newText = edits[0].newText + item.textEdit.newText;
|
||||||
|
edits.erase(edits.begin());
|
||||||
|
}
|
||||||
|
// Compatibility
|
||||||
|
item.insertText = item.textEdit.newText;
|
||||||
|
}
|
||||||
|
|
||||||
// Set sortText. Note that this happens after resizing - we could do it
|
// Set sortText. Note that this happens after resizing - we could do it
|
||||||
// before, but then we should also sort by priority.
|
// before, but then we should also sort by priority.
|
||||||
@ -200,7 +189,7 @@ void FilterAndSortCompletionResponse(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// No complete text; don't run any filtering logic except to trim the items.
|
// No complete text; don't run any filtering logic except to trim the items.
|
||||||
if (complete_text.empty()) {
|
if (!g_config->completion.filterAndSort || complete_text.empty()) {
|
||||||
finalize();
|
finalize();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -261,19 +250,6 @@ bool IsOpenParenOrAngle(const std::vector<std::string> &lines,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned GetCompletionPriority(const CodeCompletionString &CCS,
|
|
||||||
CXCursorKind result_kind,
|
|
||||||
const std::optional<std::string> &typedText) {
|
|
||||||
unsigned priority = CCS.getPriority();
|
|
||||||
if (CCS.getAvailability() != CXAvailability_Available ||
|
|
||||||
result_kind == CXCursor_Destructor ||
|
|
||||||
result_kind == CXCursor_ConversionFunction ||
|
|
||||||
(result_kind == CXCursor_CXXMethod && typedText &&
|
|
||||||
StartsWith(*typedText, "operator")))
|
|
||||||
priority *= 100;
|
|
||||||
return priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) {
|
lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) {
|
||||||
switch (cursor_kind) {
|
switch (cursor_kind) {
|
||||||
case CXCursor_UnexposedDecl:
|
case CXCursor_UnexposedDecl:
|
||||||
@ -366,11 +342,11 @@ lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildItem(std::vector<lsCompletionItem> &out,
|
void BuildItem(const CodeCompletionResult &R, const CodeCompletionString &CCS,
|
||||||
const CodeCompletionString &CCS) {
|
std::vector<lsCompletionItem> &out) {
|
||||||
assert(!out.empty());
|
assert(!out.empty());
|
||||||
auto first = out.size() - 1;
|
auto first = out.size() - 1;
|
||||||
|
bool ignore = false;
|
||||||
std::string result_type;
|
std::string result_type;
|
||||||
|
|
||||||
for (const auto &Chunk : CCS) {
|
for (const auto &Chunk : CCS) {
|
||||||
@ -404,7 +380,7 @@ void BuildItem(std::vector<lsCompletionItem> &out,
|
|||||||
// Duplicate last element, the recursive call will complete it.
|
// Duplicate last element, the recursive call will complete it.
|
||||||
if (g_config->completion.duplicateOptional) {
|
if (g_config->completion.duplicateOptional) {
|
||||||
out.push_back(out.back());
|
out.push_back(out.back());
|
||||||
BuildItem(out, *Chunk.Optional);
|
BuildItem(R, *Chunk.Optional, out);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -415,15 +391,20 @@ void BuildItem(std::vector<lsCompletionItem> &out,
|
|||||||
|
|
||||||
for (auto i = first; i < out.size(); ++i) {
|
for (auto i = first; i < out.size(); ++i) {
|
||||||
out[i].label += text;
|
out[i].label += text;
|
||||||
if (!g_config->client.snippetSupport && !out[i].parameters_.empty())
|
if (ignore ||
|
||||||
|
(!g_config->client.snippetSupport && out[i].parameters_.size()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (Kind == CodeCompletionString::CK_Placeholder) {
|
if (Kind == CodeCompletionString::CK_Placeholder) {
|
||||||
out[i].insertText +=
|
if (R.Kind == CodeCompletionResult::RK_Pattern) {
|
||||||
|
ignore = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
out[i].textEdit.newText +=
|
||||||
"${" + std::to_string(out[i].parameters_.size()) + ":" + text + "}";
|
"${" + std::to_string(out[i].parameters_.size()) + ":" + text + "}";
|
||||||
out[i].insertTextFormat = lsInsertTextFormat::Snippet;
|
out[i].insertTextFormat = lsInsertTextFormat::Snippet;
|
||||||
} else if (Kind != CodeCompletionString::CK_Informative) {
|
} else if (Kind != CodeCompletionString::CK_Informative) {
|
||||||
out[i].insertText += text;
|
out[i].textEdit.newText += text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -453,12 +434,25 @@ public:
|
|||||||
void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
|
void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
|
||||||
CodeCompletionResult *Results,
|
CodeCompletionResult *Results,
|
||||||
unsigned NumResults) override {
|
unsigned NumResults) override {
|
||||||
|
if (Context.getKind() == CodeCompletionContext::CCC_Recovery)
|
||||||
|
return;
|
||||||
ls_items.reserve(NumResults);
|
ls_items.reserve(NumResults);
|
||||||
for (unsigned i = 0; i != NumResults; i++) {
|
for (unsigned i = 0; i != NumResults; i++) {
|
||||||
auto &R = Results[i];
|
auto &R = Results[i];
|
||||||
if (R.Availability == CXAvailability_NotAccessible ||
|
if (R.Availability == CXAvailability_NotAccessible ||
|
||||||
R.Availability == CXAvailability_NotAvailable)
|
R.Availability == CXAvailability_NotAvailable)
|
||||||
continue;
|
continue;
|
||||||
|
if (R.Declaration) {
|
||||||
|
if (R.Declaration->getKind() == Decl::CXXDestructor)
|
||||||
|
continue;
|
||||||
|
if (auto *RD = dyn_cast<RecordDecl>(R.Declaration))
|
||||||
|
if (RD->isInjectedClassName())
|
||||||
|
continue;
|
||||||
|
auto NK = R.Declaration->getDeclName().getNameKind();
|
||||||
|
if (NK == DeclarationName::CXXOperatorName ||
|
||||||
|
NK == DeclarationName::CXXLiteralOperatorName)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
CodeCompletionString *CCS = R.CreateCodeCompletionString(
|
CodeCompletionString *CCS = R.CreateCodeCompletionString(
|
||||||
S, Context, getAllocator(), getCodeCompletionTUInfo(),
|
S, Context, getAllocator(), getCodeCompletionTUInfo(),
|
||||||
includeBriefComments());
|
includeBriefComments());
|
||||||
@ -470,19 +464,27 @@ public:
|
|||||||
|
|
||||||
size_t first_idx = ls_items.size();
|
size_t first_idx = ls_items.size();
|
||||||
ls_items.push_back(ls_item);
|
ls_items.push_back(ls_item);
|
||||||
BuildItem(ls_items, *CCS);
|
BuildItem(R, *CCS, ls_items);
|
||||||
|
|
||||||
for (size_t j = first_idx; j < ls_items.size(); j++) {
|
for (size_t j = first_idx; j < ls_items.size(); j++) {
|
||||||
if (g_config->client.snippetSupport &&
|
if (g_config->client.snippetSupport &&
|
||||||
ls_items[j].insertTextFormat == lsInsertTextFormat::Snippet)
|
ls_items[j].insertTextFormat == lsInsertTextFormat::Snippet)
|
||||||
ls_items[j].insertText += "$0";
|
ls_items[j].textEdit.newText += "$0";
|
||||||
ls_items[j].priority_ = GetCompletionPriority(
|
ls_items[j].priority_ = CCS->getPriority();
|
||||||
*CCS, Results[i].CursorKind, ls_items[j].filterText);
|
|
||||||
if (!g_config->completion.detailedLabel) {
|
if (!g_config->completion.detailedLabel) {
|
||||||
ls_items[j].detail = ls_items[j].label;
|
ls_items[j].detail = ls_items[j].label;
|
||||||
ls_items[j].label = ls_items[j].filterText.value_or("");
|
ls_items[j].label = ls_items[j].filterText.value_or("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if LLVM_VERSION_MAJOR >= 7
|
||||||
|
for (const FixItHint &FixIt : R.FixIts) {
|
||||||
|
auto &AST = S.getASTContext();
|
||||||
|
lsTextEdit ls_edit =
|
||||||
|
ccls::ToTextEdit(AST.getSourceManager(), AST.getLangOpts(), FixIt);
|
||||||
|
for (size_t j = first_idx; j < ls_items.size(); j++)
|
||||||
|
ls_items[j].additionalTextEdits.push_back(ls_edit);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,7 +499,7 @@ struct Handler_TextDocumentCompletion
|
|||||||
void Run(In_TextDocumentComplete *request) override {
|
void Run(In_TextDocumentComplete *request) override {
|
||||||
static CompleteConsumerCache<std::vector<lsCompletionItem>> cache;
|
static CompleteConsumerCache<std::vector<lsCompletionItem>> cache;
|
||||||
|
|
||||||
auto ¶ms = request->params;
|
const auto ¶ms = request->params;
|
||||||
Out_TextDocumentComplete out;
|
Out_TextDocumentComplete out;
|
||||||
out.id = request->id;
|
out.id = request->id;
|
||||||
|
|
||||||
@ -556,55 +558,36 @@ struct Handler_TextDocumentCompletion
|
|||||||
|
|
||||||
std::string completion_text;
|
std::string completion_text;
|
||||||
lsPosition end_pos = params.position;
|
lsPosition end_pos = params.position;
|
||||||
params.position = file->FindStableCompletionSource(
|
lsPosition begin_pos = file->FindStableCompletionSource(
|
||||||
request->params.position, &completion_text, &end_pos);
|
params.position, &completion_text, &end_pos);
|
||||||
|
|
||||||
ParseIncludeLineResult result = ParseIncludeLine(buffer_line);
|
ParseIncludeLineResult preprocess = ParseIncludeLine(buffer_line);
|
||||||
bool has_open_paren = IsOpenParenOrAngle(file->buffer_lines, end_pos);
|
bool has_open_paren = IsOpenParenOrAngle(file->buffer_lines, end_pos);
|
||||||
|
|
||||||
if (result.ok) {
|
if (preprocess.ok && preprocess.keyword.compare("include") == 0) {
|
||||||
Out_TextDocumentComplete out;
|
Out_TextDocumentComplete out;
|
||||||
out.id = request->id;
|
out.id = request->id;
|
||||||
|
{
|
||||||
if (result.quote.empty() && result.pattern.empty()) {
|
std::unique_lock<std::mutex> lock(
|
||||||
// no quote or path of file, do preprocessor keyword completion
|
include_complete->completion_items_mutex, std::defer_lock);
|
||||||
if (!std::any_of(preprocessorKeywords.begin(),
|
if (include_complete->is_scanning)
|
||||||
preprocessorKeywords.end(),
|
lock.lock();
|
||||||
[&result](std::string_view k) {
|
std::string quote = preprocess.match[5];
|
||||||
return k == result.keyword;
|
for (auto &item : include_complete->completion_items)
|
||||||
})) {
|
if (quote.empty() || quote == (item.use_angle_brackets_ ? "<" : "\""))
|
||||||
out.result.items = PreprocessorKeywordCompletionItems(result.match);
|
out.result.items.push_back(item);
|
||||||
FilterAndSortCompletionResponse(&out, result.keyword, has_open_paren);
|
|
||||||
}
|
|
||||||
} else if (result.keyword.compare("include") == 0) {
|
|
||||||
{
|
|
||||||
// do include completion
|
|
||||||
std::unique_lock<std::mutex> lock(
|
|
||||||
include_complete->completion_items_mutex, std::defer_lock);
|
|
||||||
if (include_complete->is_scanning)
|
|
||||||
lock.lock();
|
|
||||||
std::string quote = result.match[5];
|
|
||||||
for (auto &item : include_complete->completion_items)
|
|
||||||
if (quote.empty() ||
|
|
||||||
quote == (item.use_angle_brackets_ ? "<" : "\""))
|
|
||||||
out.result.items.push_back(item);
|
|
||||||
}
|
|
||||||
FilterAndSortCompletionResponse(&out, result.pattern, has_open_paren);
|
|
||||||
DecorateIncludePaths(result.match, &out.result.items);
|
|
||||||
}
|
}
|
||||||
|
begin_pos.character = 0;
|
||||||
for (lsCompletionItem &item : out.result.items) {
|
end_pos.character = (int)buffer_line.size();
|
||||||
item.textEdit->range.start.line = params.position.line;
|
FilterCandidates(&out, preprocess.pattern, begin_pos, end_pos,
|
||||||
item.textEdit->range.start.character = 0;
|
has_open_paren);
|
||||||
item.textEdit->range.end.line = params.position.line;
|
DecorateIncludePaths(preprocess.match, &out.result.items);
|
||||||
item.textEdit->range.end.character = (int)buffer_line.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline::WriteStdout(kMethodType, out);
|
pipeline::WriteStdout(kMethodType, out);
|
||||||
} else {
|
} else {
|
||||||
|
std::string path = params.textDocument.uri.GetPath();
|
||||||
CompletionManager::OnComplete callback =
|
CompletionManager::OnComplete callback =
|
||||||
[completion_text, has_open_paren, id = request->id,
|
[completion_text, path, begin_pos, end_pos, has_open_paren,
|
||||||
params = request->params](CodeCompleteConsumer *OptConsumer) {
|
id = request->id](CodeCompleteConsumer *OptConsumer) {
|
||||||
if (!OptConsumer)
|
if (!OptConsumer)
|
||||||
return;
|
return;
|
||||||
auto *Consumer = static_cast<CompletionConsumer *>(OptConsumer);
|
auto *Consumer = static_cast<CompletionConsumer *>(OptConsumer);
|
||||||
@ -612,14 +595,13 @@ struct Handler_TextDocumentCompletion
|
|||||||
out.id = id;
|
out.id = id;
|
||||||
out.result.items = Consumer->ls_items;
|
out.result.items = Consumer->ls_items;
|
||||||
|
|
||||||
FilterAndSortCompletionResponse(&out, completion_text,
|
FilterCandidates(&out, completion_text, begin_pos, end_pos,
|
||||||
has_open_paren);
|
has_open_paren);
|
||||||
pipeline::WriteStdout(kMethodType, out);
|
pipeline::WriteStdout(kMethodType, out);
|
||||||
if (!Consumer->from_cache) {
|
if (!Consumer->from_cache) {
|
||||||
std::string path = params.textDocument.uri.GetPath();
|
|
||||||
cache.WithLock([&]() {
|
cache.WithLock([&]() {
|
||||||
cache.path = path;
|
cache.path = path;
|
||||||
cache.position = params.position;
|
cache.position = begin_pos;
|
||||||
cache.result = Consumer->ls_items;
|
cache.result = Consumer->ls_items;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -627,18 +609,19 @@ struct Handler_TextDocumentCompletion
|
|||||||
|
|
||||||
clang::CodeCompleteOptions CCOpts;
|
clang::CodeCompleteOptions CCOpts;
|
||||||
CCOpts.IncludeBriefComments = true;
|
CCOpts.IncludeBriefComments = true;
|
||||||
|
CCOpts.IncludeCodePatterns = preprocess.ok; // if there is a #
|
||||||
#if LLVM_VERSION_MAJOR >= 7
|
#if LLVM_VERSION_MAJOR >= 7
|
||||||
CCOpts.IncludeFixIts = true;
|
CCOpts.IncludeFixIts = true;
|
||||||
#endif
|
#endif
|
||||||
CCOpts.IncludeMacros = true;
|
CCOpts.IncludeMacros = true;
|
||||||
if (cache.IsCacheValid(params)) {
|
if (cache.IsCacheValid(path, begin_pos)) {
|
||||||
CompletionConsumer Consumer(CCOpts, true);
|
CompletionConsumer Consumer(CCOpts, true);
|
||||||
cache.WithLock([&]() { Consumer.ls_items = cache.result; });
|
cache.WithLock([&]() { Consumer.ls_items = cache.result; });
|
||||||
callback(&Consumer);
|
callback(&Consumer);
|
||||||
} else {
|
} else {
|
||||||
clang_complete->completion_request_.PushBack(
|
clang_complete->completion_request_.PushBack(
|
||||||
std::make_unique<CompletionManager::CompletionRequest>(
|
std::make_unique<CompletionManager::CompletionRequest>(
|
||||||
request->id, params.textDocument, params.position,
|
request->id, params.textDocument, begin_pos,
|
||||||
std::make_unique<CompletionConsumer>(CCOpts, false), CCOpts,
|
std::make_unique<CompletionConsumer>(CCOpts, false), CCOpts,
|
||||||
callback));
|
callback));
|
||||||
}
|
}
|
||||||
|
@ -184,18 +184,18 @@ struct Handler_TextDocumentSignatureHelp
|
|||||||
void Run(In_TextDocumentSignatureHelp *request) override {
|
void Run(In_TextDocumentSignatureHelp *request) override {
|
||||||
static CompleteConsumerCache<lsSignatureHelp> cache;
|
static CompleteConsumerCache<lsSignatureHelp> cache;
|
||||||
|
|
||||||
auto ¶ms = request->params;
|
const auto ¶ms = request->params;
|
||||||
std::string path = params.textDocument.uri.GetPath();
|
std::string path = params.textDocument.uri.GetPath();
|
||||||
|
lsPosition begin_pos = params.position;
|
||||||
if (WorkingFile *file = working_files->GetFileByFilename(path)) {
|
if (WorkingFile *file = working_files->GetFileByFilename(path)) {
|
||||||
std::string completion_text;
|
std::string completion_text;
|
||||||
lsPosition end_pos = params.position;
|
lsPosition end_pos = params.position;
|
||||||
params.position = file->FindStableCompletionSource(
|
begin_pos = file->FindStableCompletionSource(
|
||||||
request->params.position, &completion_text, &end_pos);
|
request->params.position, &completion_text, &end_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompletionManager::OnComplete callback =
|
CompletionManager::OnComplete callback =
|
||||||
[id = request->id,
|
[id = request->id, path, begin_pos](CodeCompleteConsumer *OptConsumer) {
|
||||||
params = request->params](CodeCompleteConsumer *OptConsumer) {
|
|
||||||
if (!OptConsumer)
|
if (!OptConsumer)
|
||||||
return;
|
return;
|
||||||
auto *Consumer = static_cast<SignatureHelpConsumer *>(OptConsumer);
|
auto *Consumer = static_cast<SignatureHelpConsumer *>(OptConsumer);
|
||||||
@ -204,10 +204,9 @@ struct Handler_TextDocumentSignatureHelp
|
|||||||
out.result = Consumer->ls_sighelp;
|
out.result = Consumer->ls_sighelp;
|
||||||
pipeline::WriteStdout(kMethodType, out);
|
pipeline::WriteStdout(kMethodType, out);
|
||||||
if (!Consumer->from_cache) {
|
if (!Consumer->from_cache) {
|
||||||
std::string path = params.textDocument.uri.GetPath();
|
|
||||||
cache.WithLock([&]() {
|
cache.WithLock([&]() {
|
||||||
cache.path = path;
|
cache.path = path;
|
||||||
cache.position = params.position;
|
cache.position = begin_pos;
|
||||||
cache.result = Consumer->ls_sighelp;
|
cache.result = Consumer->ls_sighelp;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -217,7 +216,7 @@ struct Handler_TextDocumentSignatureHelp
|
|||||||
CCOpts.IncludeGlobals = false;
|
CCOpts.IncludeGlobals = false;
|
||||||
CCOpts.IncludeMacros = false;
|
CCOpts.IncludeMacros = false;
|
||||||
CCOpts.IncludeBriefComments = false;
|
CCOpts.IncludeBriefComments = false;
|
||||||
if (cache.IsCacheValid(params)) {
|
if (cache.IsCacheValid(path, begin_pos)) {
|
||||||
SignatureHelpConsumer Consumer(CCOpts, true);
|
SignatureHelpConsumer Consumer(CCOpts, true);
|
||||||
cache.WithLock([&]() { Consumer.ls_sighelp = cache.result; });
|
cache.WithLock([&]() { Consumer.ls_sighelp = cache.result; });
|
||||||
callback(&Consumer);
|
callback(&Consumer);
|
||||||
|
Loading…
Reference in New Issue
Block a user