ccls/src/message_handler.cc

167 lines
5.4 KiB
C++
Raw Normal View History

#include "message_handler.h"
2017-12-06 03:32:33 +00:00
#include "lex_utils.h"
#include "query_utils.h"
#include <loguru.hpp>
MessageHandler::MessageHandler() {
// Dynamically allocate |message_handlers|, otherwise there will be static
// initialization order races.
if (!message_handlers)
message_handlers = new std::vector<MessageHandler*>();
message_handlers->push_back(this);
}
// static
2017-12-06 03:32:33 +00:00
std::vector<MessageHandler*>* MessageHandler::message_handlers = nullptr;
bool FindFileOrFail(QueryDatabase* db,
optional<lsRequestId> id,
const std::string& absolute_path,
QueryFile** out_query_file,
QueryFileId* out_file_id) {
*out_query_file = nullptr;
auto it = db->usr_to_file.find(LowerPathIfCaseInsensitive(absolute_path));
if (it != db->usr_to_file.end()) {
QueryFile& file = db->files[it->second.id];
if (file.def) {
*out_query_file = &file;
if (out_file_id)
*out_file_id = QueryFileId(it->second.id);
return true;
}
}
if (out_file_id)
*out_file_id = QueryFileId((size_t)-1);
LOG_S(INFO) << "Unable to find file \"" << absolute_path << "\"";
2017-12-28 17:03:35 +00:00
/*
2017-12-28 16:55:46 +00:00
LOG_S(INFO) << "Files (size=" << db->usr_to_file.size() << "): "
<< StringJoinMap(db->usr_to_file,
[](const std::pair<Usr, QueryFileId>& entry) {
return entry.first;
});
2017-12-28 17:03:35 +00:00
*/
2017-12-06 03:32:33 +00:00
if (id) {
Out_Error out;
out.id = *id;
out.error.code = lsErrorCodes::InternalError;
out.error.message = "Unable to find file " + absolute_path;
2017-12-24 00:25:18 +00:00
QueueManager::WriteStdout(IpcId::Unknown, out);
2017-12-06 03:32:33 +00:00
}
return false;
}
void EmitInactiveLines(WorkingFile* working_file,
const std::vector<Range>& inactive_regions) {
Out_CquerySetInactiveRegion out;
out.params.uri = lsDocumentUri::FromPath(working_file->filename);
for (Range skipped : inactive_regions) {
optional<lsRange> ls_skipped = GetLsRange(working_file, skipped);
if (ls_skipped)
out.params.inactiveRegions.push_back(*ls_skipped);
}
2017-12-24 00:25:18 +00:00
QueueManager::WriteStdout(IpcId::CqueryPublishInactiveRegions, out);
2017-12-06 03:32:33 +00:00
}
void EmitSemanticHighlighting(QueryDatabase* db,
SemanticHighlightSymbolCache* semantic_cache,
WorkingFile* working_file,
QueryFile* file) {
assert(file->def);
auto map_symbol_kind_to_symbol_type = [](SymbolKind kind) {
switch (kind) {
case SymbolKind::Type:
return Out_CqueryPublishSemanticHighlighting::SymbolType::Type;
case SymbolKind::Func:
return Out_CqueryPublishSemanticHighlighting::SymbolType::Function;
case SymbolKind::Var:
return Out_CqueryPublishSemanticHighlighting::SymbolType::Variable;
default:
assert(false);
return Out_CqueryPublishSemanticHighlighting::SymbolType::Variable;
}
};
auto semantic_cache_for_file =
semantic_cache->GetCacheForFile(file->def->path);
// Group symbols together.
std::unordered_map<SymbolIdx, Out_CqueryPublishSemanticHighlighting::Symbol>
grouped_symbols;
for (SymbolRef sym : file->def->all_symbols) {
std::string detailed_name;
bool is_type_member = false;
// This switch statement also filters out symbols that are not highlighted.
switch (sym.idx.kind) {
case SymbolKind::Func: {
QueryFunc* func = &db->funcs[sym.idx.idx];
if (!func->def)
continue; // applies to for loop
if (func->def->is_operator)
continue; // applies to for loop
is_type_member = func->def->declaring_type.has_value();
detailed_name = func->def->short_name;
break;
}
case SymbolKind::Var: {
QueryVar* var = &db->vars[sym.idx.idx];
if (!var->def)
continue; // applies to for loop
2017-12-24 00:49:11 +00:00
switch (var->def->cls) {
case VarClass::Local:
case VarClass::Global:
case VarClass::Member:
break;
default:
2017-12-27 15:53:35 +00:00
continue; // applies to for loop
2017-12-24 00:49:11 +00:00
}
2017-12-06 03:32:33 +00:00
is_type_member = var->def->declaring_type.has_value();
detailed_name = var->def->short_name;
break;
}
case SymbolKind::Type: {
QueryType* type = &db->types[sym.idx.idx];
if (!type->def)
continue; // applies to for loop
detailed_name = type->def->detailed_name;
break;
}
default:
continue; // applies to for loop
}
optional<lsRange> loc = GetLsRange(working_file, sym.loc.range);
if (loc) {
auto it = grouped_symbols.find(sym.idx);
if (it != grouped_symbols.end()) {
it->second.ranges.push_back(*loc);
} else {
Out_CqueryPublishSemanticHighlighting::Symbol symbol;
symbol.stableId =
semantic_cache_for_file->GetStableId(sym.idx.kind, detailed_name);
symbol.type = map_symbol_kind_to_symbol_type(sym.idx.kind);
symbol.isTypeMember = is_type_member;
symbol.ranges.push_back(*loc);
grouped_symbols[sym.idx] = symbol;
}
}
}
// Publish.
Out_CqueryPublishSemanticHighlighting out;
out.params.uri = lsDocumentUri::FromPath(working_file->filename);
for (auto& entry : grouped_symbols)
out.params.symbols.push_back(entry.second);
2017-12-24 00:25:18 +00:00
QueueManager::WriteStdout(IpcId::CqueryPublishSemanticHighlighting, out);
2017-12-07 01:00:19 +00:00
}
bool ShouldIgnoreFileForIndexing(const std::string& path) {
return StartsWith(path, "git:");
}