diff --git a/command_line.cc b/command_line.cc index fa5e9c47..c5f475c3 100644 --- a/command_line.cc +++ b/command_line.cc @@ -276,6 +276,62 @@ void Reflect(TVisitor& visitor, IpcMessage_WorkspaceSymbolsRequest& value) { } +struct IpcMessage_DocumentCodeLensRequest : public BaseIpcMessage { + static constexpr IpcId kIpcId = IpcId::DocumentCodeLensRequest; + RequestId request_id; + std::string document; +}; +template +void Reflect(TVisitor& visitor, IpcMessage_DocumentCodeLensRequest& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(request_id); + REFLECT_MEMBER(document); + REFLECT_MEMBER_END(); +} + +struct IpcMessage_DocumentCodeLensResponse : public BaseIpcMessage { + static constexpr IpcId kIpcId = IpcId::DocumentCodeLensResponse; + RequestId request_id; + std::vector code_lens; +}; +template +void Reflect(TVisitor& visitor, IpcMessage_DocumentCodeLensResponse& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(request_id); + REFLECT_MEMBER(code_lens); + REFLECT_MEMBER_END(); +} + + +struct IpcMessage_CodeLensResolveRequest : public BaseIpcMessage { + static constexpr IpcId kIpcId = IpcId::CodeLensResolveRequest; + RequestId request_id; + TCodeLens code_lens; +}; +template +void Reflect(TVisitor& visitor, IpcMessage_CodeLensResolveRequest& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(request_id); + REFLECT_MEMBER(code_lens); + REFLECT_MEMBER_END(); +} + +struct IpcMessage_CodeLensResolveResponse : public BaseIpcMessage { + static constexpr IpcId kIpcId = IpcId::CodeLensResolveResponse; + RequestId request_id; + TCodeLens code_lens; +}; +template +void Reflect(TVisitor& visitor, IpcMessage_CodeLensResolveResponse& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(request_id); + REFLECT_MEMBER(code_lens); + REFLECT_MEMBER_END(); +} + + + + struct IpcMessage_WorkspaceSymbolsResponse : public BaseIpcMessage { static constexpr IpcId kIpcId = IpcId::WorkspaceSymbolsResponse; RequestId request_id; @@ -394,12 +450,29 @@ void IndexMain(int id) { +QueryableFile* FindFile(QueryableDatabase* db, const std::string& filename) { + //std::cerr << "Wanted file " << msg->document << std::endl; + // TODO: hashmap lookup. + for (auto& file : db->files) { + //std::cerr << " - Have file " << file.file_id << std::endl; + if (file.file_id == filename) { + std::cerr << "Found file " << filename << std::endl; + return &file; + } + } + std::cerr << "Unable to find file " << filename << std::endl; + return nullptr; +} - +lsLocation GetLsLocation(QueryableLocation& location) { + return lsLocation( + lsDocumentUri::FromPath(location.path), + lsRange(lsPosition(location.line - 1, location.column - 1))); +} void QueryDbMainLoop(IpcServer* language_client, IpcServer* indexers, QueryableDatabase* db) { std::vector> messages = language_client->TakeMessages(); @@ -447,73 +520,121 @@ void QueryDbMainLoop(IpcServer* language_client, IpcServer* indexers, QueryableD IpcMessage_DocumentSymbolsResponse response; response.request_id = msg->request_id; - std::cerr << "Wanted file " << msg->document << std::endl; - for (auto& file : db->files) { - std::cerr << " - Have file " << file.file_id << std::endl; - - // TODO: make sure we normalize ids! - // TODO: hashmap lookup. - if (file.file_id == msg->document) { - std::cerr << "Found file" << std::endl; - - - for (UsrRef ref : file.outline) { - SymbolIdx symbol = db->usr_to_symbol[ref.usr]; - - lsSymbolInformation info; - info.location.range.start.line = ref.loc.line - 1; // TODO: cleanup indexer to negate by 1. - info.location.range.start.character = ref.loc.column - 1; // TODO: cleanup indexer to negate by 1. - // TODO: store range information. - info.location.range.end.line = info.location.range.start.line; - info.location.range.end.character = info.location.range.start.character; - - // TODO: cleanup namespace/naming so there is only one SymbolKind. - switch (symbol.kind) { - case ::SymbolKind::Type: - { - QueryableTypeDef& def = db->types[symbol.idx]; - info.name = def.def.qualified_name; - info.kind = lsSymbolKind::Class; - break; - } - case SymbolKind::Func: - { - QueryableFuncDef& def = db->funcs[symbol.idx]; - info.name = def.def.qualified_name; - if (def.def.declaring_type.has_value()) { - info.kind = lsSymbolKind::Method; - Usr declaring = def.def.declaring_type.value(); - info.containerName = db->types[db->usr_to_symbol[declaring].idx].def.qualified_name; - } - else { - info.kind = lsSymbolKind::Function; - } - break; + QueryableFile* file = FindFile(db, msg->document); + if (file) { + for (UsrRef ref : file->outline) { + SymbolIdx symbol = db->usr_to_symbol[ref.usr]; + + lsSymbolInformation info; + info.location.range.start.line = ref.loc.line - 1; // TODO: cleanup indexer to negate by 1. + info.location.range.start.character = ref.loc.column - 1; // TODO: cleanup indexer to negate by 1. + // TODO: store range information. + info.location.range.end.line = info.location.range.start.line; + info.location.range.end.character = info.location.range.start.character; + + // TODO: cleanup namespace/naming so there is only one SymbolKind. + switch (symbol.kind) { + case ::SymbolKind::Type: { + QueryableTypeDef& def = db->types[symbol.idx]; + info.name = def.def.qualified_name; + info.kind = lsSymbolKind::Class; + break; + } + case SymbolKind::Func: { + QueryableFuncDef& def = db->funcs[symbol.idx]; + info.name = def.def.qualified_name; + if (def.def.declaring_type.has_value()) { + info.kind = lsSymbolKind::Method; + Usr declaring = def.def.declaring_type.value(); + info.containerName = db->types[db->usr_to_symbol[declaring].idx].def.qualified_name; } - case ::SymbolKind::Var: - { - QueryableVarDef& def = db->vars[symbol.idx]; - info.name = def.def.qualified_name; - info.kind = lsSymbolKind::Variable; - break; + else { + info.kind = lsSymbolKind::Function; } - }; + break; + } + case ::SymbolKind::Var: { + QueryableVarDef& def = db->vars[symbol.idx]; + info.name = def.def.qualified_name; + info.kind = lsSymbolKind::Variable; + break; + } + }; + + response.symbols.push_back(info); + } + } + + language_client->SendToClient(0, &response); + break; + } - // TODO - //info.containerName = "fooey"; + case IpcId::DocumentCodeLensRequest: { + auto msg = static_cast(message.get()); - response.symbols.push_back(info); + IpcMessage_DocumentCodeLensResponse response; + response.request_id = msg->request_id; + + lsDocumentUri file_as_uri; + file_as_uri.SetPath(msg->document); + + QueryableFile* file = FindFile(db, msg->document); + if (file) { + + for (UsrRef ref : file->outline) { + SymbolIdx symbol = db->usr_to_symbol[ref.usr]; + TCodeLens code_lens; + code_lens.range.start.line = ref.loc.line - 1; // TODO: cleanup indexer to negate by 1. + code_lens.range.start.character = ref.loc.column - 1; // TODO: cleanup indexer to negate by 1. + // TODO: store range information. + code_lens.range.end.line = code_lens.range.start.line; + code_lens.range.end.character = code_lens.range.start.character; + + code_lens.command = lsCommand(); + code_lens.command->command = "superindex.showReferences"; + code_lens.command->arguments.uri = file_as_uri; + code_lens.command->arguments.position = code_lens.range.start; + + + switch (symbol.kind) { + case SymbolKind::Type: { + QueryableTypeDef& def = db->types[symbol.idx]; + for (QueryableLocation& usage : def.uses) { + if (!usage.interesting) + continue; + code_lens.command->arguments.locations.push_back(GetLsLocation(usage)); + } + break; + } + case SymbolKind::Func: { + QueryableFuncDef& def = db->funcs[symbol.idx]; + for (QueryableLocation& usage : def.uses) + code_lens.command->arguments.locations.push_back(GetLsLocation(usage)); + break; } - break; + case SymbolKind::Var: { + QueryableVarDef& def = db->vars[symbol.idx]; + for (QueryableLocation& usage : def.uses) + code_lens.command->arguments.locations.push_back(GetLsLocation(usage)); + break; + } + }; + + // TODO: we are getting too many references + int num_usages = code_lens.command->arguments.locations.size(); + code_lens.command->title = std::to_string(num_usages) + " reference"; + if (num_usages != 1) + code_lens.command->title += "s"; + + response.code_lens.push_back(code_lens); } - } + } language_client->SendToClient(0, &response); - break; } @@ -588,20 +709,14 @@ void QueryDbMainLoop(IpcServer* language_client, IpcServer* indexers, QueryableD }; - - // TODO: store range information. info.location.range.end.line = info.location.range.start.line; info.location.range.end.character = info.location.range.start.character; response.symbols.push_back(info); - } - - } - language_client->SendToClient(0, &response); break; } @@ -743,6 +858,9 @@ void LanguageServerStdinLoop(IpcClient* server) { auto response = Out_InitializeResponse(); response.id = message->id.value(); response.result.capabilities.documentSymbolProvider = true; + //response.result.capabilities.referencesProvider = true; + response.result.capabilities.codeLensProvider = lsCodeLensOptions(); + response.result.capabilities.codeLensProvider->resolveProvider = false; response.result.capabilities.workspaceSymbolProvider = true; response.Send(); break; @@ -762,6 +880,18 @@ void LanguageServerStdinLoop(IpcClient* server) { break; } + case lsMethodId::TextDocumentCodeLens: + { + auto request = static_cast(message.get()); + + IpcMessage_DocumentCodeLensRequest ipc_request; + ipc_request.request_id = request->id.value(); + ipc_request.document = request->params.textDocument.uri.GetPath(); + std::cerr << "Request codeLens on textDocument=" << ipc_request.document << std::endl; + server->SendToServer(&ipc_request); + break; + } + case lsMethodId::WorkspaceSymbol: { auto request = static_cast(message.get()); @@ -792,7 +922,18 @@ void LanguageServerMainLoop(IpcClient* ipc) { response.id = msg->request_id; response.result = msg->symbols; response.Send(); - std::cerr << "Send symbol response to client (" << response.result.size() << " symbols)" << std::endl; + std::cerr << "Sent symbol response to client (" << response.result.size() << " symbols)" << std::endl; + break; + } + + case IpcId::DocumentCodeLensResponse: { + auto msg = static_cast(message.get()); + + auto response = Out_DocumentCodeLensResponse(); + response.id = msg->request_id; + response.result = msg->code_lens; + response.Send(); + std::cerr << "Sent code lens response to client (" << response.result.size() << " symbols)" << std::endl; break; } @@ -858,7 +999,7 @@ void LanguageServerMain(std::string process_name) { // Pass empty process name so we only try to start the querydb once. LanguageServerMain(""); return; -} + } #endif // for debugging attach @@ -946,6 +1087,11 @@ void PreMain() { IpcRegistry::instance()->Register(IpcMessage_DocumentSymbolsRequest::kIpcId); IpcRegistry::instance()->Register(IpcMessage_DocumentSymbolsResponse::kIpcId); + IpcRegistry::instance()->Register(IpcMessage_DocumentCodeLensRequest::kIpcId); + IpcRegistry::instance()->Register(IpcMessage_DocumentCodeLensResponse::kIpcId); + IpcRegistry::instance()->Register(IpcMessage_CodeLensResolveRequest::kIpcId); + IpcRegistry::instance()->Register(IpcMessage_CodeLensResolveResponse::kIpcId); + IpcRegistry::instance()->Register(IpcMessage_WorkspaceSymbolsRequest::kIpcId); IpcRegistry::instance()->Register(IpcMessage_WorkspaceSymbolsResponse::kIpcId); @@ -953,6 +1099,7 @@ void PreMain() { MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); + MessageRegistry::instance()->Register(); MessageRegistry::instance()->Register(); } diff --git a/ipc.h b/ipc.h index 289e953e..01d86d2d 100644 --- a/ipc.h +++ b/ipc.h @@ -33,6 +33,10 @@ enum class IpcId : int { // TODO: remove DocumentSymbolsRequest, DocumentSymbolsResponse, + DocumentCodeLensRequest, + DocumentCodeLensResponse, + CodeLensResolveRequest, + CodeLensResolveResponse, WorkspaceSymbolsRequest, WorkspaceSymbolsResponse }; diff --git a/language_server_api.h b/language_server_api.h index e2459114..580be41b 100644 --- a/language_server_api.h +++ b/language_server_api.h @@ -24,6 +24,8 @@ enum class lsMethodId : int { Initialize, Initialized, TextDocumentDocumentSymbol, + TextDocumentCodeLens, + CodeLensResolve, WorkspaceSymbol, }; @@ -240,6 +242,10 @@ const char* MethodIdToString(lsMethodId id) { return "initialized"; case lsMethodId::TextDocumentDocumentSymbol: return "textDocument/documentSymbol"; + case lsMethodId::TextDocumentCodeLens: + return "textDocument/codeLens"; + case lsMethodId::CodeLensResolve: + return "codeLens/resolve"; case lsMethodId::WorkspaceSymbol: return "workspace/symbol"; default: @@ -392,6 +398,14 @@ struct In_CancelRequest : public InNotificationMessage { struct lsDocumentUri { std::string raw_uri; + lsDocumentUri() {} + + static lsDocumentUri FromPath(const std::string& path) { + lsDocumentUri result; + result.SetPath(path); + return result; + } + void SetPath(const std::string& path) { // file:///c%3A/Users/jacob/Desktop/superindex/indexer/full_tests raw_uri = path; @@ -434,6 +448,9 @@ struct lsPosition { // Note: these are 0-based. int line = 0; int character = 0; + + lsPosition() {} + lsPosition(int line, int character) : line(line), character(character) {} }; template @@ -448,6 +465,9 @@ void Reflect(TVisitor& visitor, lsPosition& value) { struct lsRange { lsPosition start; lsPosition end; + + lsRange() {} + lsRange(lsPosition position) : start(position), end(position) {} }; template @@ -462,6 +482,9 @@ void Reflect(TVisitor& visitor, lsRange& value) { struct lsLocation { lsDocumentUri uri; lsRange range; + + lsLocation() {} + lsLocation(lsDocumentUri uri, lsRange range) : uri(uri), range(range) {} }; template @@ -520,18 +543,18 @@ void Reflect(TVisitor& visitor, lsSymbolInformation& value) { REFLECT_MEMBER_END(); } - +template struct lsCommand { // Title of the command (ie, 'save') std::string title; // Actual command identifier. std::string command; - // Arguments to run the command with. Could be JSON objects. - std::vector arguments; + // Arguments to run the command with. + T arguments; }; -template -void Reflect(TVisitor& visitor, lsCommand& value) { +template +void Reflect(TVisitor& visitor, lsCommand& value) { REFLECT_MEMBER_START(); REFLECT_MEMBER(title); REFLECT_MEMBER(command); @@ -540,6 +563,26 @@ void Reflect(TVisitor& visitor, lsCommand& value) { } +template +struct lsCodeLens { + // The range in which this code lens is valid. Should only span a single line. + lsRange range; + // The command this code lens represents. + optional> command; + // A data entry field that is preserved on a code lens item between + // a code lens and a code lens resolve request. + TData data; +}; + +template +void Reflect(TVisitor& visitor, lsCodeLens& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(range); + REFLECT_MEMBER(command); + REFLECT_MEMBER(data); + REFLECT_MEMBER_END(); +} + // TODO: TextDocumentEdit // TODO: WorkspaceEdit @@ -800,8 +843,13 @@ struct lsTextDocumentClientCapabilities { // Capabilities specific to the `textDocument/codeAction` optional codeAction; + struct CodeLensRegistrationOptions : public lsGenericDynamicReg { + // Code lens has a resolve provider as well. + bool resolveProvider; + }; + // Capabilities specific to the `textDocument/codeLens` - optional codeLens; + optional codeLens; // Capabilities specific to the `textDocument/documentLink` optional documentLink; @@ -842,6 +890,14 @@ void Reflect(TVisitor& visitor, lsTextDocumentClientCapabilities::lsGenericDynam REFLECT_MEMBER_END(); } +template +void Reflect(TVisitor& visitor, lsTextDocumentClientCapabilities::CodeLensRegistrationOptions& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(dynamicRegistration); + REFLECT_MEMBER(resolveProvider); + REFLECT_MEMBER_END(); +} + template void Reflect(TVisitor& visitor, lsTextDocumentClientCapabilities& value) { REFLECT_MEMBER_START(); @@ -1281,7 +1337,6 @@ struct In_DocumentSymbolRequest : public InRequestMessage { } }; - struct Out_DocumentSymbolResponse : public OutResponseMessage { std::vector result; @@ -1295,6 +1350,93 @@ struct Out_DocumentSymbolResponse : public OutResponseMessage { +struct lsDocumentCodeLensParams { + lsTextDocumentIdentifier textDocument; +}; + +template +void Reflect(TVisitor& visitor, lsDocumentCodeLensParams& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(textDocument); + REFLECT_MEMBER_END(); +} + +struct lsCodeLensUserData {}; + +template +void Reflect(TVisitor& visitor, lsCodeLensUserData& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER_END(); +} + +struct lsCodeLensCommandArguments { + lsDocumentUri uri; + lsPosition position; + std::vector locations; +}; + +void Reflect(Writer& visitor, lsCodeLensCommandArguments& value) { + visitor.StartArray(); + Reflect(visitor, value.uri); + Reflect(visitor, value.position); + Reflect(visitor, value.locations); + visitor.EndArray(); +} + +void Reflect(Reader& visitor, lsCodeLensCommandArguments& value) { + auto it = visitor.Begin(); + Reflect(*it, value.uri); + ++it; + Reflect(*it, value.position); + ++it; + Reflect(*it, value.locations); +} + +using TCodeLens = lsCodeLens; + +struct In_DocumentCodeLensRequest : public InRequestMessage { + const static lsMethodId kMethod = lsMethodId::TextDocumentCodeLens; + + lsDocumentCodeLensParams params; + + In_DocumentCodeLensRequest(optional id, Reader& reader) + : InRequestMessage(kMethod, id, reader) { + Reflect(reader, params); + } +}; + +struct Out_DocumentCodeLensResponse : public OutResponseMessage { + std::vector> result; + + // OutResponseMessage: + void WriteResult(Writer& writer) override { + ::Reflect(writer, result); + } +}; + +struct In_DocumentCodeLensResolveRequest : public InRequestMessage { + const static lsMethodId kMethod = lsMethodId::CodeLensResolve; + + TCodeLens params; + + In_DocumentCodeLensResolveRequest(optional id, Reader& reader) + : InRequestMessage(kMethod, id, reader) { + Reflect(reader, params); + } +}; + +struct Out_DocumentCodeLensResolveResponse : public OutResponseMessage { + TCodeLens result; + + // OutResponseMessage: + void WriteResult(Writer& writer) override { + ::Reflect(writer, result); + } +}; + + + + @@ -1321,7 +1463,6 @@ struct In_WorkspaceSymbolRequest : public InRequestMessage { } }; - struct Out_WorkspaceSymbolResponse : public OutResponseMessage { std::vector result;