diff --git a/src/eepp/ui/doc/languages/jsx.cpp b/src/eepp/ui/doc/languages/jsx.cpp index 20d88b116..ba3e51c4a 100644 --- a/src/eepp/ui/doc/languages/jsx.cpp +++ b/src/eepp/ui/doc/languages/jsx.cpp @@ -55,7 +55,6 @@ void addJSX() { { "NaN", "keyword2" }, { "this", "keyword2" }, }, "//" } ) - .setAutoCloseXMLTags( true ) .setLSPName( "javascriptreact" ); sd.setFoldRangeType( FoldRangeType::Braces ).setFoldBraces( { { '{', '}' } } ); diff --git a/src/eepp/ui/doc/languages/typescript.cpp b/src/eepp/ui/doc/languages/typescript.cpp index 629b17111..8fbc1a352 100644 --- a/src/eepp/ui/doc/languages/typescript.cpp +++ b/src/eepp/ui/doc/languages/typescript.cpp @@ -103,7 +103,6 @@ void addTypeScript() { "//" } ) .setSymbols( ts.getSymbols() ) .setLSPName( "typescriptreact" ) - .setAutoCloseXMLTags( true ) .setFoldRangeType( FoldRangeType::Braces ) .setFoldBraces( { { '{', '}' } } ); ; diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index 20ee8207d..fd75f1338 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -434,6 +434,31 @@ PluginRequestHandle LSPClientPlugin::processWorkspaceSymbol( const PluginMessage return hdl; } +PluginRequestHandle LSPClientPlugin::processWorkspaceDiagnostic( const PluginMessage& msg ) { + if ( !( ( msg.isBroadcast() && msg.type == PluginMessageType::LanguageServerReady && msg.data && + msg.format == PluginMessageFormat::LSPClientServer ) || + ( msg.isRequest() && msg.type == PluginMessageType::WorkspaceDiagnostic && + msg.format == PluginMessageFormat::LSPClientServer ) ) ) + return {}; +/* NOTE: I couldn't find a single LSP server supporting this feature so I cannot test it. + * I'll leave the current implementation here to continue with it later in the future. + * Since I started implementing it assuming it was commonly supported... + + LSPClientServer* server = + const_cast( reinterpret_cast( msg.data ) ); + + if ( !server->getCapabilities().diagnosticProvider.workspaceDiagnostics ) + return {}; + + server->workspaceDiagnosticAsync( + [this]( const PluginIDType&, LSPWorkspaceDiagnosticReport&& report ) { + mManager->sendBroadcast( this, PluginMessageType::WorkspaceDiagnostic, + PluginMessageFormat::WorkspaceDiagnosticReport, &report ); + } ); +*/ + return PluginRequestHandle::broadcast(); +} + PluginRequestHandle LSPClientPlugin::processTextDocumentSymbol( const PluginMessage& msg ) { if ( !msg.isRequest() || ( msg.type != PluginMessageType::TextDocumentSymbol && @@ -938,6 +963,11 @@ PluginRequestHandle LSPClientPlugin::processMessage( const PluginMessage& msg ) processFoldingRanges( msg ); break; } + case PluginMessageType::WorkspaceDiagnostic: + case PluginMessageType::LanguageServerReady: { + processWorkspaceDiagnostic( msg ); + break; + } default: break; } diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.hpp b/src/tools/ecode/plugins/lsp/lspclientplugin.hpp index 72677044a..f3e7e14cb 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.hpp @@ -27,7 +27,7 @@ class LSPClientPlugin : public Plugin { public: static PluginDefinition Definition() { return { "lspclient", "LSP Client", "Language Server Protocol Client.", - LSPClientPlugin::New, { 0, 2, 7 }, LSPClientPlugin::NewSync }; + LSPClientPlugin::New, { 0, 2, 8 }, LSPClientPlugin::NewSync }; } static Plugin* New( PluginManager* pluginManager ); @@ -171,6 +171,8 @@ class LSPClientPlugin : public Plugin { PluginRequestHandle processWorkspaceSymbol( const PluginMessage& msg ); + PluginRequestHandle processWorkspaceDiagnostic( const PluginMessage& msg ); + void tryHideTooltip( UICodeEditor* editor, const Vector2i& position ); void hideTooltip( UICodeEditor* editor ); diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.cpp b/src/tools/ecode/plugins/lsp/lspclientserver.cpp index 985492f60..b2727fa93 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.cpp @@ -55,6 +55,7 @@ static const char* MEMBER_QUERY = "query"; static const char* MEMBER_SUCCESS = "success"; static const char* MEMBER_LIMIT = "limit"; static const char* MEMBER_OPTIONS = "options"; +static const char* MEMBER_PREVIOUS_RESULT_IDS = "previousResultIds"; static json newRequest( const std::string& method, const json& params = json{} ) { json j; @@ -366,6 +367,11 @@ static void fromJson( LSPServerCapabilities& caps, const json& json ) { caps.documentHighlightProvider = toBoolOrObject( json, "documentHighlightProvider" ); caps.documentFormattingProvider = toBoolOrObject( json, "documentFormattingProvider" ); caps.workspaceSymbolProvider = toBoolOrObject( json, "workspaceSymbolProvider" ); + if ( json.contains( "diagnosticProvider" ) ) { + caps.diagnosticProvider.workspaceDiagnostics = json.value( "workspaceDiagnostics", false ); + caps.diagnosticProvider.interFileDependencies = + json.value( "interFileDependencies", false ); + } caps.foldingRangeProvider = toBoolOrObject( json, "foldingRangeProvider" ); if ( json.contains( "documentRangeFormattingProvider" ) ) caps.documentRangeFormattingProvider = @@ -1041,6 +1047,24 @@ static std::vector parseFoldingRange( const json& result ) { return ranges; } +static LSPWorkspaceDiagnosticReport parseWorkspaceDiagnosticReport( const json& res ) { + LSPWorkspaceDiagnosticReport report; + if ( res.contains( "items" ) ) { + for ( const auto& item : res["items"] ) { + if ( item.contains( "kind" ) && item.contains( "uri" ) ) { + LSPFullDocumentDiagnosticReport docReport; + URI uri = item.at( "uri" ).get(); + docReport.uri = uri; + docReport.kind = item.at( "kind" ).get(); + docReport.resultId = item.value( "resultId", "" ); + docReport.items = parseDiagnostics( item["item"] ); + report.items[uri] = std::move( docReport ); + } + } + } + return report; +} + void LSPClientServer::registerCapabilities( const json& jcap ) { if ( !jcap.is_object() || !jcap.contains( "registrations" ) || !jcap["registrations"].is_array() ) @@ -1194,6 +1218,10 @@ void LSPClientServer::initialize() { mManager->getPluginManager()->sendBroadcast( mManager->getPlugin(), PluginMessageType::LanguageServerCapabilities, PluginMessageFormat::LanguageServerCapabilities, &mCapabilities ); + + mManager->getPluginManager()->sendBroadcast( + nullptr, PluginMessageType::LanguageServerReady, + PluginMessageFormat::LSPClientServer, this ); }, []( const IdType&, const json& ) {} ); } @@ -1720,6 +1748,18 @@ LSPClientServer::workspaceSymbol( const std::string& querySymbol, const SymbolIn limit ); } +void LSPClientServer::workspaceDiagnosticAsync( const JsonReplyHandler& h ) { + auto params = json{ { MEMBER_PREVIOUS_RESULT_IDS, json::array() } }; + sendAsync( newRequest( "workspace/diagnostic", params ), h ); +} + +void LSPClientServer::workspaceDiagnosticAsync( const WorkspaceDiagnosticHandler& h ) { + workspaceDiagnosticAsync( [h]( const IdType& id, const json& json ) { + if ( h ) + h( id, parseWorkspaceDiagnosticReport( json ) ); + } ); +} + void fromJson( LSPWorkDoneProgressValue& value, const json& data ) { if ( !data.empty() ) { json ob = data; diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.hpp b/src/tools/ecode/plugins/lsp/lspclientserver.hpp index 1337f3de5..5ed0b7cda 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.hpp @@ -47,6 +47,7 @@ class LSPClientServer { using TextEditArrayHandler = ReplyHandler>; using WorkspaceEditHandler = ReplyHandler; using SemanticTokensDeltaHandler = WReplyHandler; + using WorkspaceDiagnosticHandler = WReplyHandler; class LSPRequestHandle : public PluginRequestHandle { public: @@ -199,6 +200,10 @@ class LSPClientServer { const SymbolInformationHandler& h, const size_t& limit = 100 ); + void workspaceDiagnosticAsync( const JsonReplyHandler& h ); + + void workspaceDiagnosticAsync( const WorkspaceDiagnosticHandler& h ); + LSPRequestHandle selectionRange( const URI& document, const std::vector& positions, const JsonReplyHandler& h ); diff --git a/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp b/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp index c9b655050..c9ac315a7 100644 --- a/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp @@ -488,6 +488,11 @@ void LSPClientServerManager::didChangeWorkspaceFolders( const std::string& folde Lock l( mClientsMutex ); for ( auto& server : mClients ) { server.second->didChangeWorkspaceFolders( newWorkspaceFolder, oldLSPWorkspaceFolder, true ); + if ( server.second->getCapabilities().diagnosticProvider.workspaceDiagnostics ) { + mPlugin->getManager()->sendRequest( PluginMessageType::WorkspaceDiagnostic, + PluginMessageFormat::LSPClientServer, + server.second.get() ); + } // If there's a workspace folder change, but the server don't support it, we need to close // the server because the current workspace will be broken if we don't reopen the server in // the correct rootUri/rootPath diff --git a/src/tools/ecode/plugins/lsp/lspprotocol.hpp b/src/tools/ecode/plugins/lsp/lspprotocol.hpp index eb371b8a4..1ad011a3d 100644 --- a/src/tools/ecode/plugins/lsp/lspprotocol.hpp +++ b/src/tools/ecode/plugins/lsp/lspprotocol.hpp @@ -133,6 +133,11 @@ struct LSPCodeLensOptions { bool resolveProvider = false; }; +struct LSPDiagnosticOptions { + bool interFileDependencies = false; + bool workspaceDiagnostics = false; +}; + struct LSPServerCapabilities { bool ready = false; std::vector languages; @@ -154,6 +159,7 @@ struct LSPServerCapabilities { bool foldingRangeProvider = false; LSPCodeLensOptions codeLensProvider; bool workspaceSymbolProvider = false; + LSPDiagnosticOptions diagnosticProvider; LSPDocumentOnTypeFormattingOptions documentOnTypeFormattingProvider; bool renameProvider = false; // CodeActionOptions not useful/considered at present @@ -623,6 +629,27 @@ struct LSPFoldingRange { LSPFoldingRangeKind kind{ LSPFoldingRangeKind::Region }; }; +struct LSPPreviousResultId { + URI uri; + std::string value; +}; + +using LSPPreviousResultIds = std::vector; + +static constexpr auto LSPDocumentDiagnosticReportKindFull = "full"; +static constexpr auto LSPDocumentDiagnosticReportKindUnchanged= "unchanged"; + +struct LSPFullDocumentDiagnosticReport { + URI uri; + std::string kind; + std::string resultId; + std::vector items; +}; + +struct LSPWorkspaceDiagnosticReport { + std::unordered_map items; +}; + } // namespace ecode #endif // ECODE_LSPCLIENTPROTOCOL_HPP diff --git a/src/tools/ecode/plugins/pluginmanager.cpp b/src/tools/ecode/plugins/pluginmanager.cpp index 82b94865d..025a6e442 100644 --- a/src/tools/ecode/plugins/pluginmanager.cpp +++ b/src/tools/ecode/plugins/pluginmanager.cpp @@ -222,7 +222,7 @@ void PluginManager::sendBroadcast( Plugin* pluginWho, PluginMessageType type, subscribedPlugins = mSubscribedPlugins; } for ( const auto& plugin : subscribedPlugins ) - if ( pluginWho->getId() != plugin.first ) + if ( nullptr == pluginWho || pluginWho->getId() != plugin.first ) plugin.second( { type, format, data, -1 } ); } diff --git a/src/tools/ecode/plugins/pluginmanager.hpp b/src/tools/ecode/plugins/pluginmanager.hpp index 146ae33c0..6ce5eae1b 100644 --- a/src/tools/ecode/plugins/pluginmanager.hpp +++ b/src/tools/ecode/plugins/pluginmanager.hpp @@ -93,6 +93,8 @@ enum class PluginMessageType { UIReady, // Informs the Plugins that the UI is ready to be used UIThemeReloaded, // Informs the plugins that the UI theme has been reloaded FoldingRanges, // Request to the LSP server the folding ranges of a document + WorkspaceDiagnostic, // Informs the current workspace diagnostic + LanguageServerReady, // Informs that an LSP server is ready Undefined }; @@ -108,7 +110,9 @@ enum class PluginMessageFormat { ShowDocument, SymbolInformation, DiagnosticsCodeAction, - FoldingRanges + FoldingRanges, + WorkspaceDiagnosticReport, + LSPClientServer, }; class PluginIDType { @@ -206,6 +210,10 @@ struct PluginMessage { return *static_cast( data ); } + const LSPWorkspaceDiagnosticReport& asLSPWorkspaceDiagnosticReport() const { + return *static_cast( data ); + } + const PluginIDType& asPluginID() const { return *static_cast( data ); } bool isResponse() const { return -1 != responseID && 0 != responseID; }