From 8145a06534017d64aa68dc20c9126bcd68d9d1ea Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Wed, 8 Nov 2017 23:06:32 -0800 Subject: [PATCH] First pass at semantic highlighting. It is disabled by default. --- src/command_line.cc | 68 +++++++++++++++++++++++++++++++++++++-- src/ipc.cc | 2 ++ src/ipc.h | 1 + src/language_server_api.h | 26 +++++++++++++++ src/query.h | 1 + 5 files changed, 95 insertions(+), 3 deletions(-) diff --git a/src/command_line.cc b/src/command_line.cc index a9171807..7dc00b7f 100644 --- a/src/command_line.cc +++ b/src/command_line.cc @@ -143,6 +143,51 @@ void EmitInactiveLines(WorkingFile* working_file, IpcId::CqueryPublishInactiveRegions, out); } +void EmitSemanticHighlighting(QueryDatabase* db, + WorkingFile* working_file, + QueryFile* file) { + 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; + } + }; + + // Group symbols together. + std::unordered_map> grouped_symbols; + for (SymbolRef sym : file->def->all_symbols) { + if (sym.idx.kind == SymbolKind::Var) { + QueryVar* var = &db->vars[sym.idx.idx]; + if (!var->def) + continue; + if (!var->def->is_local) + continue; + } + optional loc = GetLsRange(working_file, sym.loc.range); + if (loc) + grouped_symbols[sym.idx].push_back(*loc); + } + + // Publish. + Out_CqueryPublishSemanticHighlighting out; + out.params.uri = lsDocumentUri::FromPath(working_file->filename); + for (auto& entry : grouped_symbols) { + Out_CqueryPublishSemanticHighlighting::Symbol symbol; + symbol.type = map_symbol_kind_to_symbol_type(entry.first.kind); + symbol.ranges = entry.second; + out.params.symbols.push_back(symbol); + } + IpcManager::instance()->SendOutMessageToClient( + IpcId::CqueryPublishSemanticHighlighting, out); +} + optional FindIncludeLine(const std::vector& lines, const std::string& full_include_line) { // @@ -1286,6 +1331,18 @@ bool QueryDb_ImportMain(Config* config, return value.path; })); + // Update semantic highlighting. + for (auto& updated_file : response->update.files_def_update) { + WorkingFile* working_file = + working_files->GetFileByFilename(updated_file.path); + if (working_file) { + QueryFileId file_id = + db->usr_to_file[LowerPathIfCaseInsensitive(working_file->filename)]; + QueryFile* file = &db->files[file_id.id]; + EmitSemanticHighlighting(db, working_file, file); + } + } + // Mark the files as being done in querydb stage after we apply the index // update. for (auto& updated_file : response->update.files_def_update) @@ -1774,8 +1831,10 @@ bool QueryDbMainLoop(Config* config, QueryFile* file = nullptr; FindFileOrFail(db, nullopt, path, &file); - if (file && file->def) + if (file && file->def) { EmitInactiveLines(working_file, file->def->inactive_regions); + EmitSemanticHighlighting(db, working_file, file); + } time.ResetAndPrint( "[querydb] Loading cached index file for DidOpen (blocks " @@ -2743,8 +2802,11 @@ bool QueryDbMainLoop(Config* config, // TODO: We need to move this to a separate request, as the user may // have turned code lens off (ie, a custom DidView notification). if (file && file->def) { - EmitInactiveLines(working_files->GetFileByFilename(file->def->path), - file->def->inactive_regions); + WorkingFile* working_file = + working_files->GetFileByFilename(file->def->path); + EmitInactiveLines(working_file, file->def->inactive_regions); + // Do not emit semantic highlighting information here, as it has not + // been updated. } break; diff --git a/src/ipc.cc b/src/ipc.cc index aadea956..e9b31495 100644 --- a/src/ipc.cc +++ b/src/ipc.cc @@ -51,6 +51,8 @@ const char* IpcIdToString(IpcId id) { case IpcId::CqueryPublishInactiveRegions: return "$cquery/publishInactiveRegions"; + case IpcId::CqueryPublishSemanticHighlighting: + return "$cquery/publishSemanticHighlighting"; case IpcId::CqueryFreshenIndex: return "$cquery/freshenIndex"; diff --git a/src/ipc.h b/src/ipc.h index 3e6296f8..c1e6824c 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -32,6 +32,7 @@ enum class IpcId : int { // Custom notifications CqueryPublishInactiveRegions, + CqueryPublishSemanticHighlighting, // Custom messages CqueryFreshenIndex, diff --git a/src/language_server_api.h b/src/language_server_api.h index 9d5d6c1e..ad9b7e6c 100644 --- a/src/language_server_api.h +++ b/src/language_server_api.h @@ -1480,6 +1480,32 @@ struct Out_CquerySetInactiveRegion MAKE_REFLECT_STRUCT(Out_CquerySetInactiveRegion::Params, uri, inactiveRegions); MAKE_REFLECT_STRUCT(Out_CquerySetInactiveRegion, jsonrpc, method, params); +struct Out_CqueryPublishSemanticHighlighting + : public lsOutMessage { + enum class SymbolType { Type = 0, Function, Variable }; + struct Symbol { + SymbolType type; + NonElidedVector ranges; + }; + struct Params { + lsDocumentUri uri; + NonElidedVector symbols; + }; + std::string method = "$cquery/publishSemanticHighlighting"; + Params params; +}; +MAKE_REFLECT_TYPE_PROXY(Out_CqueryPublishSemanticHighlighting::SymbolType, int); +MAKE_REFLECT_STRUCT(Out_CqueryPublishSemanticHighlighting::Symbol, + type, + ranges); +MAKE_REFLECT_STRUCT(Out_CqueryPublishSemanticHighlighting::Params, + uri, + symbols); +MAKE_REFLECT_STRUCT(Out_CqueryPublishSemanticHighlighting, + jsonrpc, + method, + params); + struct Ipc_CqueryFreshenIndex : public IpcMessage { const static IpcId kIpcId = IpcId::CqueryFreshenIndex; lsRequestId id; diff --git a/src/query.h b/src/query.h index c38aa08c..4d32793a 100644 --- a/src/query.h +++ b/src/query.h @@ -74,6 +74,7 @@ struct SymbolIdx { } }; MAKE_REFLECT_STRUCT(SymbolIdx, kind, idx); +MAKE_HASHABLE(SymbolIdx, t.kind, t.idx); struct SymbolRef { SymbolIdx idx;