diff --git a/bin/assets/plugins/lspclient.json b/bin/assets/plugins/lspclient.json index deb538642..4a93edb09 100644 --- a/bin/assets/plugins/lspclient.json +++ b/bin/assets/plugins/lspclient.json @@ -169,6 +169,20 @@ "command": "OmniSharp -lsp", "file_patterns": ["%.cs$", "%.csx$"], "rootIndicationFileNames": ["%.sln$"] + }, + { + "language": "vue", + "name": "vls", + "url": "https://github.com/vuejs/vetur/tree/master/server", + "command": "vls --stdio", + "file_patterns": ["%.vue$"] + }, + { + "language": "java", + "name": "jdtls", + "url": "https://github.com/eclipse/eclipse.jdt.ls", + "command": "jdtls", + "file_patterns": ["%.java$"] } ] } diff --git a/include/eepp/ui/doc/syntaxdefinition.hpp b/include/eepp/ui/doc/syntaxdefinition.hpp index 640607634..f655d053d 100644 --- a/include/eepp/ui/doc/syntaxdefinition.hpp +++ b/include/eepp/ui/doc/syntaxdefinition.hpp @@ -75,11 +75,15 @@ class EE_API SyntaxDefinition { const std::string& getLSPName() const; - void setVisible( bool visible ); + SyntaxDefinition& setVisible( bool visible ); bool isVisible() const; - protected: + bool getAutoCloseXMLTags() const; + + SyntaxDefinition& setAutoCloseXMLTags(bool autoCloseXMLTags); + + protected: std::string mLanguageName; String::HashType mLanguageId; std::vector mFiles; @@ -88,6 +92,7 @@ class EE_API SyntaxDefinition { std::string mComment; std::vector mHeaders; std::string mLSPName; + bool mAutoCloseXMLTags{ false }; bool mVisible{ true }; }; diff --git a/include/eepp/ui/doc/syntaxdefinitionmanager.hpp b/include/eepp/ui/doc/syntaxdefinitionmanager.hpp index 27cf5ef28..e0d9ee8f5 100644 --- a/include/eepp/ui/doc/syntaxdefinitionmanager.hpp +++ b/include/eepp/ui/doc/syntaxdefinitionmanager.hpp @@ -153,6 +153,8 @@ class EE_API SyntaxDefinitionManager { void addNelua(); void addTeal(); + + void addVue(); }; }}} // namespace EE::UI::Doc diff --git a/include/eepp/ui/uimenucheckbox.hpp b/include/eepp/ui/uimenucheckbox.hpp index 89ba84ded..9a17d0813 100644 --- a/include/eepp/ui/uimenucheckbox.hpp +++ b/include/eepp/ui/uimenucheckbox.hpp @@ -37,7 +37,7 @@ class EE_API UIMenuCheckBox : public UIMenuItem { UISkin* mSkinActive; UISkin* mSkinInactive; - virtual Uint32 onMouseUp( const Vector2i& position, const Uint32& flags ); + Uint32 onMessage( const NodeMessage* msg ); virtual void onStateChange(); }; diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index c6387f05f..3755c69ab 100644 --- a/projects/linux/ee.creator.user +++ b/projects/linux/ee.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -1204,7 +1204,6 @@ ecode-debug ProjectExplorer.CustomExecutableRunConfiguration - ../ true false false @@ -1431,9 +1430,109 @@ 21 + + ProjectExplorer.Project.Target.1 + + Desktop + Replacement for "Desktop" + Replacement for "Desktop" + {6d057187-158a-4883-8d5b-d470a6b6b025} + 0 + 0 + 0 + + /home/programming/eepp/projects/linux + + + + all + + true + GenericProjectManager.GenericMakeStep + + 1 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + + clean + + true + GenericProjectManager.GenericMakeStep + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Default + GenericProjectManager.GenericBuildConfiguration + + 1 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + false + /usr/bin/kcachegrind + 2 + 2 + true + true + /usr/bin/valgrind + + 11 + 14 + 12 + 13 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 0 + 1 + + + 2 + + ProjectExplorer.CustomExecutableRunConfiguration + + false + true + false + true + + 1 + + ProjectExplorer.Project.TargetCount - 1 + 2 ProjectExplorer.Project.Updater.FileVersion diff --git a/src/eepp/ui/doc/syntaxdefinition.cpp b/src/eepp/ui/doc/syntaxdefinition.cpp index 5d9a3a45c..9f7cc7bec 100644 --- a/src/eepp/ui/doc/syntaxdefinition.cpp +++ b/src/eepp/ui/doc/syntaxdefinition.cpp @@ -115,14 +115,24 @@ const std::string& SyntaxDefinition::getLSPName() const { return mLSPName; } -void SyntaxDefinition::setVisible( bool visible ) { +SyntaxDefinition& SyntaxDefinition::setVisible( bool visible ) { mVisible = visible; + return *this; } bool SyntaxDefinition::isVisible() const { return mVisible; } +bool SyntaxDefinition::getAutoCloseXMLTags() const { + return mAutoCloseXMLTags; +} + +SyntaxDefinition& SyntaxDefinition::setAutoCloseXMLTags( bool autoCloseXMLTags ) { + mAutoCloseXMLTags = autoCloseXMLTags; + return *this; +} + const std::string& SyntaxDefinition::getLanguageName() const { return mLanguageName; } diff --git a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp index 505932ed4..fbc1fb3cd 100644 --- a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp +++ b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp @@ -124,6 +124,8 @@ SyntaxDefinitionManager::SyntaxDefinitionManager() { addNelua(); addTeal(); + + addVue(); } void SyntaxDefinitionManager::addPlainText() { @@ -152,7 +154,8 @@ void SyntaxDefinitionManager::addXML() { }, {}, "", - { "<%?xml" } } ); + { "<%?xml" } } ) + .setAutoCloseXMLTags( true ); } void SyntaxDefinitionManager::addHTML() { @@ -186,7 +189,8 @@ void SyntaxDefinitionManager::addHTML() { }, {}, "", - { "" } } ); + { "" } } ) + .setAutoCloseXMLTags( true ); } void SyntaxDefinitionManager::addCSS() { @@ -880,7 +884,8 @@ void SyntaxDefinitionManager::addPHP() { }, {}, "", - { "^#!.*[ /]php" } } ); + { "^#!.*[ /]php" } } ) + .setAutoCloseXMLTags( true ); add( { "PHPCore", {}, @@ -3863,6 +3868,62 @@ void SyntaxDefinitionManager::addTeal() { { "^#!.*[ /]tl" } } ); } +void SyntaxDefinitionManager::addVue() { + add( { "Vue-HTML", + {}, + { + { { "%{%{%{", "%}%}%}" }, "function", "JavaScript" }, + { { "%{%{", "%}%}" }, "function", "JavaScript" }, + { { "" }, "comment" }, + { { "%f[^>][^<]", "%f[<]" }, "normal" }, + { { "\"", "\"", "\\" }, "string" }, + { { "'", "'", "\\" }, "string" }, + { { "0x[%da-fA-F]+" }, "number" }, + { { "-?%d+[%d%.]*f?" }, "number" }, + { { "-?%.?%d+f?" }, "number" }, + { { "%f[^<]![%a_][%w%_%-]*" }, "keyword2" }, + { { "%f[^<][%a_][%w%_%-]*" }, "function" }, + { { "%f[^<]/[%a_][%w%_%-]*" }, "function" }, + { { "[%a_][%w_]*" }, "keyword" }, + { { "[/<>=]" }, "operator" }, + }, + {}, + "", + {} } ) + .setVisible( false ) + .setAutoCloseXMLTags( true ); + + add( { "Vue", + { "%.vue?$" }, + { + { { "<%s*[sS][cC][rR][iI][pP][tT]%s*>", "<%s*/%s*[sS][cC][rR][iI][pP][tT]>" }, + "function", + "JavaScript" }, + { { "<%s*[sS][tT][yY][lL][eE][^>]*>", "<%s*/%s*[sS][tT][yY][lL][eE]%s*>" }, + "function", + "CSS" }, + { { "<%s*[tT][eE][mM][pP][lL][aA][tT][eE][^>]*>", + "<%s*/%s*[tT][eE][mM][pP][lL][aA][tT][eE]%s*>" }, + "function", + "Vue-HTML" }, + { { "" }, "comment" }, + { { "%f[^>][^<]", "%f[<]" }, "normal" }, + { { "\"", "\"", "\\" }, "string" }, + { { "'", "'", "\\" }, "string" }, + { { "0x[%da-fA-F]+" }, "number" }, + { { "-?%d+[%d%.]*f?" }, "number" }, + { { "-?%.?%d+f?" }, "number" }, + { { "%f[^<]![%a_][%w%_%-]*" }, "keyword2" }, + { { "%f[^<][%a_][%w%_%-]*" }, "function" }, + { { "%f[^<]/[%a_][%w%_%-]*" }, "function" }, + { { "[%a_][%w_]*" }, "keyword" }, + { { "[/<>=]" }, "operator" }, + }, + {}, + "", + {} } ); +} + SyntaxDefinition& SyntaxDefinitionManager::add( SyntaxDefinition&& syntaxStyle ) { mDefinitions.emplace_back( std::move( syntaxStyle ) ); return mDefinitions.back(); diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index daae32f3d..a50e4cfc5 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -3430,11 +3430,8 @@ bool UICodeEditor::checkAutoCloseXMLTag( const String& text ) { return false; if ( line[start.column() - 1] != '>' || ( line.size() > 2 && line[start.column() - 2] == '/' ) ) return false; - // Only close tags if the current line syntax is XML or HTML const SyntaxDefinition& definition = mHighlighter.getSyntaxDefinitionFromTextPosition( start ); - const String::HashType xmlType = String::hash( "xml" ); - const String::HashType htmlType = String::hash( "html" ); - if ( definition.getLanguageId() != xmlType && definition.getLanguageId() != htmlType ) + if ( !definition.getAutoCloseXMLTags() ) return false; size_t foundOpenPos = line.find_last_of( "<", start.column() - 1 ); if ( foundOpenPos == String::InvalidPos || start.column() - foundOpenPos < 1 ) diff --git a/src/eepp/ui/uimenu.cpp b/src/eepp/ui/uimenu.cpp index 10fb6dd07..fc7366da2 100644 --- a/src/eepp/ui/uimenu.cpp +++ b/src/eepp/ui/uimenu.cpp @@ -524,8 +524,13 @@ Uint32 UIMenu::onKeyDown( const KeyEvent& event ) { if ( nullptr != mItemSelected && nullptr != getEventDispatcher() ) { mItemSelected->sendMouseEvent( Event::MouseClick, getEventDispatcher()->getMousePos(), EE_BUTTON_LMASK ); - NodeMessage msg( mItemSelected, NodeMessage::MouseUp, EE_BUTTON_LMASK ); - mItemSelected->messagePost( &msg ); + if ( mItemSelected ) { + NodeMessage msg( mItemSelected, NodeMessage::MouseUp, EE_BUTTON_LMASK ); + mItemSelected->messagePost( &msg ); + } + if ( mItemSelected ) { + mItemSelected->forceKeyDown( event ); + } } break; default: diff --git a/src/eepp/ui/uimenucheckbox.cpp b/src/eepp/ui/uimenucheckbox.cpp index 0b4877f77..977df0730 100644 --- a/src/eepp/ui/uimenucheckbox.cpp +++ b/src/eepp/ui/uimenucheckbox.cpp @@ -107,13 +107,15 @@ void UIMenuCheckBox::switchActive() { setActive( !mActive ); } -Uint32 UIMenuCheckBox::onMouseUp( const Vector2i& Pos, const Uint32& Flags ) { - UIMenuItem::onMouseUp( Pos, Flags ); - - if ( getParent()->isVisible() && ( Flags & EE_BUTTONS_LRM ) ) - switchActive(); - - return 1; +Uint32 UIMenuCheckBox::onMessage( const NodeMessage* msg ) { + switch ( msg->getMsg() ) { + case NodeMessage::MouseUp: { + if ( msg->getFlags() & EE_BUTTON_LMASK ) + switchActive(); + break; + } + } + return 0; } void UIMenuCheckBox::onStateChange() { diff --git a/src/eepp/ui/uimenuitem.cpp b/src/eepp/ui/uimenuitem.cpp index f4a35ec81..8487c9458 100644 --- a/src/eepp/ui/uimenuitem.cpp +++ b/src/eepp/ui/uimenuitem.cpp @@ -1,5 +1,8 @@ #include #include +#include +#include +#include namespace EE { namespace UI { @@ -69,8 +72,10 @@ Uint32 UIMenuItem::onMouseLeave( const Vector2i& pos, const Uint32& flags ) { } Uint32 UIMenuItem::onMouseClick( const Vector2i&, const Uint32& flags ) { - if ( ( flags & EE_BUTTON_LMASK ) && ( !mOnShouldCloseCb || mOnShouldCloseCb( this ) ) ) + if ( !getUISceneNode()->getWindow()->getInput()->isShiftPressed() && + ( flags & EE_BUTTON_LMASK ) && ( !mOnShouldCloseCb || mOnShouldCloseCb( this ) ) ) { getParent()->asType()->backpropagateHide(); + } return 1; } diff --git a/src/thirdparty/efsw b/src/thirdparty/efsw index 23f603887..3fd18f71b 160000 --- a/src/thirdparty/efsw +++ b/src/thirdparty/efsw @@ -1 +1 @@ -Subproject commit 23f6038879bdb2223ddebc6459618593565345e8 +Subproject commit 3fd18f71b50befb8b1b3e221eceefc55500a2e75 diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 8bbf64cfb..d86ce65f2 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -2894,7 +2894,7 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe #endif mNotificationCenter = std::make_unique( - mUISceneNode->find( "notification_center" ) ); + mUISceneNode->find( "notification_center" ), mPluginManager.get() ); mDocSearchController = std::make_unique( mSplitter, this ); mDocSearchController->initSearchBar( mUISceneNode->find( "search_bar" ), diff --git a/src/tools/ecode/notificationcenter.cpp b/src/tools/ecode/notificationcenter.cpp index e44a07b6d..45aa3738b 100644 --- a/src/tools/ecode/notificationcenter.cpp +++ b/src/tools/ecode/notificationcenter.cpp @@ -2,9 +2,28 @@ namespace ecode { -NotificationCenter::NotificationCenter( UILayout* layout ) : mLayout( layout ) {} +NotificationCenter::NotificationCenter( UILayout* layout, PluginManager* pluginManager ) : + mLayout( layout ), mPluginManager( pluginManager ) { + mPluginManager->subscribeMessages( + "notificationcenter", [&]( const PluginMessage& msg ) -> PluginRequestHandle { + if ( !msg.isBroadcast() ) + return {}; + if ( msg.type == PluginMessageType::ShowMessage ) { + auto sm = msg.asShowMessage(); + if ( !sm.message.empty() ) + addNotification( sm.message, Seconds( 10 ) ); + } else if ( msg.type == PluginMessageType::ShowDocument ) { + auto sd = msg.asShowDocument(); + if ( !sd.uri.empty() ) + addShowRequest( sd.uri.toString(), + mLayout->getUISceneNode()->i18n( "open", "Open" ), + Seconds( 10 ) ); + } + return {}; + } ); +} -UITextView* NotificationCenter::addNotification( const String& text ) { +UITextView* NotificationCenter::addNotification( const String& text, const Time& delay ) { UITextView* tv = UITextView::New(); tv->addEventListener( Event::MouseClick, [tv]( const Event* event ) { const MouseEvent* mouseEvent = static_cast( event ); @@ -17,10 +36,39 @@ UITextView* NotificationCenter::addNotification( const String& text ) { tv->setText( text ); tv->addClass( "notification" ); Action* sequence = Actions::Sequence::New( - { Actions::FadeIn::New( Seconds( 0.125 ) ), Actions::Delay::New( Seconds( 2.5 ) ), + { Actions::FadeIn::New( Seconds( 0.125 ) ), Actions::Delay::New( delay ), Actions::FadeOut::New( Seconds( 0.125 ) ), Actions::Close::New() } ); tv->runAction( sequence ); return tv; } +UILinearLayout* NotificationCenter::addShowRequest( const String& uri, const String& actionText, + const Time& delay ) { + const std::string layout = R"xml( + + + + + + + )xml"; + UILinearLayout* lay = mLayout->getUISceneNode() + ->loadLayoutFromString( layout, mLayout ) + ->asType(); + UITextView* tv = lay->findByType( UI_TYPE_TEXTVIEW )->asType(); + tv->setText( mLayout->getUISceneNode()->i18n( + "open_url_question", String::format( "Open URL\n%s?", uri.toUtf8().c_str() ) ) ); + UIPushButton* pb = lay->findByType( UI_TYPE_PUSHBUTTON )->asType(); + pb->setText( actionText ); + pb->on( Event::MouseClick, [uri]( const Event* event ) { + if ( event->asMouseEvent()->getFlags() & EE_BUTTON_LMASK ) + Engine::instance()->openURI( uri ); + } ); + Action* sequence = Actions::Sequence::New( + { Actions::FadeIn::New( Seconds( 0.125 ) ), Actions::Delay::New( delay ), + Actions::FadeOut::New( Seconds( 0.125 ) ), Actions::Close::New() } ); + lay->runAction( sequence ); + return lay; } + +} // namespace ecode diff --git a/src/tools/ecode/notificationcenter.hpp b/src/tools/ecode/notificationcenter.hpp index f1193d943..866f88c00 100644 --- a/src/tools/ecode/notificationcenter.hpp +++ b/src/tools/ecode/notificationcenter.hpp @@ -1,18 +1,23 @@ #ifndef ECODE_NOTIFICATIONCENTER_HPP #define ECODE_NOTIFICATIONCENTER_HPP +#include "plugins/pluginmanager.hpp" #include namespace ecode { class NotificationCenter { public: - NotificationCenter( UILayout* layout ); + NotificationCenter( UILayout* layout, PluginManager* pluginManager ); - UITextView* addNotification( const String& text ); + UITextView* addNotification( const String& text, const Time& delay = Seconds( 2.5 ) ); + + UILinearLayout* addShowRequest( const String& uri, const String& actionText, + const Time& delay = Seconds( 2.5 ) ); protected: UILayout* mLayout{ nullptr }; + PluginManager* mPluginManager{ nullptr }; }; } // namespace ecode diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.cpp b/src/tools/ecode/plugins/lsp/lspclientserver.cpp index f78d6065e..3290726ac 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.cpp @@ -47,6 +47,7 @@ static const char* MEMBER_TARGET_RANGE = "targetRange"; static const char* MEMBER_TARGET_SELECTION_RANGE = "targetSelectionRange"; static const char* MEMBER_PREVIOUS_RESULT_ID = "previousResultId"; static const char* MEMBER_QUERY = "query"; +static const char* MEMBER_SUCCESS = "success"; static json newRequest( const std::string& method, const json& params = json{} ) { json j; @@ -74,6 +75,18 @@ static json newEmptyResult( const PluginIDType& id ) { return j; } +static json newSuccessResult( const PluginIDType& id, bool success = true ) { + json j; + json res; + res[MEMBER_SUCCESS] = success; + j[MEMBER_RESULT] = res; + if ( id.isInteger() ) + j[MEMBER_ID] = id.asInt(); + else + j[MEMBER_ID] = id.asString(); + return j; +} + static std::string jsonString( const json& container, const std::string& member, const std::string& def ) { return container.is_object() && container.contains( member ) && container[member].is_string() @@ -809,6 +822,33 @@ parseSelectionRanges( const json& selectionRanges ) { return ret; } +static LSPShowMessageParams parseMessageRequest( const json& json ) { + LSPShowMessageParams msg; + msg.type = (LSPMessageType)json["type"].get(); + msg.message = json["message"]; + if ( json.contains( "actions" ) && json["actions"].is_array() ) { + LSPMessageActionItem item; + auto& actions = json["actions"]; + for ( const auto& ma : actions ) { + if ( ma.contains( "title" ) ) + item.title = ma["title"]; + } + if ( !item.title.empty() ) + msg.actions.emplace_back( item ); + } + return msg; +} + +static LSPShowDocumentParams parseShowDocument( const json& json ) { + LSPShowDocumentParams params; + params.uri = URI( json.value( "uri", "" ) ); + params.external = json.value( "external", false ); + params.takeFocus = json.value( "takeFocus", false ); + if ( json.contains( "selection" ) ) + params.selection = parseRange( json["selection"] ); + return params; +} + void LSPClientServer::initialize() { json codeAction{ { "codeActionLiteralSupport", @@ -824,6 +864,12 @@ void LSPClientServer::initialize() { json completionItem{ { "snippetSupport", true } }; + json showMessage; + showMessage["messageActionItem"] = json{ { "additionalPropertiesSupport", false } }; + + json showDocument; + showDocument["support"] = true; + json capabilities{ { "textDocument", json{ @@ -837,7 +883,9 @@ void LSPClientServer::initialize() { { "hover", json{ { "contentFormat", { "plaintext", "markdown" } } } }, { "completion", completionItem }, } }, - { "window", json{ { "workDoneProgress", true } } }, + { "window", json{ { "workDoneProgress", true }, + { "showMessage", showMessage }, + { "showDocument", showDocument } } }, //{ "workspace", json{ { "workspaceFolders", true }, { "configuration", false } } }, { "general", json{ { "positionEncodings", json::array( { "utf-32" } ) } } } }; @@ -856,7 +904,8 @@ void LSPClientServer::initialize() { auto rootUri = rootPath.toString(); params["rootPath"] = authAndPath; params["rootUri"] = rootUri; - params["workspaceFolders"] = toJson( { LSPWorkspaceFolder{ rootUri, FileSystem::fileNameFromPath( rootUri ) } } ); + params["workspaceFolders"] = + toJson( { LSPWorkspaceFolder{ rootUri, FileSystem::fileNameFromPath( rootUri ) } } ); write( newRequest( "initialize", params ), @@ -1213,11 +1262,31 @@ void LSPClientServer::processNotification( const json& msg ) { if ( method == "textDocument/publishDiagnostics" ) { publishDiagnostics( msg ); return; - } else if ( method == ( "window/showMessage" ) ) { - // showMessage( msg ); - } else if ( method == ( "window/logMessage" ) ) { - // logMessage( msg ); - } else if ( method == ( "$/progress" ) ) { + } else if ( method == ( "window/showMessage" ) && msg.contains( MEMBER_PARAMS ) ) { + auto msgReq = parseMessageRequest( msg[MEMBER_PARAMS] ); + mManager->getPluginManager()->sendBroadcast( PluginMessageType::ShowMessage, + PluginMessageFormat::ShowMessage, &msgReq ); + return; + } else if ( method == ( "window/logMessage" ) && msg.contains( MEMBER_PARAMS ) ) { + auto lm = parseMessageRequest( msg[MEMBER_PARAMS] ); + if ( !lm.message.empty() ) { + switch ( lm.type ) { + case LSPMessageType::Log: + case LSPMessageType::Info: + Log::notice( lm.message ); + break; + case LSPMessageType::Warning: + Log::warning( lm.message ); + break; + case LSPMessageType::Error: + Log::error( lm.message ); + break; + default: + break; + } + } + return; + } else if ( method == ( "$/progress" ) && msg.contains( MEMBER_PARAMS ) ) { workDoneProgress( parseWorkDone( msg[MEMBER_PARAMS] ) ); return; } @@ -1230,11 +1299,28 @@ void LSPClientServer::processRequest( const json& msg ) { msg.dump().c_str() ); auto method = msg[MEMBER_METHOD].get(); auto msgid = getID( msg ); - // auto params = msg[MEMBER_PARAMS]; - // bool handled = false; if ( method == "window/workDoneProgress/create" || method == "client/registerCapability" ) { write( newEmptyResult( msgid ) ); return; + } else if ( method == "window/showMessageRequest" ) { + auto msgReq = parseMessageRequest( msg[MEMBER_PARAMS] ); + mManager->getPluginManager()->sendBroadcast( PluginMessageType::ShowMessage, + PluginMessageFormat::ShowMessage, &msgReq ); + write( newEmptyResult( msgid ) ); + return; + } else if ( method == "window/showDocument" ) { + auto showDoc = parseShowDocument( msg[MEMBER_PARAMS] ); + if ( !showDoc.external ) { + LSPLocation loc; + loc.uri = showDoc.uri; + loc.range = showDoc.selection; + mManager->goToLocation( loc ); + } else { + mManager->getPluginManager()->sendBroadcast( + PluginMessageType::ShowDocument, PluginMessageFormat::ShowDocument, &showDoc ); + } + write( newSuccessResult( msgid ) ); + return; } write( newError( LSPErrorCode::MethodNotFound, method ), nullptr, nullptr, msgid ); } diff --git a/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp b/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp index 5ec807f40..b13a82659 100644 --- a/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp @@ -90,14 +90,15 @@ void LSPClientServerManager::tryRunServer( const std::shared_ptr& LSPClientServer* server = nullptr; if ( clientIt == mClients.end() ) { std::unique_ptr serverUP = runLSPServer( id, lsp, rootPath ); - if ( ( server = serverUP.get() ) ) + if ( ( server = serverUP.get() ) ) { mClients[id] = std::move( serverUP ); + if ( !mLSPWorkspaceFolder.uri.empty() ) + server->didChangeWorkspaceFolders( { mLSPWorkspaceFolder }, {} ); + } } else { server = clientIt->second.get(); } if ( server ) { - if ( !mLSPWorkspaceFolder.uri.empty() ) - server->didChangeWorkspaceFolders( { mLSPWorkspaceFolder }, {} ); server->registerDoc( doc ); } } diff --git a/src/tools/ecode/plugins/lsp/lspprotocol.hpp b/src/tools/ecode/plugins/lsp/lspprotocol.hpp index af2fba807..58c2c61ff 100644 --- a/src/tools/ecode/plugins/lsp/lspprotocol.hpp +++ b/src/tools/ecode/plugins/lsp/lspprotocol.hpp @@ -115,9 +115,14 @@ struct LSPServerCapabilities { enum class LSPMessageType { Error = 1, Warning = 2, Info = 3, Log = 4 }; +struct LSPMessageActionItem { + std::string title; +}; + struct LSPShowMessageParams { - LSPMessageType type; + LSPMessageType type{ LSPMessageType::Log }; std::string message; + std::vector actions; }; struct LSPTextDocumentContentChangeEvent { @@ -409,6 +414,13 @@ struct LSPConverter { } }; +struct LSPShowDocumentParams { + URI uri; + bool external{ true }; + bool takeFocus{ false }; + TextRange selection; +}; + } // namespace ecode #endif // ECODE_LSPCLIENTPROTOCOL_HPP diff --git a/src/tools/ecode/plugins/pluginmanager.hpp b/src/tools/ecode/plugins/pluginmanager.hpp index 2f938e6dc..2cec17148 100644 --- a/src/tools/ecode/plugins/pluginmanager.hpp +++ b/src/tools/ecode/plugins/pluginmanager.hpp @@ -70,6 +70,8 @@ enum class PluginMessageType { FindAndOpenClosestURI, // Request a component to find and open the closest path from an URI DocumentFormatting, // Request the LSP Server to format a document SymbolReference, // Request the LSP Server to find a symbol reference in the project + ShowMessage, // The LSP server sends a request to the client to show a message on screen + ShowDocument, // The LSP server sends a request to the client to show a document Undefined }; @@ -79,7 +81,9 @@ enum class PluginMessageFormat { CodeCompletion, LanguageServerCapabilities, SignatureHelp, - ProjectSearchResult + ProjectSearchResult, + ShowMessage, + ShowDocument, }; class PluginIDType { @@ -159,6 +163,14 @@ struct PluginMessage { return *static_cast( data ); } + const LSPShowMessageParams& asShowMessage() const { + return *static_cast( data ); + } + + const LSPShowDocumentParams& asShowDocument() const { + return *static_cast( data ); + } + const PluginIDType& asPluginID() const { return *static_cast( data ); } bool isResponse() const { return -1 != responseID && 0 != responseID; }