mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-30 11:27:07 +00:00
Remove variant and clean up
This commit is contained in:
parent
4d519dcbcb
commit
fa9df5bcef
@ -656,18 +656,18 @@ ClangCompleteManager::ClangCompleteManager(Project* project,
|
|||||||
on_dropped_(on_dropped),
|
on_dropped_(on_dropped),
|
||||||
preloaded_sessions_(kMaxPreloadedSessions),
|
preloaded_sessions_(kMaxPreloadedSessions),
|
||||||
completion_sessions_(kMaxCompletionSessions) {
|
completion_sessions_(kMaxCompletionSessions) {
|
||||||
new std::thread([&]() {
|
std::thread([&]() {
|
||||||
SetThreadName("comp-query");
|
SetThreadName("comp-query");
|
||||||
CompletionQueryMain(this);
|
CompletionQueryMain(this);
|
||||||
});
|
}).detach();
|
||||||
new std::thread([&]() {
|
std::thread([&]() {
|
||||||
SetThreadName("comp-preload");
|
SetThreadName("comp-preload");
|
||||||
CompletionPreloadMain(this);
|
CompletionPreloadMain(this);
|
||||||
});
|
}).detach();
|
||||||
new std::thread([&]() {
|
std::thread([&]() {
|
||||||
SetThreadName("diag-query");
|
SetThreadName("diag-query");
|
||||||
DiagnosticQueryMain(this);
|
DiagnosticQueryMain(this);
|
||||||
});
|
}).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangCompleteManager::CodeComplete(
|
void ClangCompleteManager::CodeComplete(
|
||||||
@ -680,7 +680,6 @@ void ClangCompleteManager::CodeComplete(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ClangCompleteManager::DiagnosticsUpdate(
|
void ClangCompleteManager::DiagnosticsUpdate(
|
||||||
const lsRequestId& id,
|
|
||||||
const lsTextDocumentIdentifier& document) {
|
const lsTextDocumentIdentifier& document) {
|
||||||
bool has = false;
|
bool has = false;
|
||||||
diagnostic_request_.Iterate([&](const DiagnosticRequest& request) {
|
diagnostic_request_.Iterate([&](const DiagnosticRequest& request) {
|
||||||
|
@ -91,8 +91,7 @@ struct ClangCompleteManager {
|
|||||||
const lsTextDocumentPositionParams& completion_location,
|
const lsTextDocumentPositionParams& completion_location,
|
||||||
const OnComplete& on_complete);
|
const OnComplete& on_complete);
|
||||||
// Request a diagnostics update.
|
// Request a diagnostics update.
|
||||||
void DiagnosticsUpdate(const lsRequestId& request_id,
|
void DiagnosticsUpdate(const lsTextDocumentIdentifier& document);
|
||||||
const lsTextDocumentIdentifier& document);
|
|
||||||
|
|
||||||
// Notify the completion manager that |filename| has been viewed and we
|
// Notify the completion manager that |filename| has been viewed and we
|
||||||
// should begin preloading completion data.
|
// should begin preloading completion data.
|
||||||
|
@ -172,7 +172,7 @@ void RunQueryDbThread(const std::string& bin_name,
|
|||||||
args);
|
args);
|
||||||
},
|
},
|
||||||
[](lsRequestId id) {
|
[](lsRequestId id) {
|
||||||
if (!std::holds_alternative<std::monostate>(id)) {
|
if (id.Valid()) {
|
||||||
Out_Error out;
|
Out_Error out;
|
||||||
out.id = id;
|
out.id = id;
|
||||||
out.error.code = lsErrorCodes::InternalError;
|
out.error.code = lsErrorCodes::InternalError;
|
||||||
@ -243,7 +243,7 @@ void RunQueryDbThread(const std::string& bin_name,
|
|||||||
//
|
//
|
||||||
// |ipc| is connected to a server.
|
// |ipc| is connected to a server.
|
||||||
void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
|
void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
|
||||||
new std::thread([request_times]() {
|
std::thread([request_times]() {
|
||||||
SetThreadName("stdin");
|
SetThreadName("stdin");
|
||||||
auto* queue = QueueManager::instance();
|
auto* queue = QueueManager::instance();
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -257,7 +257,7 @@ void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
|
|||||||
// Emit an error ResponseMessage if |id| is available.
|
// Emit an error ResponseMessage if |id| is available.
|
||||||
if (message) {
|
if (message) {
|
||||||
lsRequestId id = message->GetRequestId();
|
lsRequestId id = message->GetRequestId();
|
||||||
if (!std::holds_alternative<std::monostate>(id)) {
|
if (id.Valid()) {
|
||||||
Out_Error out;
|
Out_Error out;
|
||||||
out.id = id;
|
out.id = id;
|
||||||
out.error.code = lsErrorCodes::InvalidParams;
|
out.error.code = lsErrorCodes::InvalidParams;
|
||||||
@ -279,12 +279,12 @@ void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
|
|||||||
if (method_type == kMethodType_Exit)
|
if (method_type == kMethodType_Exit)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
}).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
|
void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
|
||||||
MultiQueueWaiter* waiter) {
|
MultiQueueWaiter* waiter) {
|
||||||
new std::thread([=]() {
|
std::thread([=]() {
|
||||||
SetThreadName("stdout");
|
SetThreadName("stdout");
|
||||||
auto* queue = QueueManager::instance();
|
auto* queue = QueueManager::instance();
|
||||||
|
|
||||||
@ -305,7 +305,7 @@ void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanguageServerMain(const std::string& bin_name,
|
void LanguageServerMain(const std::string& bin_name,
|
||||||
|
@ -393,8 +393,7 @@ void ParseFile(DiagnosticsEngine* diag_engine,
|
|||||||
file_contents, &perf);
|
file_contents, &perf);
|
||||||
|
|
||||||
if (indexes.empty()) {
|
if (indexes.empty()) {
|
||||||
if (g_config->index.enabled &&
|
if (g_config->index.enabled && request.id.Valid()) {
|
||||||
!std::holds_alternative<std::monostate>(request.id)) {
|
|
||||||
Out_Error out;
|
Out_Error out;
|
||||||
out.id = request.id;
|
out.id = request.id;
|
||||||
out.error.code = lsErrorCodes::InternalError;
|
out.error.code = lsErrorCodes::InternalError;
|
||||||
|
@ -29,21 +29,16 @@ std::string ElideLongPath(const std::string& path) {
|
|||||||
|
|
||||||
size_t TrimCommonPathPrefix(const std::string& result,
|
size_t TrimCommonPathPrefix(const std::string& result,
|
||||||
const std::string& trimmer) {
|
const std::string& trimmer) {
|
||||||
size_t i = 0;
|
#ifdef _WIN32
|
||||||
while (i < result.size() && i < trimmer.size()) {
|
std::string s = result, t = trimmer;
|
||||||
char a = result[i];
|
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
|
||||||
char b = trimmer[i];
|
std::transform(t.begin(), t.end(), t.begin(), ::tolower);
|
||||||
#if defined(_WIN32)
|
if (s.compare(0, t.size(), t) == 0)
|
||||||
a = (char)tolower(a);
|
return t.size();
|
||||||
b = (char)tolower(b);
|
#else
|
||||||
|
if (result.compare(0, trimmer.size(), trimmer) == 0)
|
||||||
|
return trimmer.size();
|
||||||
#endif
|
#endif
|
||||||
if (a != b)
|
|
||||||
break;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == trimmer.size())
|
|
||||||
return i;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,21 +46,14 @@ size_t TrimCommonPathPrefix(const std::string& result,
|
|||||||
bool TrimPath(Project* project,
|
bool TrimPath(Project* project,
|
||||||
const std::string& project_root,
|
const std::string& project_root,
|
||||||
std::string* insert_path) {
|
std::string* insert_path) {
|
||||||
size_t start = 0;
|
size_t start = TrimCommonPathPrefix(*insert_path, project_root);
|
||||||
bool angle = false;
|
bool angle = false;
|
||||||
|
|
||||||
size_t len = TrimCommonPathPrefix(*insert_path, project_root);
|
for (auto& include_dir : project->quote_include_directories)
|
||||||
if (len > start)
|
start = std::max(start, TrimCommonPathPrefix(*insert_path, include_dir));
|
||||||
start = len;
|
|
||||||
|
|
||||||
for (auto& include_dir : project->quote_include_directories) {
|
|
||||||
len = TrimCommonPathPrefix(*insert_path, include_dir);
|
|
||||||
if (len > start)
|
|
||||||
start = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& include_dir : project->angle_include_directories) {
|
for (auto& include_dir : project->angle_include_directories) {
|
||||||
len = TrimCommonPathPrefix(*insert_path, include_dir);
|
auto len = TrimCommonPathPrefix(*insert_path, include_dir);
|
||||||
if (len > start) {
|
if (len > start) {
|
||||||
start = len;
|
start = len;
|
||||||
angle = true;
|
angle = true;
|
||||||
@ -115,8 +103,8 @@ void IncludeComplete::Rescan() {
|
|||||||
g_config->completion.includeBlacklist);
|
g_config->completion.includeBlacklist);
|
||||||
|
|
||||||
is_scanning = true;
|
is_scanning = true;
|
||||||
new std::thread([this]() {
|
std::thread([this]() {
|
||||||
SetThreadName("scan_includes");
|
SetThreadName("scan_includes");
|
||||||
Timer timer;
|
Timer timer;
|
||||||
|
|
||||||
InsertStlIncludes();
|
InsertStlIncludes();
|
||||||
@ -129,7 +117,7 @@ void IncludeComplete::Rescan() {
|
|||||||
|
|
||||||
timer.ResetAndPrint("[perf] Scanning for includes");
|
timer.ResetAndPrint("[perf] Scanning for includes");
|
||||||
is_scanning = false;
|
is_scanning = false;
|
||||||
});
|
}).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IncludeComplete::InsertCompletionItem(const std::string& absolute_path,
|
void IncludeComplete::InsertCompletionItem(const std::string& absolute_path,
|
||||||
|
13
src/lsp.cc
13
src/lsp.cc
@ -275,6 +275,19 @@ bool lsTextEdit::operator==(const lsTextEdit& that) {
|
|||||||
return range == that.range && newText == that.newText;
|
return range == that.range && newText == that.newText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Reflect(Writer& visitor, lsMarkedString& value) {
|
||||||
|
// If there is a language, emit a `{language:string, value:string}` object. If
|
||||||
|
// not, emit a string.
|
||||||
|
if (value.language) {
|
||||||
|
REFLECT_MEMBER_START();
|
||||||
|
REFLECT_MEMBER(language);
|
||||||
|
REFLECT_MEMBER(value);
|
||||||
|
REFLECT_MEMBER_END();
|
||||||
|
} else {
|
||||||
|
Reflect(visitor, value.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string Out_ShowLogMessage::method() {
|
std::string Out_ShowLogMessage::method() {
|
||||||
if (display_type == DisplayType::Log)
|
if (display_type == DisplayType::Log)
|
||||||
return "window/logMessage";
|
return "window/logMessage";
|
||||||
|
11
src/lsp.h
11
src/lsp.h
@ -239,7 +239,7 @@ MAKE_REFLECT_STRUCT(lsTextDocumentIdentifier, uri);
|
|||||||
struct lsVersionedTextDocumentIdentifier {
|
struct lsVersionedTextDocumentIdentifier {
|
||||||
lsDocumentUri uri;
|
lsDocumentUri uri;
|
||||||
// The version number of this document. number | null
|
// The version number of this document. number | null
|
||||||
std::variant<std::monostate, int> version;
|
std::optional<int> version;
|
||||||
|
|
||||||
lsTextDocumentIdentifier AsTextDocumentIdentifier() const;
|
lsTextDocumentIdentifier AsTextDocumentIdentifier() const;
|
||||||
};
|
};
|
||||||
@ -325,12 +325,11 @@ MAKE_REFLECT_STRUCT(lsFormattingOptions, tabSize, insertSpaces);
|
|||||||
//
|
//
|
||||||
// Note that markdown strings will be sanitized - that means html will be
|
// Note that markdown strings will be sanitized - that means html will be
|
||||||
// escaped.
|
// escaped.
|
||||||
struct lsMarkedString1 {
|
struct lsMarkedString {
|
||||||
std::string_view language;
|
std::optional<std::string> language;
|
||||||
std::string_view value;
|
std::string value;
|
||||||
};
|
};
|
||||||
using lsMarkedString = std::variant<std::string_view, lsMarkedString1>;
|
void Reflect(Writer& visitor, lsMarkedString& value);
|
||||||
MAKE_REFLECT_STRUCT(lsMarkedString1, language, value);
|
|
||||||
|
|
||||||
struct lsTextDocumentContentChangeEvent {
|
struct lsTextDocumentContentChangeEvent {
|
||||||
// The range of the document that changed.
|
// The range of the document that changed.
|
||||||
|
@ -87,7 +87,7 @@ struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
|
|||||||
|
|
||||||
Timer time;
|
Timer time;
|
||||||
// Send index requests for every file.
|
// Send index requests for every file.
|
||||||
project->Index(QueueManager::instance(), working_files, std::monostate());
|
project->Index(QueueManager::instance(), working_files, lsRequestId());
|
||||||
time.ResetAndPrint("[perf] Dispatched $ccls/freshenIndex index requests");
|
time.ResetAndPrint("[perf] Dispatched $ccls/freshenIndex index requests");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -518,12 +518,12 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
|
|||||||
}
|
}
|
||||||
LOG_S(INFO) << "Starting " << g_config->index.threads << " indexers";
|
LOG_S(INFO) << "Starting " << g_config->index.threads << " indexers";
|
||||||
for (int i = 0; i < g_config->index.threads; i++) {
|
for (int i = 0; i < g_config->index.threads; i++) {
|
||||||
new std::thread([=]() {
|
std::thread([=]() {
|
||||||
SetThreadName("indexer" + std::to_string(i));
|
SetThreadName("indexer" + std::to_string(i));
|
||||||
Indexer_Main(diag_engine, file_consumer_shared, timestamp_manager,
|
Indexer_Main(diag_engine, file_consumer_shared, timestamp_manager,
|
||||||
import_manager, import_pipeline_status, project,
|
import_manager, import_pipeline_status, project,
|
||||||
working_files, waiter);
|
working_files, waiter);
|
||||||
});
|
}).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start scanning include directories before dispatching project
|
// Start scanning include directories before dispatching project
|
||||||
|
@ -11,8 +11,8 @@ MAKE_REFLECT_STRUCT(In_Shutdown, id);
|
|||||||
REGISTER_IN_MESSAGE(In_Shutdown);
|
REGISTER_IN_MESSAGE(In_Shutdown);
|
||||||
|
|
||||||
struct Out_Shutdown : public lsOutMessage<Out_Shutdown> {
|
struct Out_Shutdown : public lsOutMessage<Out_Shutdown> {
|
||||||
lsRequestId id; // defaults to std::monostate (null)
|
lsRequestId id;
|
||||||
std::monostate result; // null
|
JsonNull result;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_Shutdown, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_Shutdown, jsonrpc, id, result);
|
||||||
|
|
||||||
|
@ -39,7 +39,6 @@ struct Handler_TextDocumentDidChange
|
|||||||
}
|
}
|
||||||
clang_complete->NotifyEdit(path);
|
clang_complete->NotifyEdit(path);
|
||||||
clang_complete->DiagnosticsUpdate(
|
clang_complete->DiagnosticsUpdate(
|
||||||
std::monostate(),
|
|
||||||
request->params.textDocument.AsTextDocumentIdentifier());
|
request->params.textDocument.AsTextDocumentIdentifier());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -5,41 +5,40 @@
|
|||||||
namespace {
|
namespace {
|
||||||
MethodType kMethodType = "textDocument/hover";
|
MethodType kMethodType = "textDocument/hover";
|
||||||
|
|
||||||
std::pair<std::string_view, std::string_view> GetCommentsAndHover(
|
// Find the comments for |sym|, if any.
|
||||||
QueryDatabase* db,
|
std::optional<lsMarkedString> GetComments(QueryDatabase* db, SymbolRef sym) {
|
||||||
SymbolRef sym) {
|
std::optional<lsMarkedString> ret;
|
||||||
switch (sym.kind) {
|
WithEntity(db, sym, [&](const auto& entity) {
|
||||||
case SymbolKind::Type: {
|
if (const auto* def = entity.AnyDef())
|
||||||
if (const auto* def = db->GetType(sym).AnyDef()) {
|
if (!def->comments.empty()) {
|
||||||
return {def->comments, !def->hover.empty()
|
lsMarkedString m;
|
||||||
? std::string_view(def->hover)
|
m.value = def->comments;
|
||||||
: std::string_view(def->detailed_name)};
|
ret = m;
|
||||||
}
|
}
|
||||||
break;
|
});
|
||||||
}
|
return ret;
|
||||||
case SymbolKind::Func: {
|
}
|
||||||
if (const auto* def = db->GetFunc(sym).AnyDef()) {
|
|
||||||
return {def->comments, !def->hover.empty()
|
// Returns the hover or detailed name for `sym`, if any.
|
||||||
? std::string_view(def->hover)
|
std::optional<lsMarkedString> GetHoverOrName(QueryDatabase* db,
|
||||||
: std::string_view(def->detailed_name)};
|
const std::string& language,
|
||||||
|
SymbolRef sym) {
|
||||||
|
|
||||||
|
std::optional<lsMarkedString> ret;
|
||||||
|
WithEntity(db, sym, [&](const auto& entity) {
|
||||||
|
if (const auto* def = entity.AnyDef()) {
|
||||||
|
lsMarkedString m;
|
||||||
|
m.language = language;
|
||||||
|
if (!def->hover.empty()) {
|
||||||
|
m.value = def->hover;
|
||||||
|
ret = m;
|
||||||
|
} else if (!def->detailed_name.empty()) {
|
||||||
|
m.value = def->detailed_name;
|
||||||
|
ret = m;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case SymbolKind::Var: {
|
});
|
||||||
if (const auto* def = db->GetVar(sym).AnyDef()) {
|
return ret;
|
||||||
return {def->comments, !def->hover.empty()
|
|
||||||
? std::string_view(def->hover)
|
|
||||||
: std::string_view(def->detailed_name)};
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SymbolKind::File:
|
|
||||||
case SymbolKind::Invalid: {
|
|
||||||
assert(false && "unexpected");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {"", ""};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct In_TextDocumentHover : public RequestInMessage {
|
struct In_TextDocumentHover : public RequestInMessage {
|
||||||
@ -66,7 +65,7 @@ void Reflect(Writer& visitor, Out_TextDocumentHover& value) {
|
|||||||
if (value.result)
|
if (value.result)
|
||||||
REFLECT_MEMBER(result);
|
REFLECT_MEMBER(result);
|
||||||
else {
|
else {
|
||||||
// Empty std::optional<> is elided by the default serializer, we need to write
|
// Empty optional<> is elided by the default serializer, we need to write
|
||||||
// |null| to be compliant with the LSP.
|
// |null| to be compliant with the LSP.
|
||||||
visitor.Key("result");
|
visitor.Key("result");
|
||||||
visitor.Null();
|
visitor.Null();
|
||||||
@ -77,11 +76,11 @@ void Reflect(Writer& visitor, Out_TextDocumentHover& value) {
|
|||||||
struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
|
struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
|
||||||
MethodType GetMethodType() const override { return kMethodType; }
|
MethodType GetMethodType() const override { return kMethodType; }
|
||||||
void Run(In_TextDocumentHover* request) override {
|
void Run(In_TextDocumentHover* request) override {
|
||||||
|
auto& params = request->params;
|
||||||
QueryFile* file;
|
QueryFile* file;
|
||||||
if (!FindFileOrFail(db, project, request->id,
|
if (!FindFileOrFail(db, project, request->id,
|
||||||
request->params.textDocument.uri.GetPath(), &file)) {
|
params.textDocument.uri.GetPath(), &file))
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
WorkingFile* working_file =
|
WorkingFile* working_file =
|
||||||
working_files->GetFileByFilename(file->def->path);
|
working_files->GetFileByFilename(file->def->path);
|
||||||
@ -90,25 +89,23 @@ struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
|
|||||||
out.id = request->id;
|
out.id = request->id;
|
||||||
|
|
||||||
for (SymbolRef sym :
|
for (SymbolRef sym :
|
||||||
FindSymbolsAtLocation(working_file, file, request->params.position)) {
|
FindSymbolsAtLocation(working_file, file, params.position)) {
|
||||||
// Found symbol. Return hover.
|
// Found symbol. Return hover.
|
||||||
std::optional<lsRange> ls_range = GetLsRange(
|
std::optional<lsRange> ls_range = GetLsRange(
|
||||||
working_files->GetFileByFilename(file->def->path), sym.range);
|
working_files->GetFileByFilename(file->def->path), sym.range);
|
||||||
if (!ls_range)
|
if (!ls_range)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::pair<std::string_view, std::string_view> comments_hover =
|
std::optional<lsMarkedString> comments = GetComments(db, sym);
|
||||||
GetCommentsAndHover(db, sym);
|
std::optional<lsMarkedString> hover =
|
||||||
if (comments_hover.first.size() || comments_hover.second.size()) {
|
GetHoverOrName(db, file->def->language, sym);
|
||||||
|
if (comments || hover) {
|
||||||
out.result = Out_TextDocumentHover::Result();
|
out.result = Out_TextDocumentHover::Result();
|
||||||
if (comments_hover.first.size()) {
|
|
||||||
out.result->contents.emplace_back(comments_hover.first);
|
|
||||||
}
|
|
||||||
if (comments_hover.second.size()) {
|
|
||||||
out.result->contents.emplace_back(lsMarkedString1{
|
|
||||||
std::string_view(file->def->language), comments_hover.second});
|
|
||||||
}
|
|
||||||
out.result->range = *ls_range;
|
out.result->range = *ls_range;
|
||||||
|
if (comments)
|
||||||
|
out.result->contents.push_back(*comments);
|
||||||
|
if (hover)
|
||||||
|
out.result->contents.push_back(*hover);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ struct Handler_WorkspaceDidChangeConfiguration
|
|||||||
std::to_string(project->entries.size()) + " files)");
|
std::to_string(project->entries.size()) + " files)");
|
||||||
|
|
||||||
time.Reset();
|
time.Reset();
|
||||||
project->Index(QueueManager::instance(), working_files, std::monostate());
|
project->Index(QueueManager::instance(), working_files, lsRequestId());
|
||||||
time.ResetAndPrint(
|
time.ResetAndPrint(
|
||||||
"[perf] Dispatched workspace/didChangeConfiguration index requests");
|
"[perf] Dispatched workspace/didChangeConfiguration index requests");
|
||||||
|
|
||||||
|
@ -2,6 +2,40 @@
|
|||||||
|
|
||||||
MethodType kMethodType_Unknown = "$unknown";
|
MethodType kMethodType_Unknown = "$unknown";
|
||||||
MethodType kMethodType_Exit = "exit";
|
MethodType kMethodType_Exit = "exit";
|
||||||
MethodType kMethodType_TextDocumentPublishDiagnostics = "textDocument/publishDiagnostics";
|
MethodType kMethodType_TextDocumentPublishDiagnostics =
|
||||||
MethodType kMethodType_CclsPublishInactiveRegions = "$ccls/publishInactiveRegions";
|
"textDocument/publishDiagnostics";
|
||||||
MethodType kMethodType_CclsPublishSemanticHighlighting = "$ccls/publishSemanticHighlighting";
|
MethodType kMethodType_CclsPublishInactiveRegions =
|
||||||
|
"$ccls/publishInactiveRegions";
|
||||||
|
MethodType kMethodType_CclsPublishSemanticHighlighting =
|
||||||
|
"$ccls/publishSemanticHighlighting";
|
||||||
|
|
||||||
|
void Reflect(Reader& visitor, lsRequestId& value) {
|
||||||
|
if (visitor.IsInt64()) {
|
||||||
|
value.type = lsRequestId::kInt;
|
||||||
|
value.value = visitor.GetInt64();
|
||||||
|
} else if (visitor.IsInt()) {
|
||||||
|
value.type = lsRequestId::kInt;
|
||||||
|
value.value = visitor.GetInt();
|
||||||
|
} else if (visitor.IsString()) {
|
||||||
|
value.type = lsRequestId::kString;
|
||||||
|
value.value = atoll(visitor.GetString().c_str());
|
||||||
|
} else {
|
||||||
|
value.type = lsRequestId::kNone;
|
||||||
|
value.value = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reflect(Writer& visitor, lsRequestId& value) {
|
||||||
|
switch (value.type) {
|
||||||
|
case lsRequestId::kNone:
|
||||||
|
visitor.Null();
|
||||||
|
break;
|
||||||
|
case lsRequestId::kInt:
|
||||||
|
visitor.Int(value.value);
|
||||||
|
break;
|
||||||
|
case lsRequestId::kString:
|
||||||
|
auto s = std::to_string(value.value);
|
||||||
|
visitor.String(s.c_str(), s.length());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
15
src/method.h
15
src/method.h
@ -12,7 +12,18 @@ extern MethodType kMethodType_TextDocumentPublishDiagnostics;
|
|||||||
extern MethodType kMethodType_CclsPublishInactiveRegions;
|
extern MethodType kMethodType_CclsPublishInactiveRegions;
|
||||||
extern MethodType kMethodType_CclsPublishSemanticHighlighting;
|
extern MethodType kMethodType_CclsPublishSemanticHighlighting;
|
||||||
|
|
||||||
using lsRequestId = std::variant<std::monostate, int64_t, std::string>;
|
struct lsRequestId {
|
||||||
|
// The client can send the request id as an int or a string. We should output
|
||||||
|
// the same format we received.
|
||||||
|
enum Type { kNone, kInt, kString };
|
||||||
|
Type type = kNone;
|
||||||
|
|
||||||
|
int value = -1;
|
||||||
|
|
||||||
|
bool Valid() const { return type != kNone; }
|
||||||
|
};
|
||||||
|
void Reflect(Reader& visitor, lsRequestId& value);
|
||||||
|
void Reflect(Writer& visitor, lsRequestId& value);
|
||||||
|
|
||||||
struct InMessage {
|
struct InMessage {
|
||||||
virtual ~InMessage() = default;
|
virtual ~InMessage() = default;
|
||||||
@ -32,6 +43,6 @@ struct RequestInMessage : public InMessage {
|
|||||||
// NotificationInMessage does not have |id|.
|
// NotificationInMessage does not have |id|.
|
||||||
struct NotificationInMessage : public InMessage {
|
struct NotificationInMessage : public InMessage {
|
||||||
lsRequestId GetRequestId() const override {
|
lsRequestId GetRequestId() const override {
|
||||||
return std::monostate();
|
return lsRequestId();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <variant>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class QueueManager;
|
class QueueManager;
|
||||||
|
@ -140,6 +140,15 @@ void Reflect(Writer& visitor, NtString& value) {
|
|||||||
visitor.String(s ? s : "");
|
visitor.String(s ? s : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Reflect(Reader& visitor, JsonNull& value) {
|
||||||
|
assert(visitor.Format() == SerializeFormat::Json);
|
||||||
|
visitor.GetNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reflect(Writer& visitor, JsonNull& value) {
|
||||||
|
visitor.Null();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Move this to indexer.cc
|
// TODO: Move this to indexer.cc
|
||||||
void Reflect(Reader& visitor, IndexInclude& value) {
|
void Reflect(Reader& visitor, IndexInclude& value) {
|
||||||
REFLECT_MEMBER_START();
|
REFLECT_MEMBER_START();
|
||||||
@ -299,15 +308,6 @@ void Reflect(TVisitor& visitor, IndexFile& value) {
|
|||||||
REFLECT_MEMBER_END();
|
REFLECT_MEMBER_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reflect(Reader& visitor, std::monostate&) {
|
|
||||||
assert(visitor.Format() == SerializeFormat::Json);
|
|
||||||
visitor.GetNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reflect(Writer& visitor, std::monostate&) {
|
|
||||||
visitor.Null();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reflect(Reader& visitor, SerializeFormat& value) {
|
void Reflect(Reader& visitor, SerializeFormat& value) {
|
||||||
std::string fmt = visitor.GetString();
|
std::string fmt = visitor.GetString();
|
||||||
value = fmt[0] == 'b' ? SerializeFormat::Binary : SerializeFormat::Json;
|
value = fmt[0] == 'b' ? SerializeFormat::Binary : SerializeFormat::Json;
|
||||||
|
@ -13,11 +13,12 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <variant>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
enum class SerializeFormat { Binary, Json };
|
enum class SerializeFormat { Binary, Json };
|
||||||
|
|
||||||
|
struct JsonNull {};
|
||||||
|
|
||||||
class Reader {
|
class Reader {
|
||||||
public:
|
public:
|
||||||
virtual ~Reader() {}
|
virtual ~Reader() {}
|
||||||
@ -168,20 +169,18 @@ void Reflect(Writer& visitor, std::string_view& view);
|
|||||||
void Reflect(Reader& visitor, NtString& value);
|
void Reflect(Reader& visitor, NtString& value);
|
||||||
void Reflect(Writer& visitor, NtString& value);
|
void Reflect(Writer& visitor, NtString& value);
|
||||||
|
|
||||||
// std::monostate is used to represent JSON null
|
void Reflect(Reader& visitor, JsonNull& value);
|
||||||
void Reflect(Reader& visitor, std::monostate&);
|
void Reflect(Writer& visitor, JsonNull& value);
|
||||||
void Reflect(Writer& visitor, std::monostate&);
|
|
||||||
|
|
||||||
void Reflect(Reader& visitor, SerializeFormat& value);
|
void Reflect(Reader& visitor, SerializeFormat& value);
|
||||||
void Reflect(Writer& visitor, SerializeFormat& value);
|
void Reflect(Writer& visitor, SerializeFormat& value);
|
||||||
|
|
||||||
//// Type constructors
|
//// Type constructors
|
||||||
|
|
||||||
// ReflectMember std::optional<T> is used to represent TypeScript std::optional properties
|
// ReflectMember std::optional<T> is used to represent TypeScript optional properties
|
||||||
// (in `key: value` context).
|
// (in `key: value` context).
|
||||||
// Reflect std::optional<T> is used for a different purpose, whether an object is
|
// Reflect std::optional<T> is used for a different purpose, whether an object is
|
||||||
// nullable (possibly in `value` context). For the nullable semantics,
|
// nullable (possibly in `value` context).
|
||||||
// std::variant<std::monostate, T> is recommended.
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Reflect(Reader& visitor, std::optional<T>& value) {
|
void Reflect(Reader& visitor, std::optional<T>& value) {
|
||||||
if (visitor.IsNull()) {
|
if (visitor.IsNull()) {
|
||||||
@ -243,57 +242,6 @@ void ReflectMember(Writer& visitor, const char* name, Maybe<T>& value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper struct to reflect std::variant
|
|
||||||
template <size_t N, typename... Ts>
|
|
||||||
struct ReflectVariant {
|
|
||||||
// If T appears in Ts..., we should set the value of std::variant<Ts...> to
|
|
||||||
// what we get from Reader.
|
|
||||||
template <typename T>
|
|
||||||
void ReflectTag(Reader& visitor, std::variant<Ts...>& value) {
|
|
||||||
if constexpr (std::disjunction_v<std::is_same<T, Ts>...>) {
|
|
||||||
T a;
|
|
||||||
Reflect(visitor, a);
|
|
||||||
value = std::move(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()(Reader& visitor, std::variant<Ts...>& value) {
|
|
||||||
// Based on tag dispatch, call different ReflectTag helper.
|
|
||||||
if (visitor.IsNull())
|
|
||||||
ReflectTag<std::monostate>(visitor, value);
|
|
||||||
// It is possible that IsInt64() && IsInt(). We don't call ReflectTag<int>
|
|
||||||
// if int is not in Ts...
|
|
||||||
else if (std::disjunction_v<std::is_same<int, Ts>...> && visitor.IsInt())
|
|
||||||
ReflectTag<int>(visitor, value);
|
|
||||||
else if (visitor.IsInt64())
|
|
||||||
ReflectTag<int64_t>(visitor, value);
|
|
||||||
else if (visitor.IsString())
|
|
||||||
ReflectTag<std::string>(visitor, value);
|
|
||||||
else
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check which type the variant contains and call corresponding Reflect.
|
|
||||||
void operator()(Writer& visitor, std::variant<Ts...>& value) {
|
|
||||||
if (value.index() == N - 1)
|
|
||||||
Reflect(visitor, std::get<N - 1>(value));
|
|
||||||
else
|
|
||||||
ReflectVariant<N - 1, Ts...>()(visitor, value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Writer reflection on std::variant recurses. This is induction basis.
|
|
||||||
template <typename... Ts>
|
|
||||||
struct ReflectVariant<0, Ts...> {
|
|
||||||
void operator()(Writer& visitor, std::variant<Ts...>& value) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// std::variant
|
|
||||||
template <typename TVisitor, typename... Ts>
|
|
||||||
void Reflect(TVisitor& visitor, std::variant<Ts...>& value) {
|
|
||||||
ReflectVariant<sizeof...(Ts), Ts...>()(visitor, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// std::vector
|
// std::vector
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Reflect(Reader& visitor, std::vector<T>& values) {
|
void Reflect(Reader& visitor, std::vector<T>& values) {
|
||||||
|
@ -24,19 +24,15 @@ lsPosition GetPositionForOffset(const std::string& content, int offset) {
|
|||||||
if (offset >= content.size())
|
if (offset >= content.size())
|
||||||
offset = (int)content.size() - 1;
|
offset = (int)content.size() - 1;
|
||||||
|
|
||||||
lsPosition result;
|
int line = 0, col = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (i < offset) {
|
for (; i < offset; i++) {
|
||||||
if (content[i] == '\n') {
|
if (content[i] == '\n')
|
||||||
result.line += 1;
|
line++, col = 0;
|
||||||
result.character = 0;
|
else
|
||||||
} else {
|
col++;
|
||||||
result.character += 1;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
}
|
||||||
|
return {line, col};
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> ToLines(const std::string& content) {
|
std::vector<std::string> ToLines(const std::string& content) {
|
||||||
@ -511,8 +507,8 @@ void WorkingFiles::OnChange(const lsTextDocumentDidChangeParams& change) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// version: number | null
|
// version: number | null
|
||||||
if (std::holds_alternative<int>(change.textDocument.version))
|
if (change.textDocument.version)
|
||||||
file->version = std::get<int>(change.textDocument.version);
|
file->version = *change.textDocument.version;
|
||||||
|
|
||||||
for (const lsTextDocumentContentChangeEvent& diff : change.contentChanges) {
|
for (const lsTextDocumentContentChangeEvent& diff : change.contentChanges) {
|
||||||
// Per the spec replace everything if the rangeLength and range are not set.
|
// Per the spec replace everything if the rangeLength and range are not set.
|
||||||
|
Loading…
Reference in New Issue
Block a user