diff --git a/include/eepp/system/scopedop.hpp b/include/eepp/system/scopedop.hpp index f5ef01992..07bb05bc1 100644 --- a/include/eepp/system/scopedop.hpp +++ b/include/eepp/system/scopedop.hpp @@ -1,6 +1,7 @@ #ifndef EE_SYSTEM_SCOPEDOP_HPP #define EE_SYSTEM_SCOPEDOP_HPP +#include #include namespace EE { namespace System { @@ -36,6 +37,21 @@ class BoolScopedOp { bool& boolRef; }; +class AtomicBoolScopedOp { + public: + explicit AtomicBoolScopedOp( std::atomic& boolRef ) : boolRef( boolRef ) {} + + explicit AtomicBoolScopedOp( std::atomic& boolRef, bool initialVal ) : + boolRef( boolRef ) { + boolRef = initialVal; + } + + ~AtomicBoolScopedOp() { boolRef = !boolRef; } + + private: + std::atomic& boolRef; +}; + class BoolScopedOpOptional { public: explicit BoolScopedOpOptional( bool cond, bool& boolRef ) : cond( cond ), boolRef( boolRef ) {} diff --git a/src/tools/ecode/plugins/formatter/formatterplugin.cpp b/src/tools/ecode/plugins/formatter/formatterplugin.cpp index 258ecad9c..40e3a54ef 100644 --- a/src/tools/ecode/plugins/formatter/formatterplugin.cpp +++ b/src/tools/ecode/plugins/formatter/formatterplugin.cpp @@ -260,7 +260,7 @@ void FormatterPlugin::loadFormatterConfig( const std::string& path, bool updateC } void FormatterPlugin::load( PluginManager* pluginManager ) { - BoolScopedOp loading( mLoading, true ); + AtomicBoolScopedOp loading( mLoading, true ); mPluginManager = pluginManager; pluginManager->subscribeMessages( this, [this]( const auto& notification ) -> PluginRequestHandle { @@ -288,12 +288,13 @@ void FormatterPlugin::load( PluginManager* pluginManager ) { Log::error( "Parsing formatter \"%s\" failed:\n%s", fpath.c_str(), e.what() ); } } + + subscribeFileSystemListener(); mReady = !mFormatters.empty(); if ( mReady ) { fireReadyCbs(); setReady(); } - subscribeFileSystemListener(); } bool FormatterPlugin::onCreateContextMenu( UICodeEditor* editor, UIPopUpMenu* menu, const Vector2i&, diff --git a/src/tools/ecode/plugins/linter/linterplugin.cpp b/src/tools/ecode/plugins/linter/linterplugin.cpp index 2cd347f9b..11781dcde 100644 --- a/src/tools/ecode/plugins/linter/linterplugin.cpp +++ b/src/tools/ecode/plugins/linter/linterplugin.cpp @@ -548,7 +548,7 @@ TextDocument* LinterPlugin::getDocumentFromURI( const URI& uri ) { } void LinterPlugin::load( PluginManager* pluginManager ) { - BoolScopedOp loading( mLoading, true ); + AtomicBoolScopedOp loading( mLoading, true ); pluginManager->subscribeMessages( this, [this]( const auto& notification ) -> PluginRequestHandle { return processMessage( notification ); @@ -572,12 +572,13 @@ void LinterPlugin::load( PluginManager* pluginManager ) { Log::error( "Parsing linter \"%s\" failed:\n%s", tpath.c_str(), e.what() ); } } + + subscribeFileSystemListener(); mReady = !mLinters.empty(); if ( mReady ) { fireReadyCbs(); setReady(); } - subscribeFileSystemListener(); } void LinterPlugin::onRegister( UICodeEditor* editor ) { diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index db5642ff4..7ae9a89f7 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -727,7 +727,7 @@ PluginRequestHandle LSPClientPlugin::processMessage( const PluginMessage& msg ) } void LSPClientPlugin::load( PluginManager* pluginManager ) { - BoolScopedOp loading( mLoading, true ); + AtomicBoolScopedOp loading( mLoading, true ); pluginManager->subscribeMessages( this, [this]( const auto& notification ) -> PluginRequestHandle { return processMessage( notification ); @@ -758,6 +758,7 @@ void LSPClientPlugin::load( PluginManager* pluginManager ) { mClientManager.load( this, pluginManager, std::move( lsps ) ); + subscribeFileSystemListener(); mReady = mClientManager.lspCount() > 0; for ( const auto& doc : mDelayedDocs ) if ( mDocs.find( doc.first ) != mDocs.end() ) @@ -767,7 +768,6 @@ void LSPClientPlugin::load( PluginManager* pluginManager ) { fireReadyCbs(); setReady(); } - subscribeFileSystemListener(); } static std::string parseCommand( nlohmann::json cmd ) { diff --git a/src/tools/ecode/plugins/pluginmanager.cpp b/src/tools/ecode/plugins/pluginmanager.cpp index f40533b60..4303d00d6 100644 --- a/src/tools/ecode/plugins/pluginmanager.cpp +++ b/src/tools/ecode/plugins/pluginmanager.cpp @@ -449,7 +449,12 @@ UIWindow* UIPluginManager::New( UISceneNode* sceneNode, PluginManager* manager, } Plugin::Plugin( PluginManager* manager ) : - mManager( manager ), mThreadPool( manager->getThreadPool() ) {} + mManager( manager ), + mThreadPool( manager->getThreadPool() ), + mReady( false ), // All plugins will start as not ready until proved the contrary + mLoading( true ) // All plugins will start as loading until the load is complete, this is to + // avoid concurrency issues +{} void Plugin::subscribeFileSystemListener() { if ( mFileSystemListenerCb != 0 || mManager->getFileSystemListener() == nullptr ) @@ -461,12 +466,12 @@ void Plugin::subscribeFileSystemListener() { [this]( const FileEvent& ev, const FileInfo& file ) { if ( ev.type != FileSystemEventType::Modified ) return; - if ( !mShuttingDown && !mLoading && file.getFilepath() == mConfigPath && + if ( !mShuttingDown && !isLoading() && file.getFilepath() == mConfigPath && file.getModificationTime() != mConfigFileInfo.getModificationTime() ) { std::string fileContents; FileSystem::fileGet( file.getFilepath(), fileContents ); if ( getConfigFileHash() != String::hash( fileContents ) ) { - if ( mManager->isPluginReloadEnabled() ) { + if ( mManager->isPluginReloadEnabled() && !isLoading() && isReady() ) { mConfigFileInfo = file; mManager->getFileSystemListener()->removeListener( mFileSystemListenerCb ); mFileSystemListenerCb = 0; @@ -494,6 +499,10 @@ bool Plugin::isReady() const { return mReady; } +bool Plugin::isLoading() const { + return mLoading; +} + bool Plugin::isShuttingDown() const { return mShuttingDown; } diff --git a/src/tools/ecode/plugins/pluginmanager.hpp b/src/tools/ecode/plugins/pluginmanager.hpp index a2947110b..33d2cb0c8 100644 --- a/src/tools/ecode/plugins/pluginmanager.hpp +++ b/src/tools/ecode/plugins/pluginmanager.hpp @@ -406,7 +406,7 @@ class Plugin : public UICodeEditorPlugin { bool isReady() const; - bool isLoading() const { return mLoading; } + bool isLoading() const; bool isShuttingDown() const; @@ -425,9 +425,9 @@ class Plugin : public UICodeEditorPlugin { std::string mConfigPath; FileInfo mConfigFileInfo; - bool mReady{ false }; - bool mLoading{ false }; - bool mShuttingDown{ false }; + std::atomic mReady{ false }; + std::atomic mLoading{ false }; + std::atomic mShuttingDown{ false }; void setReady(); }; diff --git a/src/tools/ecode/plugins/xmltools/xmltoolsplugin.cpp b/src/tools/ecode/plugins/xmltools/xmltoolsplugin.cpp index 5795644cf..4e11c611a 100644 --- a/src/tools/ecode/plugins/xmltools/xmltoolsplugin.cpp +++ b/src/tools/ecode/plugins/xmltools/xmltoolsplugin.cpp @@ -52,7 +52,7 @@ bool XMLToolsPlugin::getAutoEditMatch() const { } void XMLToolsPlugin::load( PluginManager* pluginManager ) { - BoolScopedOp loading( mLoading, true ); + AtomicBoolScopedOp loading( mLoading, true ); std::string path = pluginManager->getPluginsPath() + "xmltools.json"; if ( FileSystem::fileExists( path ) || FileSystem::fileWrite( path, "{\n \"config\":{},\n \"keybindings\":{}\n}\n" ) ) { @@ -98,11 +98,10 @@ void XMLToolsPlugin::load( PluginManager* pluginManager ) { mConfigHash = String::hash( data ); } + subscribeFileSystemListener(); mReady = true; fireReadyCbs(); setReady(); - - subscribeFileSystemListener(); } void XMLToolsPlugin::onRegisterDocument( TextDocument* doc ) {