mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-27 08:37:58 +03:00
Started implementing LSP workspace diagnostic to find that not a single LSP implements it, so I just wasted 2 hours of my life. I'll keep the base structure for the future.
This commit is contained in:
@@ -55,7 +55,6 @@ void addJSX() {
|
||||
{ "NaN", "keyword2" }, { "this", "keyword2" },
|
||||
},
|
||||
"//" } )
|
||||
.setAutoCloseXMLTags( true )
|
||||
.setLSPName( "javascriptreact" );
|
||||
|
||||
sd.setFoldRangeType( FoldRangeType::Braces ).setFoldBraces( { { '{', '}' } } );
|
||||
|
||||
@@ -103,7 +103,6 @@ void addTypeScript() {
|
||||
"//" } )
|
||||
.setSymbols( ts.getSymbols() )
|
||||
.setLSPName( "typescriptreact" )
|
||||
.setAutoCloseXMLTags( true )
|
||||
.setFoldRangeType( FoldRangeType::Braces )
|
||||
.setFoldBraces( { { '{', '}' } } );
|
||||
;
|
||||
|
||||
@@ -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 &&
|
||||
@@ -938,6 +963,11 @@ PluginRequestHandle LSPClientPlugin::processMessage( const PluginMessage& msg )
|
||||
processFoldingRanges( msg );
|
||||
break;
|
||||
}
|
||||
case PluginMessageType::WorkspaceDiagnostic:
|
||||
case PluginMessageType::LanguageServerReady: {
|
||||
processWorkspaceDiagnostic( msg );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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<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() )
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -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<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
|
||||
|
||||
@@ -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 } );
|
||||
}
|
||||
|
||||
|
||||
@@ -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<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; }
|
||||
|
||||
Reference in New Issue
Block a user