Skip to content

Commit

Permalink
Started implementing LSP workspace diagnostic to find that not a sing…
Browse files Browse the repository at this point in the history
…le LSP implements it, so I just wasted 2 hours of my life. I'll keep the base structure for the future.
  • Loading branch information
SpartanJ committed Nov 26, 2024
1 parent 9f18c81 commit 0e97236
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 5 deletions.
1 change: 0 additions & 1 deletion src/eepp/ui/doc/languages/jsx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ void addJSX() {
{ "NaN", "keyword2" }, { "this", "keyword2" },
},
"//" } )
.setAutoCloseXMLTags( true )
.setLSPName( "javascriptreact" );

sd.setFoldRangeType( FoldRangeType::Braces ).setFoldBraces( { { '{', '}' } } );
Expand Down
1 change: 0 additions & 1 deletion src/eepp/ui/doc/languages/typescript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ void addTypeScript() {
"//" } )
.setSymbols( ts.getSymbols() )
.setLSPName( "typescriptreact" )
.setAutoCloseXMLTags( true )
.setFoldRangeType( FoldRangeType::Braces )
.setFoldBraces( { { '{', '}' } } );
;
Expand Down
30 changes: 30 additions & 0 deletions src/tools/ecode/plugins/lsp/lspclientplugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<LSPClientServer*>( reinterpret_cast<const LSPClientServer*>( 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 &&
Expand Down Expand Up @@ -938,6 +963,11 @@ PluginRequestHandle LSPClientPlugin::processMessage( const PluginMessage& msg )
processFoldingRanges( msg );
break;
}
case PluginMessageType::WorkspaceDiagnostic:
case PluginMessageType::LanguageServerReady: {
processWorkspaceDiagnostic( msg );
break;
}
default:
break;
}
Expand Down
4 changes: 3 additions & 1 deletion src/tools/ecode/plugins/lsp/lspclientplugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down Expand Up @@ -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 );
Expand Down
40 changes: 40 additions & 0 deletions src/tools/ecode/plugins/lsp/lspclientserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -1041,6 +1047,24 @@ static std::vector<LSPFoldingRange> 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<std::string>();
docReport.uri = uri;
docReport.kind = item.at( "kind" ).get<std::string>();
docReport.resultId = item.value<std::string>( "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() )
Expand Down Expand Up @@ -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& ) {} );
}
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions src/tools/ecode/plugins/lsp/lspclientserver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class LSPClientServer {
using TextEditArrayHandler = ReplyHandler<std::vector<LSPTextEdit>>;
using WorkspaceEditHandler = ReplyHandler<LSPWorkspaceEdit>;
using SemanticTokensDeltaHandler = WReplyHandler<LSPSemanticTokensDelta>;
using WorkspaceDiagnosticHandler = WReplyHandler<LSPWorkspaceDiagnosticReport>;

class LSPRequestHandle : public PluginRequestHandle {
public:
Expand Down Expand Up @@ -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<TextPosition>& positions,
const JsonReplyHandler& h );
Expand Down
5 changes: 5 additions & 0 deletions src/tools/ecode/plugins/lsp/lspclientservermanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions src/tools/ecode/plugins/lsp/lspprotocol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ struct LSPCodeLensOptions {
bool resolveProvider = false;
};

struct LSPDiagnosticOptions {
bool interFileDependencies = false;
bool workspaceDiagnostics = false;
};

struct LSPServerCapabilities {
bool ready = false;
std::vector<std::string> languages;
Expand All @@ -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
Expand Down Expand Up @@ -623,6 +629,27 @@ struct LSPFoldingRange {
LSPFoldingRangeKind kind{ LSPFoldingRangeKind::Region };
};

struct LSPPreviousResultId {
URI uri;
std::string value;
};

using LSPPreviousResultIds = std::vector<LSPPreviousResultId>;

static constexpr auto LSPDocumentDiagnosticReportKindFull = "full";
static constexpr auto LSPDocumentDiagnosticReportKindUnchanged= "unchanged";

struct LSPFullDocumentDiagnosticReport {
URI uri;
std::string kind;
std::string resultId;
std::vector<LSPDiagnostic> items;
};

struct LSPWorkspaceDiagnosticReport {
std::unordered_map<URI, LSPFullDocumentDiagnosticReport> items;
};

} // namespace ecode

#endif // ECODE_LSPCLIENTPROTOCOL_HPP
2 changes: 1 addition & 1 deletion src/tools/ecode/plugins/pluginmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 } );
}

Expand Down
10 changes: 9 additions & 1 deletion src/tools/ecode/plugins/pluginmanager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand All @@ -108,7 +110,9 @@ enum class PluginMessageFormat {
ShowDocument,
SymbolInformation,
DiagnosticsCodeAction,
FoldingRanges
FoldingRanges,
WorkspaceDiagnosticReport,
LSPClientServer,
};

class PluginIDType {
Expand Down Expand Up @@ -206,6 +210,10 @@ struct PluginMessage {
return *static_cast<const LSPDiagnosticsCodeAction*>( data );
}

const LSPWorkspaceDiagnosticReport& asLSPWorkspaceDiagnosticReport() const {
return *static_cast<const LSPWorkspaceDiagnosticReport*>( data );
}

const PluginIDType& asPluginID() const { return *static_cast<const PluginIDType*>( data ); }

bool isResponse() const { return -1 != responseID && 0 != responseID; }
Expand Down

0 comments on commit 0e97236

Please sign in to comment.