diff --git a/include/eepp/ui/keyboardshortcut.hpp b/include/eepp/ui/keyboardshortcut.hpp index 50c1b44ae..5f1a329e4 100644 --- a/include/eepp/ui/keyboardshortcut.hpp +++ b/include/eepp/ui/keyboardshortcut.hpp @@ -43,9 +43,9 @@ class EE_API KeyBindings { void addKeybindsUnordered( const std::unordered_map& binds ); - void addKeybindString( const std::string& keys, const std::string& command ); + void addKeybindString(const std::string& key, const std::string& command ); - void addKeybind( const Shortcut& keys, const std::string& command ); + void addKeybind( const Shortcut& key, const std::string& command ); /** If the command is already on the list, it will remove the previous keybind. */ void replaceKeybindString( const std::string& keys, const std::string& command ); diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index 0529b79af..37e17fd75 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -31,13 +31,17 @@ class UIMenuItem; class UICodeEditorPlugin { public: + typedef std::function OnReadyCb; virtual std::string getId() = 0; virtual std::string getTitle() = 0; virtual std::string getDescription() = 0; + virtual bool isReady() const = 0; virtual bool hasGUIConfig() { return false; } virtual bool hasFileConfig() { return false; } virtual UIWindow* getGUIConfig() { return nullptr; } virtual std::string getFileConfigPath() { return ""; } + virtual void setOnReadyCallback( const OnReadyCb& cb ) { mOnReadyCallback = cb; }; + virtual ~UICodeEditorPlugin() {} virtual void onRegister( UICodeEditor* ) = 0; @@ -75,6 +79,9 @@ class UICodeEditorPlugin { const Float& /*gutterWidth*/ ){}; virtual void minimapDrawAfterLineText( UICodeEditor*, const Int64&, const Vector2f&, const Vector2f&, const Float&, const Float& ){}; + + protected: + OnReadyCb mOnReadyCallback; }; class EE_API DocEvent : public Event { @@ -245,6 +252,8 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { void setColorScheme( const SyntaxColorScheme& colorScheme ); + bool hasDocument() const; + /** If the document is managed by more than one client you need to NOT auto register base * commands and implement your own logic for those commands, since are dependant of the client * state. diff --git a/src/eepp/ui/keyboardshortcut.cpp b/src/eepp/ui/keyboardshortcut.cpp index c3fb032c2..e99af485b 100644 --- a/src/eepp/ui/keyboardshortcut.cpp +++ b/src/eepp/ui/keyboardshortcut.cpp @@ -48,13 +48,13 @@ void KeyBindings::addKeybindsUnordered( } } -void KeyBindings::addKeybindString( const std::string& keys, const std::string& command ) { - addKeybind( getShortcutFromString( keys ), command ); +void KeyBindings::addKeybindString( const std::string& key, const std::string& command ) { + addKeybind( getShortcutFromString( key ), command ); } -void KeyBindings::addKeybind( const KeyBindings::Shortcut& keys, const std::string& command ) { - mShortcuts[sanitizeShortcut( keys )] = command; - mKeybindingsInvert[command] = sanitizeShortcut( keys ); +void KeyBindings::addKeybind( const KeyBindings::Shortcut& key, const std::string& command ) { + mShortcuts[sanitizeShortcut( key )] = command; + mKeybindingsInvert[command] = sanitizeShortcut( key ); } void KeyBindings::replaceKeybindString( const std::string& keys, const std::string& command ) { diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index f2c96a31f..178014a26 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -734,6 +734,10 @@ void UICodeEditor::setColorScheme( const SyntaxColorScheme& colorScheme ) { invalidateDraw(); } +bool UICodeEditor::hasDocument() const { + return mDoc.get() != nullptr; +} + std::shared_ptr UICodeEditor::getDocumentRef() const { return mDoc; } diff --git a/src/eepp/ui/uitableview.cpp b/src/eepp/ui/uitableview.cpp index 722004d0b..897af90de 100644 --- a/src/eepp/ui/uitableview.cpp +++ b/src/eepp/ui/uitableview.cpp @@ -117,7 +117,7 @@ Float UITableView::getMaxColumnContentWidth( const size_t& colIndex, bool bestGu getUISceneNode()->setIsLoading( true ); Float yOffset = getHeaderHeight(); auto worstCaseFunc = [&]( const ModelIndex& index ) { - UIWidget* widget = updateCell( 0, index, 0, yOffset ); + UIWidget* widget = updateCell( index.row(), index, 0, yOffset ); if ( widget->isType( UI_TYPE_PUSHBUTTON ) ) { Float w = widget->asType()->getContentSize().getWidth(); if ( w > lWidth ) diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 9a91b2786..2443be02c 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -342,12 +342,23 @@ void App::runCommand( const std::string& command ) { } } +void App::onPluginEnabled( UICodeEditorPlugin* plugin ) { + if ( mSplitter ) + mSplitter->forEachEditor( + [&]( UICodeEditor* editor ) { editor->registerPlugin( plugin ); } ); +} + void App::initPluginManager() { mPluginManager = std::make_unique( mResPath, mPluginsPath, mThreadPool ); mPluginManager->onPluginEnabled = [&]( UICodeEditorPlugin* plugin ) { - if ( mSplitter ) - mSplitter->forEachEditor( - [&]( UICodeEditor* editor ) { editor->registerPlugin( plugin ); } ); + if ( nullptr == mUISceneNode || plugin->isReady() ) { + onPluginEnabled( plugin ); + } else { + // If plugin loads asynchronously and is not ready, delay the plugin enabled callback + plugin->setOnReadyCallback( [&, plugin]( auto* ) { + mUISceneNode->runOnMainThread( [&, plugin]() { onPluginEnabled( plugin ); } ); + } ); + } }; mPluginManager->registerPlugin( LinterPlugin::Definition() ); mPluginManager->registerPlugin( FormatterPlugin::Definition() ); @@ -2167,7 +2178,6 @@ std::map App::getLocalKeybindings() { { { KEY_M, KeyMod::getDefaultModifier() }, "menu-toggle" }, { { KEY_S, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "save-all" }, { { KEY_F9, KEYMOD_LALT }, "switch-side-panel" }, - { { KEY_F, KEYMOD_LALT }, "format-doc" }, { { KEY_J, KEYMOD_CTRL | KEYMOD_LALT | KEYMOD_SHIFT }, "terminal-split-left" }, { { KEY_L, KEYMOD_CTRL | KEYMOD_LALT | KEYMOD_SHIFT }, "terminal-split-right" }, { { KEY_I, KEYMOD_CTRL | KEYMOD_LALT | KEYMOD_SHIFT }, "terminal-split-top" }, diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index 6325265dd..7a4af1a5b 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -349,6 +349,8 @@ class App : public UICodeEditorSplitter::Client { void initPluginManager(); void checkWidgetPick( UITreeView* widgetTree ); + + void onPluginEnabled( UICodeEditorPlugin* plugin ); }; } // namespace ecode diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp index 7d6d49ac1..c3b246b25 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp @@ -38,6 +38,8 @@ class AutoCompletePlugin : public UICodeEditorPlugin { std::string getDescription() { return Definition().description; } + bool isReady() const { return true; } + void onRegister( UICodeEditor* ); void onUnregister( UICodeEditor* ); bool onKeyDown( UICodeEditor*, const KeyEvent& ); diff --git a/src/tools/ecode/plugins/formatter/formatterplugin.cpp b/src/tools/ecode/plugins/formatter/formatterplugin.cpp index a73f10273..8e9d75b3c 100644 --- a/src/tools/ecode/plugins/formatter/formatterplugin.cpp +++ b/src/tools/ecode/plugins/formatter/formatterplugin.cpp @@ -44,28 +44,46 @@ FormatterPlugin::~FormatterPlugin() { } for ( auto editor : mEditors ) { - editor->getDocument().removeCommand( "format-doc" ); + for ( auto& kb : mKeyBindings ) { + editor->getKeyBindings().removeCommandKeybind( kb.first ); + if ( editor->hasDocument() ) + editor->getDocument().removeCommand( kb.first ); + } + editor->unregisterPlugin( this ); } } void FormatterPlugin::onRegister( UICodeEditor* editor ) { + Log::info( "FormatterPlugin::onRegister" ); mEditors.insert( editor ); - auto& doc = editor->getDocument(); + for ( auto& kb : mKeyBindings ) { + Log::info( "FormatterPlugin::onRegister addKeybindString %s %s", kb.first.c_str(), + kb.second.c_str() ); + editor->getKeyBindings().addKeybindString( kb.second, kb.first ); + } - if ( doc.hasCommand( "format-doc" ) ) - return; + if ( editor->hasDocument() ) + editor->getDocument().setCommand( "format-doc", [&, editor]() { formatDoc( editor ); } ); - doc.setCommand( "format-doc", [&, editor]() { formatDoc( editor ); } ); - - editor->addEventListener( Event::OnDocumentSave, [&]( const Event* event ) { + mOnDocumentSaveCb = editor->addEventListener( Event::OnDocumentSave, [&]( const Event* event ) { if ( mAutoFormatOnSave && event->getNode()->isType( UI_TYPE_CODEEDITOR ) ) formatDoc( event->getNode()->asType() ); } ); } void FormatterPlugin::onUnregister( UICodeEditor* editor ) { + Log::info( "FormatterPlugin::onUnregister" ); + for ( auto& kb : mKeyBindings ) { + editor->getKeyBindings().removeCommandKeybind( kb.first ); + if ( editor->hasDocument() ) + editor->getDocument().removeCommand( kb.first ); + } + + if ( mOnDocumentSaveCb != 0 ) + editor->removeEventListener( mOnDocumentSaveCb ); + if ( mShuttingDown ) return; mEditors.erase( editor ); @@ -112,6 +130,10 @@ void FormatterPlugin::loadFormatterConfig( const std::string& path ) { auto& config = j["config"]; if ( config.contains( "auto_format_on_save" ) ) setAutoFormatOnSave( config["auto_format_on_save"].get() ); + + mKeyBindings["format-doc"] = "alt+f"; + if ( config.contains( "keybindings" ) && config["keybindings"].contains( "format-doc" ) ) + mKeyBindings["format-doc"] = config["keybindings"]["format-doc"]; } if ( !j.contains( "formatters" ) ) @@ -178,6 +200,8 @@ void FormatterPlugin::load( const PluginManager* pluginManager ) { } } mReady = !mFormatters.empty(); + if ( mReady && mOnReadyCallback ) + mOnReadyCallback( this ); } bool FormatterPlugin::hasFileConfig() { diff --git a/src/tools/ecode/plugins/formatter/formatterplugin.hpp b/src/tools/ecode/plugins/formatter/formatterplugin.hpp index 2348c332f..2db1a7e6e 100644 --- a/src/tools/ecode/plugins/formatter/formatterplugin.hpp +++ b/src/tools/ecode/plugins/formatter/formatterplugin.hpp @@ -43,6 +43,8 @@ class FormatterPlugin : public UICodeEditorPlugin { void onUnregister( UICodeEditor* ); + bool isReady() const { return mReady; } + bool getAutoFormatOnSave() const; void setAutoFormatOnSave( bool autoFormatOnSave ); @@ -75,10 +77,13 @@ class FormatterPlugin : public UICodeEditorPlugin { mNativeFormatters; Int32 mWorkersCount{ 0 }; std::string mConfigPath; + /* cmd, shortcut */ + std::map mKeyBindings; bool mAutoFormatOnSave{ false }; bool mShuttingDown{ false }; bool mReady{ false }; + Uint32 mOnDocumentSaveCb{ 0 }; FormatterPlugin( const PluginManager* pluginManager ); diff --git a/src/tools/ecode/plugins/linter/linterplugin.cpp b/src/tools/ecode/plugins/linter/linterplugin.cpp index 0fb45d2ef..1f0a68fe0 100644 --- a/src/tools/ecode/plugins/linter/linterplugin.cpp +++ b/src/tools/ecode/plugins/linter/linterplugin.cpp @@ -181,6 +181,8 @@ void LinterPlugin::load( const PluginManager* pluginManager ) { } } mReady = !mLinters.empty(); + if ( mReady && mOnReadyCallback ) + mOnReadyCallback( this ); } void LinterPlugin::onRegister( UICodeEditor* editor ) { diff --git a/src/tools/ecode/plugins/linter/linterplugin.hpp b/src/tools/ecode/plugins/linter/linterplugin.hpp index c3a681fd4..9f446abe5 100644 --- a/src/tools/ecode/plugins/linter/linterplugin.hpp +++ b/src/tools/ecode/plugins/linter/linterplugin.hpp @@ -62,6 +62,8 @@ class LinterPlugin : public UICodeEditorPlugin { std::string getDescription() { return Definition().description; } + bool isReady() const { return mReady; } + bool hasFileConfig(); std::string getFileConfigPath();