From 71d1b1ffc6e9d9947ec38cc7a24f66f3f9ec515f Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Thu, 13 Apr 2017 23:43:50 -0700 Subject: [PATCH] Implement textDocument/documentHighlight --- src/command_line.cc | 51 ++++++++++++++++++++++++++++++++++++-- src/indexer.h | 4 +++ src/ipc.cc | 2 ++ src/ipc.h | 1 + src/language_server_api.cc | 5 ++++ src/language_server_api.h | 37 +++++++++++++++++++++++++++ src/platform_win.cc | 1 + 7 files changed, 99 insertions(+), 2 deletions(-) diff --git a/src/command_line.cc b/src/command_line.cc index 38b73374..751cdd83 100644 --- a/src/command_line.cc +++ b/src/command_line.cc @@ -538,6 +538,7 @@ std::unique_ptr BuildIpcMessageQueue(const std::string& name, s RegisterId(ipc.get()); RegisterId(ipc.get()); RegisterId(ipc.get()); + RegisterId(ipc.get()); RegisterId(ipc.get()); RegisterId(ipc.get()); RegisterId(ipc.get()); @@ -561,6 +562,7 @@ void RegisterMessageTypes() { MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); + MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); @@ -918,6 +920,49 @@ void QueryDbMainLoop( break; } + case IpcId::TextDocumentDocumentHighlight: { + auto msg = static_cast(message.get()); + + QueryFileId file_id; + QueryableFile* file = FindFile(db, msg->params.textDocument.uri.GetPath(), &file_id); + if (!file) { + std::cerr << "Unable to find file " << msg->params.textDocument.uri.GetPath() << std::endl; + break; + } + Out_TextDocumentDocumentHighlight response; + response.id = msg->id; + + // TODO: consider refactoring into FindSymbolsAtLocation(file); + int target_line = msg->params.position.line + 1; + int target_column = msg->params.position.character + 1; + for (const SymbolRef& ref : file->def.all_symbols) { + if (ref.loc.range.start.line >= target_line && ref.loc.range.end.line <= target_line && + ref.loc.range.start.column <= target_column && ref.loc.range.end.column >= target_column) { + + // Found symbol. Return references to highlight. + std::vector uses = GetUsesOfSymbol(db, ref.idx); + response.result.reserve(uses.size()); + for (const QueryableLocation& use : uses) { + if (use.path != file_id) + continue; + + optional ls_location = GetLsLocation(db, working_files, use); + if (!ls_location) + continue; + + lsDocumentHighlight highlight; + highlight.kind = lsDocumentHighlightKind::Text; + highlight.range = ls_location->range; + response.result.push_back(highlight); + } + break; + } + } + + SendOutMessageToClient(language_client, response); + break; + } + case IpcId::TextDocumentHover: { auto msg = static_cast(message.get()); @@ -929,13 +974,14 @@ void QueryDbMainLoop( Out_TextDocumentHover response; response.id = msg->id; + // TODO: consider refactoring into FindSymbolsAtLocation(file); int target_line = msg->params.position.line + 1; int target_column = msg->params.position.character + 1; for (const SymbolRef& ref : file->def.all_symbols) { if (ref.loc.range.start.line >= target_line && ref.loc.range.end.line <= target_line && ref.loc.range.start.column <= target_column && ref.loc.range.end.column >= target_column) { - // Found symbol. Return references. + // Found symbol. Return hover. optional ls_range = GetLsRange(working_files->GetFileByFilename(file->def.usr), ref.loc.range); if (!ls_range) continue; @@ -1282,8 +1328,8 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) { response.result.capabilities.codeLensProvider->resolveProvider = false; response.result.capabilities.definitionProvider = true; + response.result.capabilities.documentHighlightProvider = true; response.result.capabilities.hoverProvider = true; - response.result.capabilities.referencesProvider = true; response.result.capabilities.documentSymbolProvider = true; @@ -1310,6 +1356,7 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) { case IpcId::TextDocumentDidSave: case IpcId::TextDocumentCompletion: case IpcId::TextDocumentDefinition: + case IpcId::TextDocumentDocumentHighlight: case IpcId::TextDocumentHover: case IpcId::TextDocumentReferences: case IpcId::TextDocumentDocumentSymbol: diff --git a/src/indexer.h b/src/indexer.h index 2d04718c..accc2099 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -50,6 +50,10 @@ bool operator==(const Id& a, const Id& b) { assert(a.group == b.group && "Cannot compare Ids from different groups"); return a.id == b.id; } +template +bool operator!=(const Id& a, const Id& b) { + return !(a == b); +} using IndexTypeId = Id; using IndexFuncId = Id; diff --git a/src/ipc.cc b/src/ipc.cc index 3a3eb633..a5fdf37e 100644 --- a/src/ipc.cc +++ b/src/ipc.cc @@ -22,6 +22,8 @@ const char* IpcIdToString(IpcId id) { return "textDocument/completion"; case IpcId::TextDocumentDefinition: return "textDocument/definition"; + case IpcId::TextDocumentDocumentHighlight: + return "textDocument/documentHighlight"; case IpcId::TextDocumentHover: return "textDocument/hover"; case IpcId::TextDocumentReferences: diff --git a/src/ipc.h b/src/ipc.h index 388b8bd7..ca0c53b0 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -16,6 +16,7 @@ enum class IpcId : int { TextDocumentDidSave, TextDocumentCompletion, TextDocumentDefinition, + TextDocumentDocumentHighlight, TextDocumentHover, TextDocumentReferences, TextDocumentDocumentSymbol, diff --git a/src/language_server_api.cc b/src/language_server_api.cc index 157170a4..804e117b 100644 --- a/src/language_server_api.cc +++ b/src/language_server_api.cc @@ -166,6 +166,11 @@ std::string lsDocumentUri::GetPath() const { } std::replace(result.begin(), result.end(), '\\', '/'); + +#if defined(_WIN32) + //std::transform(result.begin(), result.end(), result.begin(), ::tolower); +#endif + return result; } diff --git a/src/language_server_api.h b/src/language_server_api.h index 9b79d582..c5f7dbd6 100644 --- a/src/language_server_api.h +++ b/src/language_server_api.h @@ -488,6 +488,29 @@ struct lsTextDocumentEdit { }; MAKE_REFLECT_STRUCT(lsTextDocumentEdit, textDocument, edits); +// A document highlight kind. +enum class lsDocumentHighlightKind { + // A textual occurrence. + Text = 1, + // Read-access of a symbol, like reading a variable. + Read = 2, + // Write-access of a symbol, like writing to a variable. + Write = 3 +}; +MAKE_REFLECT_TYPE_PROXY(lsDocumentHighlightKind, int); + +// A document highlight is a range inside a text document which deserves +// special attention. Usually a document highlight is visualized by changing +// the background color of its range. +struct lsDocumentHighlight { + // The range this highlight applies to. + lsRange range; + + // The highlight kind, default is DocumentHighlightKind.Text. + lsDocumentHighlightKind kind = lsDocumentHighlightKind::Text; +}; +MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind); + // TODO: WorkspaceEdit // TODO: DocumentFilter // TODO: DocumentSelector @@ -1131,6 +1154,20 @@ struct Out_TextDocumentDefinition : public lsOutMessage { + const static IpcId kIpcId = IpcId::TextDocumentDocumentHighlight; + + lsRequestId id; + lsTextDocumentPositionParams params; +}; +MAKE_REFLECT_STRUCT(Ipc_TextDocumentDocumentHighlight, id, params); +struct Out_TextDocumentDocumentHighlight : public lsOutMessage { + lsRequestId id; + NonElidedVector result; +}; +MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentHighlight, jsonrpc, id, result); + // Hover struct Ipc_TextDocumentHover : public IpcMessage { const static IpcId kIpcId = IpcId::TextDocumentHover; diff --git a/src/platform_win.cc b/src/platform_win.cc index 652b0704..9d5a28e4 100644 --- a/src/platform_win.cc +++ b/src/platform_win.cc @@ -141,6 +141,7 @@ std::string NormalizePath(const std::string& path) { std::string result = buffer; std::replace(result.begin(), result.end(), '\\', '/'); + //std::transform(result.begin(), result.end(), result.begin(), ::tolower); return result; }