mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-22 07:35:08 +00:00
Use Sema/CodeCompleteConsumer
This commit is contained in:
parent
d3536831c3
commit
a4dd5d0c44
@ -5,8 +5,10 @@
|
|||||||
#include "log.hh"
|
#include "log.hh"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include <clang/Sema/CodeCompleteConsumer.h>
|
||||||
#include <llvm/ADT/Twine.h>
|
#include <llvm/ADT/Twine.h>
|
||||||
#include <llvm/Support/Threading.h>
|
#include <llvm/Support/Threading.h>
|
||||||
|
using namespace clang;
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -30,23 +32,16 @@ std::string StripFileType(const std::string& path) {
|
|||||||
return Ret.str();
|
return Ret.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned GetCompletionPriority(const CXCompletionString& str,
|
unsigned GetCompletionPriority(const CodeCompletionString& CCS,
|
||||||
CXCursorKind result_kind,
|
CXCursorKind result_kind,
|
||||||
const std::optional<std::string>& typedText) {
|
const std::optional<std::string>& typedText) {
|
||||||
unsigned priority = clang_getCompletionPriority(str);
|
unsigned priority = CCS.getPriority();
|
||||||
|
if (CCS.getAvailability() != CXAvailability_Available ||
|
||||||
// XXX: What happens if priority overflows?
|
result_kind == CXCursor_Destructor ||
|
||||||
if (result_kind == CXCursor_Destructor) {
|
result_kind == CXCursor_ConversionFunction ||
|
||||||
priority *= 100;
|
|
||||||
}
|
|
||||||
if (result_kind == CXCursor_ConversionFunction ||
|
|
||||||
(result_kind == CXCursor_CXXMethod && typedText &&
|
(result_kind == CXCursor_CXXMethod && typedText &&
|
||||||
StartsWith(*typedText, "operator"))) {
|
StartsWith(*typedText, "operator")))
|
||||||
priority *= 100;
|
priority *= 100;
|
||||||
}
|
|
||||||
if (clang_getCompletionAvailability(str) != CXAvailability_Available) {
|
|
||||||
priority *= 100;
|
|
||||||
}
|
|
||||||
return priority;
|
return priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,85 +137,76 @@ lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildCompletionItemTexts(std::vector<lsCompletionItem>& out,
|
void BuildCompletionItemTexts(std::vector<lsCompletionItem> &out,
|
||||||
CXCompletionString completion_string,
|
CodeCompletionString &CCS,
|
||||||
bool include_snippets) {
|
bool include_snippets) {
|
||||||
assert(!out.empty());
|
assert(!out.empty());
|
||||||
auto out_first = out.size() - 1;
|
auto out_first = out.size() - 1;
|
||||||
|
|
||||||
std::string result_type;
|
std::string result_type;
|
||||||
|
|
||||||
int num_chunks = clang_getNumCompletionChunks(completion_string);
|
for (unsigned i = 0, num_chunks = CCS.size(); i < num_chunks; ++i) {
|
||||||
for (int i = 0; i < num_chunks; ++i) {
|
const CodeCompletionString::Chunk &Chunk = CCS[i];
|
||||||
CXCompletionChunkKind kind =
|
CodeCompletionString::ChunkKind Kind = Chunk.Kind;
|
||||||
clang_getCompletionChunkKind(completion_string, i);
|
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
switch (kind) {
|
switch (Kind) {
|
||||||
// clang-format off
|
case CodeCompletionString::CK_TypedText:
|
||||||
case CXCompletionChunk_LeftParen: text = '('; break;
|
case CodeCompletionString::CK_Text:
|
||||||
case CXCompletionChunk_RightParen: text = ')'; break;
|
case CodeCompletionString::CK_Placeholder:
|
||||||
case CXCompletionChunk_LeftBracket: text = '['; break;
|
case CodeCompletionString::CK_Informative:
|
||||||
case CXCompletionChunk_RightBracket: text = ']'; break;
|
if (Chunk.Text)
|
||||||
case CXCompletionChunk_LeftBrace: text = '{'; break;
|
text = Chunk.Text;
|
||||||
case CXCompletionChunk_RightBrace: text = '}'; break;
|
for (auto i = out_first; i < out.size(); i++) {
|
||||||
case CXCompletionChunk_LeftAngle: text = '<'; break;
|
// first TypedText is used for filtering
|
||||||
case CXCompletionChunk_RightAngle: text = '>'; break;
|
if (Kind == CodeCompletionString::CK_TypedText && !out[i].filterText)
|
||||||
case CXCompletionChunk_Comma: text = ", "; break;
|
|
||||||
case CXCompletionChunk_Colon: text = ':'; break;
|
|
||||||
case CXCompletionChunk_SemiColon: text = ';'; break;
|
|
||||||
case CXCompletionChunk_Equal: text = '='; break;
|
|
||||||
case CXCompletionChunk_HorizontalSpace: text = ' '; break;
|
|
||||||
case CXCompletionChunk_VerticalSpace: text = ' '; break;
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
case CXCompletionChunk_ResultType:
|
|
||||||
result_type =
|
|
||||||
ToString(clang_getCompletionChunkText(completion_string, i));
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case CXCompletionChunk_TypedText:
|
|
||||||
case CXCompletionChunk_Placeholder:
|
|
||||||
case CXCompletionChunk_Text:
|
|
||||||
case CXCompletionChunk_Informative:
|
|
||||||
text = ToString(clang_getCompletionChunkText(completion_string, i));
|
|
||||||
|
|
||||||
for (auto i = out_first; i < out.size(); ++i) {
|
|
||||||
// first typed text is used for filtering
|
|
||||||
if (kind == CXCompletionChunk_TypedText && !out[i].filterText)
|
|
||||||
out[i].filterText = text;
|
out[i].filterText = text;
|
||||||
|
if (Kind == CodeCompletionString::CK_Placeholder)
|
||||||
if (kind == CXCompletionChunk_Placeholder)
|
|
||||||
out[i].parameters_.push_back(text);
|
out[i].parameters_.push_back(text);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CodeCompletionString::CK_ResultType:
|
||||||
case CXCompletionChunk_CurrentParameter:
|
if (Chunk.Text)
|
||||||
|
result_type = Chunk.Text;
|
||||||
|
continue;
|
||||||
|
case CodeCompletionString::CK_CurrentParameter:
|
||||||
// We have our own parsing logic for active parameter. This doesn't seem
|
// We have our own parsing logic for active parameter. This doesn't seem
|
||||||
// to be very reliable.
|
// to be very reliable.
|
||||||
continue;
|
continue;
|
||||||
|
case CodeCompletionString::CK_Optional: {
|
||||||
case CXCompletionChunk_Optional: {
|
|
||||||
CXCompletionString nested =
|
|
||||||
clang_getCompletionChunkCompletionString(completion_string, i);
|
|
||||||
// duplicate last element, the recursive call will complete it
|
// duplicate last element, the recursive call will complete it
|
||||||
out.push_back(out.back());
|
out.push_back(out.back());
|
||||||
BuildCompletionItemTexts(out, nested, include_snippets);
|
BuildCompletionItemTexts(out, *Chunk.Optional, include_snippets);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// clang-format off
|
||||||
|
case CodeCompletionString::CK_LeftParen: text = '('; break;
|
||||||
|
case CodeCompletionString::CK_RightParen: text = ')'; break;
|
||||||
|
case CodeCompletionString::CK_LeftBracket: text = '['; break;
|
||||||
|
case CodeCompletionString::CK_RightBracket: text = ']'; break;
|
||||||
|
case CodeCompletionString::CK_LeftBrace: text = '{'; break;
|
||||||
|
case CodeCompletionString::CK_RightBrace: text = '}'; break;
|
||||||
|
case CodeCompletionString::CK_LeftAngle: text = '<'; break;
|
||||||
|
case CodeCompletionString::CK_RightAngle: text = '>'; break;
|
||||||
|
case CodeCompletionString::CK_Comma: text = ", "; break;
|
||||||
|
case CodeCompletionString::CK_Colon: text = ':'; break;
|
||||||
|
case CodeCompletionString::CK_SemiColon: text = ';'; break;
|
||||||
|
case CodeCompletionString::CK_Equal: text = '='; break;
|
||||||
|
case CodeCompletionString::CK_HorizontalSpace: text = ' '; break;
|
||||||
|
case CodeCompletionString::CK_VerticalSpace: text = ' '; break;
|
||||||
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i = out_first; i < out.size(); ++i)
|
for (auto i = out_first; i < out.size(); ++i)
|
||||||
out[i].label += text;
|
out[i].label += text;
|
||||||
|
|
||||||
if (kind == CXCompletionChunk_Informative)
|
if (Kind == CodeCompletionString::CK_Informative)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (auto i = out_first; i < out.size(); ++i) {
|
for (auto i = out_first; i < out.size(); ++i) {
|
||||||
if (!include_snippets && !out[i].parameters_.empty())
|
if (!include_snippets && !out[i].parameters_.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (kind == CXCompletionChunk_Placeholder) {
|
if (Kind == CodeCompletionString::CK_Placeholder) {
|
||||||
out[i].insertText +=
|
out[i].insertText +=
|
||||||
"${" + 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;
|
||||||
@ -243,106 +229,71 @@ void BuildCompletionItemTexts(std::vector<lsCompletionItem>& out,
|
|||||||
|
|
||||||
// |do_insert|: if |!do_insert|, do not append strings to |insert| after
|
// |do_insert|: if |!do_insert|, do not append strings to |insert| after
|
||||||
// a placeholder.
|
// a placeholder.
|
||||||
void BuildDetailString(CXCompletionString completion_string,
|
void BuildDetailString(const CodeCompletionString &CCS, lsCompletionItem &item,
|
||||||
std::string& label,
|
bool &do_insert, std::vector<std::string> *parameters,
|
||||||
std::string& detail,
|
bool include_snippets, int &angle_stack) {
|
||||||
std::string& insert,
|
for (unsigned i = 0, num_chunks = CCS.size(); i < num_chunks; ++i) {
|
||||||
bool& do_insert,
|
const CodeCompletionString::Chunk &Chunk = CCS[i];
|
||||||
lsInsertTextFormat& format,
|
CodeCompletionString::ChunkKind Kind = Chunk.Kind;
|
||||||
std::vector<std::string>* parameters,
|
const char* text = nullptr;
|
||||||
bool include_snippets,
|
switch (Kind) {
|
||||||
int& angle_stack) {
|
case CodeCompletionString::CK_TypedText:
|
||||||
int num_chunks = clang_getNumCompletionChunks(completion_string);
|
item.label = Chunk.Text;
|
||||||
auto append = [&](const char* text) {
|
[[fallthrough]];
|
||||||
detail += text;
|
case CodeCompletionString::CK_Text:
|
||||||
if (do_insert && include_snippets)
|
item.detail += Chunk.Text;
|
||||||
insert += text;
|
if (do_insert)
|
||||||
};
|
item.insertText += Chunk.Text;
|
||||||
for (int i = 0; i < num_chunks; ++i) {
|
break;
|
||||||
CXCompletionChunkKind kind =
|
case CodeCompletionString::CK_Placeholder: {
|
||||||
clang_getCompletionChunkKind(completion_string, i);
|
parameters->push_back(Chunk.Text);
|
||||||
|
item.detail += Chunk.Text;
|
||||||
switch (kind) {
|
// Add parameter declarations as snippets if enabled
|
||||||
case CXCompletionChunk_Optional: {
|
if (include_snippets) {
|
||||||
CXCompletionString nested =
|
item.insertText += "${" + std::to_string(parameters->size()) + ":" + Chunk.Text + "}";
|
||||||
clang_getCompletionChunkCompletionString(completion_string, i);
|
item.insertTextFormat = lsInsertTextFormat::Snippet;
|
||||||
// Do not add text to insert string if we're in angle brackets.
|
} else
|
||||||
bool should_insert = do_insert && angle_stack == 0;
|
do_insert = false;
|
||||||
BuildDetailString(nested, label, detail, insert,
|
break;
|
||||||
should_insert, format, parameters,
|
}
|
||||||
include_snippets, angle_stack);
|
case CodeCompletionString::CK_Informative:
|
||||||
break;
|
item.detail += Chunk.Text;
|
||||||
}
|
break;
|
||||||
|
case CodeCompletionString::CK_Optional: {
|
||||||
case CXCompletionChunk_Placeholder: {
|
// Do not add text to insert string if we're in angle brackets.
|
||||||
std::string text =
|
bool should_insert = do_insert && angle_stack == 0;
|
||||||
ToString(clang_getCompletionChunkText(completion_string, i));
|
BuildDetailString(*Chunk.Optional, item, should_insert,
|
||||||
parameters->push_back(text);
|
parameters, include_snippets, angle_stack);
|
||||||
detail += text;
|
break;
|
||||||
// Add parameter declarations as snippets if enabled
|
}
|
||||||
if (include_snippets) {
|
case CodeCompletionString::CK_ResultType:
|
||||||
insert +=
|
item.detail = Chunk.Text + item.detail + " ";
|
||||||
"${" + std::to_string(parameters->size()) + ":" + text + "}";
|
break;
|
||||||
format = lsInsertTextFormat::Snippet;
|
case CodeCompletionString::CK_CurrentParameter:
|
||||||
} else
|
// We have our own parsing logic for active parameter. This doesn't seem
|
||||||
do_insert = false;
|
// to be very reliable.
|
||||||
break;
|
break;
|
||||||
}
|
// clang-format off
|
||||||
|
case CodeCompletionString::CK_LeftParen: text = "("; break;
|
||||||
case CXCompletionChunk_CurrentParameter:
|
case CodeCompletionString::CK_RightParen: text = ")"; break;
|
||||||
// We have our own parsing logic for active parameter. This doesn't seem
|
case CodeCompletionString::CK_LeftBracket: text = "["; break;
|
||||||
// to be very reliable.
|
case CodeCompletionString::CK_RightBracket: text = "]"; break;
|
||||||
break;
|
case CodeCompletionString::CK_LeftBrace: text = "{"; break;
|
||||||
|
case CodeCompletionString::CK_RightBrace: text = "}"; break;
|
||||||
case CXCompletionChunk_TypedText: {
|
case CodeCompletionString::CK_LeftAngle: text = "<"; angle_stack++; break;
|
||||||
std::string text =
|
case CodeCompletionString::CK_RightAngle: text = ">"; angle_stack--; break;
|
||||||
ToString(clang_getCompletionChunkText(completion_string, i));
|
case CodeCompletionString::CK_Comma: text = ", "; break;
|
||||||
label = text;
|
case CodeCompletionString::CK_Colon: text = ":"; break;
|
||||||
detail += text;
|
case CodeCompletionString::CK_SemiColon: text = ";"; break;
|
||||||
if (do_insert)
|
case CodeCompletionString::CK_Equal: text = "="; break;
|
||||||
insert += text;
|
case CodeCompletionString::CK_HorizontalSpace:
|
||||||
break;
|
case CodeCompletionString::CK_VerticalSpace: text = " "; break;
|
||||||
}
|
// clang-format on
|
||||||
|
}
|
||||||
case CXCompletionChunk_Text: {
|
if (text) {
|
||||||
std::string text =
|
item.detail += text;
|
||||||
ToString(clang_getCompletionChunkText(completion_string, i));
|
if (do_insert && include_snippets)
|
||||||
detail += text;
|
item.insertText += text;
|
||||||
if (do_insert)
|
|
||||||
insert += text;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CXCompletionChunk_Informative: {
|
|
||||||
detail += ToString(clang_getCompletionChunkText(completion_string, i));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CXCompletionChunk_ResultType: {
|
|
||||||
CXString text = clang_getCompletionChunkText(completion_string, i);
|
|
||||||
std::string new_detail = ToString(text) + detail + " ";
|
|
||||||
detail = new_detail;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
case CXCompletionChunk_LeftParen: append("("); break;
|
|
||||||
case CXCompletionChunk_RightParen: append(")"); break;
|
|
||||||
case CXCompletionChunk_LeftBracket: append("["); break;
|
|
||||||
case CXCompletionChunk_RightBracket: append("]"); break;
|
|
||||||
case CXCompletionChunk_LeftBrace: append("{"); break;
|
|
||||||
case CXCompletionChunk_RightBrace: append("}"); break;
|
|
||||||
case CXCompletionChunk_LeftAngle: append("<"); angle_stack++; break;
|
|
||||||
case CXCompletionChunk_RightAngle: append(">"); angle_stack--; break;
|
|
||||||
case CXCompletionChunk_Comma: append(", "); break;
|
|
||||||
case CXCompletionChunk_Colon: append(":"); break;
|
|
||||||
case CXCompletionChunk_SemiColon: append(";"); break;
|
|
||||||
case CXCompletionChunk_Equal: append("="); break;
|
|
||||||
// clang-format on
|
|
||||||
case CXCompletionChunk_HorizontalSpace:
|
|
||||||
case CXCompletionChunk_VerticalSpace:
|
|
||||||
append(" ");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -483,35 +434,24 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
|||||||
|
|
||||||
for (unsigned i = 0; i < cx_results->NumResults; ++i) {
|
for (unsigned i = 0; i < cx_results->NumResults; ++i) {
|
||||||
CXCompletionResult& result = cx_results->Results[i];
|
CXCompletionResult& result = cx_results->Results[i];
|
||||||
|
auto CCS = (CodeCompletionString *)result.CompletionString;
|
||||||
// TODO: Try to figure out how we can hide base method calls without
|
if (CCS->getAvailability() == CXAvailability_NotAvailable)
|
||||||
// also hiding method implementation assistance, ie,
|
|
||||||
//
|
|
||||||
// void Foo::* {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
|
|
||||||
if (clang_getCompletionAvailability(result.CompletionString) ==
|
|
||||||
CXAvailability_NotAvailable)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// TODO: fill in more data
|
lsCompletionItem ls_item;
|
||||||
lsCompletionItem ls_completion_item;
|
ls_item.kind = GetCompletionKind(result.CursorKind);
|
||||||
|
if (const char* brief = CCS->getBriefComment())
|
||||||
ls_completion_item.kind = GetCompletionKind(result.CursorKind);
|
ls_item.documentation = brief;
|
||||||
ls_completion_item.documentation =
|
|
||||||
ToString(clang_getCompletionBriefComment(result.CompletionString));
|
|
||||||
|
|
||||||
// label/detail/filterText/insertText/priority
|
// label/detail/filterText/insertText/priority
|
||||||
if (g_config->completion.detailedLabel) {
|
if (g_config->completion.detailedLabel) {
|
||||||
ls_completion_item.detail = ToString(
|
ls_item.detail = CCS->getParentContextName().str();
|
||||||
clang_getCompletionParent(result.CompletionString, nullptr));
|
|
||||||
|
|
||||||
auto first_idx = ls_result.size();
|
auto first_idx = ls_result.size();
|
||||||
ls_result.push_back(ls_completion_item);
|
ls_result.push_back(ls_item);
|
||||||
|
|
||||||
// label/filterText/insertText
|
// label/filterText/insertText
|
||||||
BuildCompletionItemTexts(ls_result, result.CompletionString,
|
BuildCompletionItemTexts(ls_result, *CCS,
|
||||||
g_config->client.snippetSupport);
|
g_config->client.snippetSupport);
|
||||||
|
|
||||||
for (auto i = first_idx; i < ls_result.size(); ++i) {
|
for (auto i = first_idx; i < ls_result.size(); ++i) {
|
||||||
@ -520,28 +460,21 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
|||||||
ls_result[i].insertText += "$0";
|
ls_result[i].insertText += "$0";
|
||||||
}
|
}
|
||||||
|
|
||||||
ls_result[i].priority_ =
|
ls_result[i].priority_ = GetCompletionPriority(
|
||||||
GetCompletionPriority(result.CompletionString, result.CursorKind,
|
*CCS, result.CursorKind, ls_result[i].filterText);
|
||||||
ls_result[i].filterText);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bool do_insert = true;
|
bool do_insert = true;
|
||||||
int angle_stack = 0;
|
int angle_stack = 0;
|
||||||
BuildDetailString(result.CompletionString, ls_completion_item.label,
|
BuildDetailString(*CCS, ls_item, do_insert,
|
||||||
ls_completion_item.detail,
|
&ls_item.parameters_,
|
||||||
ls_completion_item.insertText, do_insert,
|
|
||||||
ls_completion_item.insertTextFormat,
|
|
||||||
&ls_completion_item.parameters_,
|
|
||||||
g_config->client.snippetSupport, angle_stack);
|
g_config->client.snippetSupport, angle_stack);
|
||||||
if (g_config->client.snippetSupport &&
|
if (g_config->client.snippetSupport &&
|
||||||
ls_completion_item.insertTextFormat ==
|
ls_item.insertTextFormat == lsInsertTextFormat::Snippet)
|
||||||
lsInsertTextFormat::Snippet) {
|
ls_item.insertText += "$0";
|
||||||
ls_completion_item.insertText += "$0";
|
ls_item.priority_ =
|
||||||
}
|
GetCompletionPriority(*CCS, result.CursorKind, ls_item.label);
|
||||||
ls_completion_item.priority_ =
|
ls_result.push_back(ls_item);
|
||||||
GetCompletionPriority(result.CompletionString, result.CursorKind,
|
|
||||||
ls_completion_item.label);
|
|
||||||
ls_result.push_back(ls_completion_item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,10 +19,11 @@ enum class lsCompletionTriggerKind {
|
|||||||
// Completion was triggered by typing an identifier (24x7 code
|
// Completion was triggered by typing an identifier (24x7 code
|
||||||
// complete), manual invocation (e.g Ctrl+Space) or via API.
|
// complete), manual invocation (e.g Ctrl+Space) or via API.
|
||||||
Invoked = 1,
|
Invoked = 1,
|
||||||
|
|
||||||
// Completion was triggered by a trigger character specified by
|
// Completion was triggered by a trigger character specified by
|
||||||
// the `triggerCharacters` properties of the `CompletionRegistrationOptions`.
|
// the `triggerCharacters` properties of the `CompletionRegistrationOptions`.
|
||||||
TriggerCharacter = 2
|
TriggerCharacter = 2,
|
||||||
|
// Completion was re-triggered as the current completion list is incomplete.
|
||||||
|
TriggerForIncompleteCompletions = 3,
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_TYPE_PROXY(lsCompletionTriggerKind);
|
MAKE_REFLECT_TYPE_PROXY(lsCompletionTriggerKind);
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ MAKE_REFLECT_TYPE_PROXY(lsCompletionTriggerKind);
|
|||||||
// request is triggered.
|
// request is triggered.
|
||||||
struct lsCompletionContext {
|
struct lsCompletionContext {
|
||||||
// How the completion was triggered.
|
// How the completion was triggered.
|
||||||
lsCompletionTriggerKind triggerKind;
|
lsCompletionTriggerKind triggerKind = lsCompletionTriggerKind::Invoked;
|
||||||
|
|
||||||
// The trigger character (a single character) that has trigger code complete.
|
// The trigger character (a single character) that has trigger code complete.
|
||||||
// Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter`
|
// Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter`
|
||||||
@ -42,7 +43,7 @@ struct lsCompletionParams : lsTextDocumentPositionParams {
|
|||||||
// The completion context. This is only available it the client specifies to
|
// The completion context. This is only available it the client specifies to
|
||||||
// send this using
|
// send this using
|
||||||
// `ClientCapabilities.textDocument.completion.contextSupport === true`
|
// `ClientCapabilities.textDocument.completion.contextSupport === true`
|
||||||
std::optional<lsCompletionContext> context;
|
lsCompletionContext context;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsCompletionParams, textDocument, position, context);
|
MAKE_REFLECT_STRUCT(lsCompletionParams, textDocument, position, context);
|
||||||
|
|
||||||
@ -254,6 +255,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
|
|||||||
void Run(std::unique_ptr<InMessage> message) override {
|
void Run(std::unique_ptr<InMessage> message) override {
|
||||||
auto request = std::shared_ptr<In_TextDocumentComplete>(
|
auto request = std::shared_ptr<In_TextDocumentComplete>(
|
||||||
static_cast<In_TextDocumentComplete*>(message.release()));
|
static_cast<In_TextDocumentComplete*>(message.release()));
|
||||||
|
auto& params = request->params;
|
||||||
|
|
||||||
auto write_empty_result = [request]() {
|
auto write_empty_result = [request]() {
|
||||||
Out_TextDocumentComplete out;
|
Out_TextDocumentComplete out;
|
||||||
@ -261,7 +263,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
|
|||||||
pipeline::WriteStdout(kMethodType, out);
|
pipeline::WriteStdout(kMethodType, out);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string path = request->params.textDocument.uri.GetPath();
|
std::string path = params.textDocument.uri.GetPath();
|
||||||
WorkingFile* file = working_files->GetFileByFilename(path);
|
WorkingFile* file = working_files->GetFileByFilename(path);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
write_empty_result();
|
write_empty_result();
|
||||||
@ -271,21 +273,19 @@ struct Handler_TextDocumentCompletion : MessageHandler {
|
|||||||
// It shouldn't be possible, but sometimes vscode will send queries out
|
// It shouldn't be possible, but sometimes vscode will send queries out
|
||||||
// of order, ie, we get completion request before buffer content update.
|
// of order, ie, we get completion request before buffer content update.
|
||||||
std::string buffer_line;
|
std::string buffer_line;
|
||||||
if (request->params.position.line >= 0 &&
|
if (params.position.line >= 0 &&
|
||||||
request->params.position.line < file->buffer_lines.size()) {
|
params.position.line < file->buffer_lines.size())
|
||||||
buffer_line = file->buffer_lines[request->params.position.line];
|
buffer_line = file->buffer_lines[params.position.line];
|
||||||
}
|
|
||||||
|
|
||||||
// Check for - and : before completing -> or ::, since vscode does not
|
// Check for - and : before completing -> or ::, since vscode does not
|
||||||
// support multi-character trigger characters.
|
// support multi-character trigger characters.
|
||||||
if (request->params.context &&
|
if (params.context.triggerKind ==
|
||||||
request->params.context->triggerKind ==
|
|
||||||
lsCompletionTriggerKind::TriggerCharacter &&
|
lsCompletionTriggerKind::TriggerCharacter &&
|
||||||
request->params.context->triggerCharacter) {
|
params.context.triggerCharacter) {
|
||||||
bool did_fail_check = false;
|
bool did_fail_check = false;
|
||||||
|
|
||||||
std::string character = *request->params.context->triggerCharacter;
|
std::string character = *params.context.triggerCharacter;
|
||||||
int preceding_index = request->params.position.character - 2;
|
int preceding_index = params.position.character - 2;
|
||||||
|
|
||||||
// If the character is '"', '<' or '/', make sure that the line starts
|
// If the character is '"', '<' or '/', make sure that the line starts
|
||||||
// with '#'.
|
// with '#'.
|
||||||
@ -318,11 +318,11 @@ struct Handler_TextDocumentCompletion : MessageHandler {
|
|||||||
|
|
||||||
bool is_global_completion = false;
|
bool is_global_completion = false;
|
||||||
std::string existing_completion;
|
std::string existing_completion;
|
||||||
lsPosition end_pos = request->params.position;
|
lsPosition end_pos = params.position;
|
||||||
if (file) {
|
if (file) {
|
||||||
request->params.position = file->FindStableCompletionSource(
|
params.position = file->FindStableCompletionSource(
|
||||||
request->params.position, &is_global_completion,
|
request->params.position, &is_global_completion, &existing_completion,
|
||||||
&existing_completion, &end_pos);
|
&end_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseIncludeLineResult result = ParseIncludeLine(buffer_line);
|
ParseIncludeLineResult result = ParseIncludeLine(buffer_line);
|
||||||
@ -359,16 +359,16 @@ struct Handler_TextDocumentCompletion : MessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 = 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 = params.position.line;
|
||||||
item.textEdit->range.end.character = (int)buffer_line.size();
|
item.textEdit->range.end.character = (int)buffer_line.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline::WriteStdout(kMethodType, out);
|
pipeline::WriteStdout(kMethodType, out);
|
||||||
} else {
|
} else {
|
||||||
ClangCompleteManager::OnComplete callback = std::bind(
|
ClangCompleteManager::OnComplete callback = std::bind(
|
||||||
[this, request, is_global_completion, existing_completion,
|
[this, request, params, is_global_completion, existing_completion,
|
||||||
has_open_paren](const std::vector<lsCompletionItem>& results,
|
has_open_paren](const std::vector<lsCompletionItem>& results,
|
||||||
bool is_cached_result) {
|
bool is_cached_result) {
|
||||||
Out_TextDocumentComplete out;
|
Out_TextDocumentComplete out;
|
||||||
@ -381,7 +381,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
|
|||||||
|
|
||||||
// Cache completion results.
|
// Cache completion results.
|
||||||
if (!is_cached_result) {
|
if (!is_cached_result) {
|
||||||
std::string path = request->params.textDocument.uri.GetPath();
|
std::string path = params.textDocument.uri.GetPath();
|
||||||
if (is_global_completion) {
|
if (is_global_completion) {
|
||||||
global_code_complete_cache->WithLock([&]() {
|
global_code_complete_cache->WithLock([&]() {
|
||||||
global_code_complete_cache->cached_path_ = path;
|
global_code_complete_cache->cached_path_ = path;
|
||||||
@ -391,7 +391,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
|
|||||||
non_global_code_complete_cache->WithLock([&]() {
|
non_global_code_complete_cache->WithLock([&]() {
|
||||||
non_global_code_complete_cache->cached_path_ = path;
|
non_global_code_complete_cache->cached_path_ = path;
|
||||||
non_global_code_complete_cache->cached_completion_position_ =
|
non_global_code_complete_cache->cached_completion_position_ =
|
||||||
request->params.position;
|
params.position;
|
||||||
non_global_code_complete_cache->cached_results_ = results;
|
non_global_code_complete_cache->cached_results_ = results;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -421,16 +421,14 @@ struct Handler_TextDocumentCompletion : MessageHandler {
|
|||||||
callback(global_code_complete_cache->cached_results_,
|
callback(global_code_complete_cache->cached_results_,
|
||||||
true /*is_cached_result*/);
|
true /*is_cached_result*/);
|
||||||
});
|
});
|
||||||
clang_complete->CodeComplete(request->id, request->params,
|
clang_complete->CodeComplete(request->id, params, freshen_global);
|
||||||
freshen_global);
|
} else if (non_global_code_complete_cache->IsCacheValid(params)) {
|
||||||
} else if (non_global_code_complete_cache->IsCacheValid(
|
|
||||||
request->params)) {
|
|
||||||
non_global_code_complete_cache->WithLock([&]() {
|
non_global_code_complete_cache->WithLock([&]() {
|
||||||
callback(non_global_code_complete_cache->cached_results_,
|
callback(non_global_code_complete_cache->cached_results_,
|
||||||
true /*is_cached_result*/);
|
true /*is_cached_result*/);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
clang_complete->CodeComplete(request->id, request->params, callback);
|
clang_complete->CodeComplete(request->id, params, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user