diff --git a/bin/assets/plugins/formatters.json b/bin/assets/plugins/formatters.json index 2ca2fbe3c..5efe32122 100644 --- a/bin/assets/plugins/formatters.json +++ b/bin/assets/plugins/formatters.json @@ -24,6 +24,10 @@ "command": "ktlint -F $FILENAME", "type": "inplace" }, + { + "file_patterns": ["%.rs"], + "command": "rustfmt --emit stdout --color never $FILENAME" + }, { "file_patterns": ["%.json$", "%.cson$"], "command": "json", diff --git a/bin/assets/plugins/lspclient.json b/bin/assets/plugins/lspclient.json index fc5746090..e1a8ebf06 100644 --- a/bin/assets/plugins/lspclient.json +++ b/bin/assets/plugins/lspclient.json @@ -66,9 +66,9 @@ }, { "language": "rust", - "name": "rust-language-server", - "url": "https://github.com/rust-lang/rls", - "command": "rls", + "name": "rust-analyzer", + "url": "https://rust-analyzer.github.io", + "command": "rust-analyzer", "file_patterns": ["%.rs$"] }, { diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 51ff39a80..cfa73e498 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -532,10 +532,8 @@ App::~App() { delete mFileSystemListener; mFileSystemListener = nullptr; } + mPluginManager.reset(); eeSAFE_DELETE( mSplitter ); - eeSAFE_DELETE( mAutoCompletePlugin ); - eeSAFE_DELETE( mLinterPlugin ); - eeSAFE_DELETE( mFormatterPlugin ); eeSAFE_DELETE( mConsole ); } diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index e21279a2e..0a95161d5 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -255,9 +255,6 @@ class App : public UICodeEditorSplitter::Client { std::string mKeybindingsPath; std::string mResPath; Float mDisplayDPI{ 96 }; - AutoCompletePlugin* mAutoCompletePlugin{ nullptr }; - LinterPlugin* mLinterPlugin{ nullptr }; - FormatterPlugin* mFormatterPlugin{ nullptr }; std::shared_ptr mThreadPool; std::shared_ptr mDirTree; UITreeView* mProjectTreeView{ nullptr }; diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp index fd937848f..fa7c5e01d 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp @@ -170,10 +170,6 @@ bool AutoCompletePlugin::onKeyDown( UICodeEditor* editor, const KeyEvent& event return false; } -bool AutoCompletePlugin::onKeyUp( UICodeEditor*, const KeyEvent& ) { - return false; -} - bool AutoCompletePlugin::onTextInput( UICodeEditor* editor, const TextInputEvent& ) { std::string partialSymbol( getPartialSymbol( &editor->getDocument() ) ); if ( partialSymbol.size() >= 3 ) { @@ -252,9 +248,6 @@ void AutoCompletePlugin::update( UICodeEditor* ) { } } -void AutoCompletePlugin::preDraw( UICodeEditor*, const Vector2f&, const Float&, - const TextPosition& ) {} - void AutoCompletePlugin::postDraw( UICodeEditor* editor, const Vector2f& startScroll, const Float& lineHeight, const TextPosition& cursor ) { std::vector suggestions; diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp index c3b246b25..c8b7ccbd7 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp @@ -43,10 +43,8 @@ class AutoCompletePlugin : public UICodeEditorPlugin { void onRegister( UICodeEditor* ); void onUnregister( UICodeEditor* ); bool onKeyDown( UICodeEditor*, const KeyEvent& ); - bool onKeyUp( UICodeEditor*, const KeyEvent& ); bool onTextInput( UICodeEditor*, const TextInputEvent& ); void update( UICodeEditor* ); - void preDraw( UICodeEditor*, const Vector2f&, const Float&, const TextPosition& ); void postDraw( UICodeEditor*, const Vector2f& startScroll, const Float& lineHeight, const TextPosition& cursor ); bool onMouseDown( UICodeEditor*, const Vector2i&, const Uint32& ); diff --git a/src/tools/ecode/plugins/lsp/lspclientprotocol.hpp b/src/tools/ecode/plugins/lsp/lspclientprotocol.hpp index eff53eb68..31102cdca 100644 --- a/src/tools/ecode/plugins/lsp/lspclientprotocol.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientprotocol.hpp @@ -295,6 +295,8 @@ struct LSPCompletionItem { LSPMarkupContent documentation; std::string sortText; std::string insertText; + std::string filterText; + LSPTextEdit textEdit; std::vector additionalTextEdits; }; diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.cpp b/src/tools/ecode/plugins/lsp/lspclientserver.cpp index 5a5e8f718..b978d7c25 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.cpp @@ -47,13 +47,20 @@ static const char* MEMBER_TARGET_SELECTION_RANGE = "targetSelectionRange"; // static const char* MEMBER_PREVIOUS_RESULT_ID = "previousResultId"; // static const char* MEMBER_QUERY = "query"; -static json newRequest( const std::string& method, const json& params = {} ) { +static json newRequest( const std::string& method, const json& params = json{} ) { json j; j[MEMBER_METHOD] = method; j[MEMBER_PARAMS] = params.empty() ? json() : params; return j; } +static json newResponse( const std::string& method, const int& id ) { + json j; + j[MEMBER_METHOD] = method; + j[MEMBER_ID] = id; + return j; +} + static json textDocumentURI( const URI& document ) { return json{ { MEMBER_URI, document.toString() } }; } @@ -181,10 +188,10 @@ static void fromJson( std::vector& trigger, const json& json ) { static void fromJson( LSPCompletionOptions& options, const json& json ) { if ( !json.empty() && json.is_object() ) { - auto ob = json; options.provider = true; - options.resolveProvider = ob["resolveProvider"].get(); - fromJson( options.triggerCharacters, ob["triggerCharacters"] ); + if ( json.contains( "resolveProvider" ) && !json["resolveProvider"].is_null() ) + options.resolveProvider = json["resolveProvider"].get(); + fromJson( options.triggerCharacters, json["triggerCharacters"] ); } } @@ -362,15 +369,17 @@ static LSPResponseError parseResponseError( const json& v ) { return ret; } -static std::vector parseTextEdit( const json& result ) { +static LSPTextEdit parseTextEdit( const json& result ) { + LSPTextEdit edit; + edit.text = result.at( "newText" ).get(); + edit.range = parseRange( result.at( MEMBER_RANGE ) ); + return edit; +} + +static std::vector parseTextEditArray( const json& result ) { std::vector ret; - const auto textEdits = result; - for ( const auto& redit : textEdits ) { - auto edit = redit; - auto text = edit.at( "newText" ).get(); - auto range = parseRange( edit.at( MEMBER_RANGE ) ); - ret.push_back( { range, text } ); - } + for ( const auto& edit : result ) + ret.push_back( parseTextEdit( edit ) ); return ret; } @@ -386,7 +395,7 @@ static LSPTextDocumentEdit parseTextDocumentEdit( const json& result ) { LSPTextDocumentEdit ret; auto ob = result; fromJson( ret.textDocument, ob.at( "textDocument" ) ); - ret.edits = parseTextEdit( ob.at( "edits" ) ); + ret.edits = parseTextEditArray( ob.at( "edits" ) ); return ret; } @@ -395,7 +404,7 @@ static LSPWorkspaceEdit parseWorkSpaceEdit( const json& result ) { auto changes = result.at( "changes" ); for ( auto it = changes.begin(); it != changes.end(); ++it ) { ret.changes.insert( std::pair>( - URI( it.key() ), parseTextEdit( it.value() ) ) ); + URI( it.key() ), parseTextEditArray( it.value() ) ) ); } auto documentChanges = result.at( "documentChanges" ); // resourceOperations not supported for now @@ -584,40 +593,32 @@ static std::vector parseDocumentCompletion( const json& resul LSPMarkupContent doc = item.contains( MEMBER_DOCUMENTATION ) ? parseMarkupContent( item.at( MEMBER_DOCUMENTATION ) ) : LSPMarkupContent{}; - auto sortText = item.value( "sortText", "" ); - if ( sortText.empty() ) - sortText = label; - auto insertText = item.value( "insertText", "" ); - if ( insertText.empty() ) - insertText = label; - if ( item.contains( "textEdit" ) ) { - const auto& textEdit = item["textEdit"]; - if ( !textEdit.empty() ) { - auto newText = textEdit.value( "newText", "" ); - insertText = newText; - } - } + auto filterText = item.value( "filterText", label ); + auto insertText = item.value( "insertText", label ); + auto sortText = item.value( "sortText", label ); + LSPTextEdit textEdit; + if ( item.contains( "textEdit" ) ) + textEdit = parseTextEdit( item["textEdit"] ); auto kind = static_cast( item.value( MEMBER_KIND, 1 ) ); - const std::vector additionalTextEdits = item.contains( "additionalTextEdits" ) - ? parseTextEdit( item.at( "additionalTextEdits" ) ) + ? parseTextEditArray( item.at( "additionalTextEdits" ) ) : std::vector{}; - ret.push_back( { label, kind, detail, doc, sortText, insertText, - additionalTextEdits /*, textEdit*/ } ); + ret.push_back( { label, kind, detail, doc, sortText, insertText, filterText, textEdit, + additionalTextEdits } ); } return ret; } void LSPClientServer::initialize() { - json codeAction{ - { "codeActionLiteralSupport", json{ { "codeActionKind", json{ { "valueSet", {} } } } } } }; + json codeAction{ { "codeActionLiteralSupport", + json{ { "codeActionKind", json{ { "valueSet", json::array() } } } } } }; json semanticTokens{ { "requests", json{ { "range", true }, { "full", json{ { "delta", true } } } } }, { "tokenTypes", supportedSemanticTokenTypes() }, - { "tokenModifiers", {} }, + { "tokenModifiers", json::array() }, { "formats", { "relative" } }, }; @@ -690,7 +691,7 @@ LSPClientServer::~LSPClientServer() { bool LSPClientServer::start() { bool ret = mProcess.create( mLSP.command, Process::getDefaultOptions(), {}, mRootPath ); - if ( ret ) { + if ( ret && mProcess.isAlive() ) { mProcess.startAsyncRead( [this]( const char* bytes, size_t n ) { readStdOut( bytes, n ); }, [this]( const char* bytes, size_t n ) { readStdErr( bytes, n ); } ); @@ -761,6 +762,9 @@ LSPClientServer::RequestHandle LSPClientServer::write( const json& msg, const Js method = msg[MEMBER_METHOD].get(); else if ( msg.contains( MEMBER_MESSAGE ) ) method = msg[MEMBER_MESSAGE]; + if ( method == "workspace/didChangeWorkspaceFolders" && + !mCapabilities.workspaceFolders.supported ) + return ret; Log::info( "LSPClientServer server %s calling %s", mLSP.name.c_str(), method.c_str() ); Log::debug( "LSPClientServer server %s sending message:\n%s", mLSP.name.c_str(), sjson.c_str() ); @@ -977,6 +981,10 @@ void LSPClientServer::processRequest( const json& msg ) { auto msgid = msg[MEMBER_ID].get(); // auto params = msg[MEMBER_PARAMS]; // bool handled = false; + if ( method == "window/workDoneProgress/create" || method == "client/registerCapability" ) { + write( newResponse( method, msgid ) ); + return; + } write( newError( LSPErrorCode::MethodNotFound, method ), nullptr, nullptr, msgid ); } diff --git a/src/tools/ecode/plugins/pluginmanager.cpp b/src/tools/ecode/plugins/pluginmanager.cpp index 9db94c113..71cca2dc3 100644 --- a/src/tools/ecode/plugins/pluginmanager.cpp +++ b/src/tools/ecode/plugins/pluginmanager.cpp @@ -108,6 +108,13 @@ void PluginManager::setWorkspaceFolder( const std::string& workspaceFolder ) { json{ { "folder", mWorkspaceFolder } } ); } +void PluginManager::pushNotification( UICodeEditorPlugin* pluginWho, Notification notification, + const nlohmann::json& json ) const { + for ( const auto& plugin : mSubscribedPlugins ) + if ( pluginWho->getId() != plugin.first ) + plugin.second( notification, json ); +} + void PluginManager::subscribeNotifications( UICodeEditorPlugin* plugin, std::function cb ) const { diff --git a/src/tools/ecode/plugins/pluginmanager.hpp b/src/tools/ecode/plugins/pluginmanager.hpp index e03a7f2bb..5160f4e5d 100644 --- a/src/tools/ecode/plugins/pluginmanager.hpp +++ b/src/tools/ecode/plugins/pluginmanager.hpp @@ -104,6 +104,9 @@ class PluginManager { void setWorkspaceFolder( const std::string& workspaceFolder ); + void pushNotification( UICodeEditorPlugin* pluginWho, Notification, + const nlohmann::json& ) const; + void subscribeNotifications( UICodeEditorPlugin* plugin, std::function cb ) const;