diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index cac8560cc..14526a68c 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -845,6 +845,8 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { bool gutterSpaceExists( UICodeEditorPlugin* plugin ) const; bool topSpaceExists( UICodeEditorPlugin* plugin ) const; + + bool createContextMenu(); }; }} // namespace EE::UI diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index 101dd0d5c..b2d0ecd97 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -57,7 +57,7 @@ class EE_API UIWidget : public UINode { void tooltipRemove(); - UIWidget* setTooltipText( const String& Text ); + UIWidget* setTooltipText( const String& text ); String getTooltipText(); diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index ef751b5d6..e8f73f004 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -102,6 +102,7 @@ const std::map UICodeEditor::getDefaultKeybi { { KEY_UP, KEYMOD_LALT }, "add-cursor-above" }, { { KEY_DOWN, KEYMOD_LALT }, "add-cursor-below" }, { { KEY_ESCAPE }, "reset-cursor" }, + { { KEY_APPLICATION }, "open-context-menu" }, }; } @@ -163,6 +164,11 @@ UICodeEditor::UICodeEditor( const bool& autoRegisterBaseCommands, UICodeEditor( "codeeditor", autoRegisterBaseCommands, autoRegisterBaseKeybindings ) {} UICodeEditor::~UICodeEditor() { + if ( mCurrentMenu ) { + mCurrentMenu->clearEventListener(); + mCurrentMenu = nullptr; + } + for ( auto& plugin : mPlugins ) plugin->onUnregister( this ); @@ -970,6 +976,11 @@ void UICodeEditor::createDefaultContextMenuOptions( UIPopUpMenu* menu ) { } } +bool UICodeEditor::createContextMenu() { + Rectf pos( getScreenPosition( mDoc->getSelection().start() ) ); + return onCreateContextMenu( pos.getPosition().asInt(), 0 ); +} + bool UICodeEditor::onCreateContextMenu( const Vector2i& position, const Uint32& flags ) { if ( mCurrentMenu ) return false; @@ -991,12 +1002,13 @@ bool UICodeEditor::onCreateContextMenu( const Vector2i& position, const Uint32& } menu->setCloseOnHide( true ); - menu->addEventListener( Event::OnItemClicked, [&]( const Event* event ) { + menu->addEventListener( Event::OnItemClicked, [&, menu]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; UIMenuItem* item = event->getNode()->asType(); std::string txt( item->getId() ); mDoc.get()->execute( txt ); + menu->hide(); } ); Vector2f pos( position.asFloat() ); @@ -1004,6 +1016,10 @@ bool UICodeEditor::onCreateContextMenu( const Vector2i& position, const Uint32& UIMenu::findBestMenuPos( pos, menu ); menu->setPixelsPosition( pos ); menu->show(); + menu->addEventListener( Event::OnMenuHide, [&]( const Event* ) { + if ( !isClosing() ) + setFocus(); + } ); menu->addEventListener( Event::OnClose, [&]( const Event* ) { mCurrentMenu = nullptr; } ); mCurrentMenu = menu; return true; @@ -2862,6 +2878,7 @@ void UICodeEditor::registerCommands() { mDoc->setCommand( "copy-containing-folder-path", [&] { copyContainingFolderPath(); } ); mDoc->setCommand( "copy-file-path", [&] { copyFilePath(); } ); mDoc->setCommand( "find-replace", [&] { showFindReplace(); } ); + mDoc->setCommand( "open-context-menu", [&] { createContextMenu(); } ); mUnlockedCmd.insert( { "copy", "select-all" } ); } diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index 0a90aaafd..436ee0991 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -357,16 +357,16 @@ Uint32 UIWidget::onMouseLeave( const Vector2i& Pos, const Uint32& Flags ) { return UINode::onMouseLeave( Pos, Flags ); } -UIWidget* UIWidget::setTooltipText( const String& Text ) { - if ( NULL == mTooltip ) { // If the tooltip wasn't created it will avoid to create a new one if - // the string is "" - if ( Text.size() ) { +UIWidget* UIWidget::setTooltipText( const String& text ) { + // If the tooltip wasn't created it will avoid to create a new one if the string is "" + if ( NULL == mTooltip ) { + if ( !text.empty() ) { createTooltip(); - mTooltip->setText( Text ); + mTooltip->setText( text ); } } else { // but if it's created, i will allow it - mTooltip->setText( Text ); + mTooltip->setText( text ); } return this; diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index 70e681c8d..20a5bd905 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -226,8 +226,10 @@ void LSPClientPlugin::loadLSPConfig( std::vector& lsps, const std Time::fromString( config["server_close_after_idle_time"].get() ) ); } - if ( mKeyBindings.empty() ) + if ( mKeyBindings.empty() ) { mKeyBindings["lsp-go-to-definition"] = "f2"; + mKeyBindings["lsp-symbol-info"] = "f1"; + } if ( j.contains( "keybindings" ) ) { auto kb = j["keybindings"]; @@ -235,8 +237,9 @@ void LSPClientPlugin::loadLSPConfig( std::vector& lsps, const std if ( kb.contains( key ) ) mKeyBindings[key] = kb[key]; }; - auto list = { "lsp-go-to-definition", "lsp-go-to-declaration", "lsp-go-to-implementation", - "lsp-go-to-type-definition", "lsp-switch-header-source" }; + auto list = { "lsp-go-to-definition", "lsp-go-to-declaration", + "lsp-go-to-implementation", "lsp-go-to-type-definition", + "lsp-switch-header-source", "lsp-symbol-info" }; for ( const auto& key : list ) bindKey( key ); } @@ -376,11 +379,11 @@ void LSPClientPlugin::onRegister( UICodeEditor* editor ) { "textDocument/typeDefinition" ); } ); - editor->getDocument().setCommand( "lsp-switch-header-source", [&, editor]() { - auto* server = mClientManager.getOneLSPClientServer( editor ); - if ( server ) - server->switchSourceHeader( editor->getDocument().getURI() ); - } ); + editor->getDocument().setCommand( "lsp-switch-header-source", + [&, editor]() { switchSourceHeader( editor ); } ); + + editor->getDocument().setCommand( "lsp-symbol-info", + [&, editor]() { getSymbolInfo( editor ); } ); } std::vector listeners; @@ -400,6 +403,31 @@ void LSPClientPlugin::onRegister( UICodeEditor* editor ) { mDelayedDocs[&editor->getDocument()] = editor->getDocumentRef(); } +void LSPClientPlugin::switchSourceHeader( UICodeEditor* editor ) { + auto* server = mClientManager.getOneLSPClientServer( editor ); + if ( server ) + server->switchSourceHeader( editor->getDocument().getURI() ); +} + +void LSPClientPlugin::getSymbolInfo( UICodeEditor* editor ) { + auto server = mClientManager.getOneLSPClientServer( editor ); + if ( server == nullptr ) + return; + server->documentHover( + editor->getDocument().getURI(), editor->getDocument().getSelection().start(), + [&, editor]( const Int64&, const LSPHover& resp ) { + if ( resp.range.isValid() && !resp.contents.empty() && + !resp.contents[0].value.empty() ) { + editor->runOnMainThread( [editor, resp, this]() { + displayTooltip( + editor, resp, + editor->getScreenPosition( editor->getDocument().getSelection().start() ) + .getPosition() ); + } ); + } + } ); +} + void LSPClientPlugin::onUnregister( UICodeEditor* editor ) { for ( auto& kb : mKeyBindings ) { editor->getKeyBindings().removeCommandKeybind( kb.first ); @@ -442,6 +470,8 @@ bool LSPClientPlugin::onCreateContextMenu( UICodeEditor* editor, UIPopUpMenu* me }; auto cap = server->getCapabilities(); + addFn( "lsp-symbol-info", "Symbol Info" ); + if ( cap.definitionProvider ) addFn( "lsp-go-to-definition", "Go To Definition" ); @@ -461,14 +491,15 @@ bool LSPClientPlugin::onCreateContextMenu( UICodeEditor* editor, UIPopUpMenu* me } void LSPClientPlugin::hideTooltip( UICodeEditor* editor ) { - if ( editor && editor->getTooltip() && editor->getTooltip()->isVisible() ) { + UITooltip* tooltip = nullptr; + if ( editor && ( tooltip = editor->getTooltip() ) && tooltip->isVisible() ) { editor->setTooltipText( "" ); - editor->getTooltip()->hide(); + tooltip->hide(); // Restore old tooltip state - editor->getTooltip()->setFontStyle( mOldTextStyle ); - editor->getTooltip()->setHorizontalAlign( mOldTextAlign ); - editor->getTooltip()->setUsingCustomStyling( mOldUsingCustomStyling ); - editor->getTooltip()->setDontAutoHideOnMouseMove( mOldDontAutoHideOnMouseMove ); + tooltip->setFontStyle( mOldTextStyle ); + tooltip->setHorizontalAlign( mOldTextAlign ); + tooltip->setUsingCustomStyling( mOldUsingCustomStyling ); + tooltip->setDontAutoHideOnMouseMove( mOldDontAutoHideOnMouseMove ); } } @@ -483,6 +514,45 @@ void LSPClientPlugin::tryHideTooltip( UICodeEditor* editor, const Vector2i& posi hideTooltip( editor ); } +void LSPClientPlugin::displayTooltip( UICodeEditor* editor, const LSPHover& resp, + const Vector2f& position ) { + editor->setTooltipText( resp.contents[0].value ); + // HACK: Gets the old font style to restore it when the tooltip is hidden + UITooltip* tooltip = editor->getTooltip(); + if ( tooltip == nullptr ) + return; + mOldTextStyle = tooltip->getFontStyle(); + mOldTextAlign = tooltip->getHorizontalAlign(); + mOldDontAutoHideOnMouseMove = tooltip->dontAutoHideOnMouseMove(); + mOldUsingCustomStyling = tooltip->getUsingCustomStyling(); + tooltip->setHorizontalAlign( UI_HALIGN_LEFT ); + tooltip->setPixelsPosition( tooltip->getTooltipPosition( position ) ); + tooltip->setDontAutoHideOnMouseMove( true ); + tooltip->setUsingCustomStyling( true ); + tooltip->setFontStyle( Text::Regular ); + + const auto& syntaxDef = resp.contents[0].kind == LSPMarkupKind::MarkDown + ? SyntaxDefinitionManager::instance()->getByLSPName( "markdown" ) + : editor->getSyntaxDefinition(); + + SyntaxTokenizer::tokenizeText( syntaxDef, editor->getColorScheme(), *tooltip->getTextCache() ); + + if ( editor->hasFocus() && !tooltip->isVisible() ) + tooltip->show(); +} + +void LSPClientPlugin::tryDisplayTooltip( UICodeEditor* editor, const LSPHover& resp, + const Vector2i& position ) { + TextPosition startCursorPosition = editor->resolveScreenPosition( position.asFloat() ); + TextPosition currentMousePosition = currentMouseTextPosition( editor ); + if ( startCursorPosition != currentMousePosition || + !( resp.range.isValid() && !resp.contents.empty() && !resp.contents[0].value.empty() && + resp.range.contains( startCursorPosition ) ) ) + return; + mCurrentHover = resp; + displayTooltip( editor, resp, position.asFloat() ); +} + bool LSPClientPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& position, const Uint32& flags ) { if ( flags != 0 ) { @@ -502,47 +572,10 @@ bool LSPClientPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& positio server->documentHover( editor->getDocument().getURI(), currentMouseTextPosition( editor ), [&, editor, position]( const Int64&, const LSPHover& resp ) { - if ( resp.range.isValid() && !resp.contents.empty() ) { + if ( resp.range.isValid() && !resp.contents.empty() && + !resp.contents[0].value.empty() ) { editor->runOnMainThread( [editor, resp, position, this]() { - TextPosition startCursorPosition = - editor->resolveScreenPosition( position.asFloat() ); - TextPosition currentMousePosition = - currentMouseTextPosition( editor ); - if ( startCursorPosition != currentMousePosition ) - return; - if ( resp.range.isValid() && !resp.contents.empty() && - resp.range.contains( startCursorPosition ) ) { - mCurrentHover = resp; - editor->setTooltipText( resp.contents[0].value ); - // HACK: Gets the old font style to restore it when the tooltip - // is hidden - mOldTextStyle = editor->getTooltip()->getFontStyle(); - mOldTextAlign = editor->getTooltip()->getHorizontalAlign(); - mOldDontAutoHideOnMouseMove = - editor->getTooltip()->dontAutoHideOnMouseMove(); - mOldUsingCustomStyling = - editor->getTooltip()->getUsingCustomStyling(); - editor->getTooltip()->setHorizontalAlign( UI_HALIGN_LEFT ); - editor->getTooltip()->setPixelsPosition( - editor->getTooltip()->getTooltipPosition( - position.asFloat() ) ); - editor->getTooltip()->setDontAutoHideOnMouseMove( true ); - editor->getTooltip()->setUsingCustomStyling( true ); - editor->getTooltip()->setFontStyle( Text::Regular ); - - const auto& syntaxDef = - resp.contents[0].kind == LSPMarkupKind::MarkDown - ? SyntaxDefinitionManager::instance()->getByLSPName( - "markdown" ) - : editor->getSyntaxDefinition(); - - SyntaxTokenizer::tokenizeText( - syntaxDef, editor->getColorScheme(), - *editor->getTooltip()->getTextCache() ); - - if ( editor->hasFocus() && !editor->getTooltip()->isVisible() ) - editor->getTooltip()->show(); - } + tryDisplayTooltip( editor, resp, position ); } ); } } ); diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.hpp b/src/tools/ecode/plugins/lsp/lspclientplugin.hpp index b82737679..c9fa75052 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.hpp @@ -113,6 +113,14 @@ class LSPClientPlugin : public UICodeEditorPlugin { void tryHideTooltip( UICodeEditor* editor, const Vector2i& position ); void hideTooltip( UICodeEditor* editor ); + + void tryDisplayTooltip( UICodeEditor* editor, const LSPHover& resp, const Vector2i& position ); + + void displayTooltip( UICodeEditor* editor, const LSPHover& resp, const Vector2f& position ); + + void getSymbolInfo( UICodeEditor* editor ); + + void switchSourceHeader( UICodeEditor* editor ); }; } // namespace ecode