diff --git a/include/eepp/ui/doc/syntaxhighlighter.hpp b/include/eepp/ui/doc/syntaxhighlighter.hpp index f9a64ad8f..25119f0d6 100644 --- a/include/eepp/ui/doc/syntaxhighlighter.hpp +++ b/include/eepp/ui/doc/syntaxhighlighter.hpp @@ -9,7 +9,7 @@ namespace EE { namespace UI { namespace Doc { struct EE_API TokenizedLine { SyntaxState initState; - String::HashType hash; + String::HashType hash{ 0 }; std::vector tokens; SyntaxState state; Uint64 signature{ 0 }; diff --git a/include/eepp/ui/doc/syntaxtokenizer.hpp b/include/eepp/ui/doc/syntaxtokenizer.hpp index 04cffa680..fc50ace9f 100644 --- a/include/eepp/ui/doc/syntaxtokenizer.hpp +++ b/include/eepp/ui/doc/syntaxtokenizer.hpp @@ -53,7 +53,7 @@ struct SyntaxStateRestored { struct SyntaxState { // 8 bits per pattern - max 4 sub-languages - max 254 patterns per language Uint8 state[MAX_SUB_SYNTAXS]{ SYNTAX_TOKENIZER_STATE_NONE, SYNTAX_TOKENIZER_STATE_NONE, - SYNTAX_TOKENIZER_STATE_NONE, SYNTAX_TOKENIZER_STATE_NONE }; + SYNTAX_TOKENIZER_STATE_NONE, SYNTAX_TOKENIZER_STATE_NONE }; // 8 bits per language (language index) - max 4 sub-languages - max 255 languages Uint8 langStack[MAX_SUB_SYNTAXS]{ 0, 0, 0, 0 }; diff --git a/src/eepp/ui/doc/syntaxhighlighter.cpp b/src/eepp/ui/doc/syntaxhighlighter.cpp index 1d31db395..f4f9af324 100644 --- a/src/eepp/ui/doc/syntaxhighlighter.cpp +++ b/src/eepp/ui/doc/syntaxhighlighter.cpp @@ -199,17 +199,28 @@ bool SyntaxHighlighter::updateDirty( int visibleLinesCount ) { for ( Int64 index = mFirstInvalidLine; index <= max; index++ ) { SyntaxState state; - Lock l( mLinesMutex ); if ( index > 0 ) { + Lock l( mLinesMutex ); auto prevIt = mLines.find( index - 1 ); - if ( prevIt != mLines.end() ) { + if ( prevIt != mLines.end() ) state = prevIt->second.state; - } } - const auto& it = mLines.find( index ); - if ( it == mLines.end() || it->second.hash != mDoc->line( index ).getHash() || - it->second.initState != state ) { - mLines[index] = tokenizeLine( index, state ); + + bool mustTokenize = false; + + { + Lock l( mLinesMutex ); + const auto& it = mLines.find( index ); + mustTokenize = it == mLines.end() || + it->second.hash != mDoc->line( index ).getHash() || + it->second.initState != state; + } + + if ( mustTokenize ) { + auto tokenizedLine = tokenizeLine( index, state ); + + Lock l( mLinesMutex ); + mLines[index] = std::move( tokenizedLine ); mTokenizerLines[index] = mLines[index]; changed = true; } @@ -223,14 +234,20 @@ bool SyntaxHighlighter::updateDirty( int visibleLinesCount ) { const SyntaxDefinition& SyntaxHighlighter::getSyntaxDefinitionFromTextPosition( const TextPosition& position ) { - Lock l( mLinesMutex ); - auto found = mLines.find( position.line() ); - if ( found == mLines.end() ) - return SyntaxDefinitionManager::instance()->getPlainDefinition(); + SyntaxState lineState; + + { + Lock l( mLinesMutex ); + auto found = mLines.find( position.line() ); + if ( found == mLines.end() ) { + return SyntaxDefinitionManager::instance()->getPlainDefinition(); + } else { + lineState = found->second.state; + } + } - const TokenizedLine& line = found->second; SyntaxStateRestored state = - SyntaxTokenizer::retrieveSyntaxState( mDoc->getSyntaxDefinition(), line.state ); + SyntaxTokenizer::retrieveSyntaxState( mDoc->getSyntaxDefinition(), lineState ); if ( nullptr == state.currentSyntax ) return SyntaxDefinitionManager::instance()->getPlainDefinition(); @@ -276,14 +293,18 @@ void SyntaxHighlighter::setLine( const size_t& line, const TokenizedLine& tokeni void SyntaxHighlighter::mergeLine( const size_t& line, const TokenizedLine& tokenization ) { TokenizedLine tline; { - Lock l( mLinesMutex ); + mLinesMutex.lock(); auto found = mTokenizerLines.find( line ); if ( found != mTokenizerLines.end() && mDoc->line( line ).getHash() == found->second.hash ) { tline = found->second; + mLinesMutex.unlock(); } else { + mLinesMutex.unlock(); tline = tokenizeLine( line ); + mLinesMutex.lock(); mTokenizerLines[line] = tline; + mLinesMutex.unlock(); } } diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 6cdb0c6c6..59a190b0e 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -547,6 +547,12 @@ void App::closeApp() { mWindow->close(); } +void App::onReady() { + // Plugin reload is only available right after we render the first frame and the editor is ready + // to run. + mPluginManager->setPluginReloadEnabled( true ); +} + void App::mainLoop() { mWindow->getInput()->update(); SceneManager::instance()->update(); @@ -563,6 +569,7 @@ void App::mainLoop() { if ( unlikely( firstFrame ) ) { Log::info( "First frame took: %.2f ms", globalClock.getElapsedTime().asMilliseconds() ); firstFrame = false; + onReady(); } } else { #if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index ea487c886..9cf8bbe3d 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -592,6 +592,8 @@ class App : public UICodeEditorSplitter::Client { void updateOpenRecentFolderBtn(); void updateDocInfoLocation(); + + void onReady(); }; } // namespace ecode diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp index 92f97658c..2edfe1c2a 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp @@ -80,6 +80,8 @@ AutoCompletePlugin::AutoCompletePlugin( PluginManager* pluginManager ) : mManager->subscribeMessages( this, [this]( const PluginMessage& msg ) -> PluginRequestHandle { return processResponse( msg ); } ); + mReady = true; + setReady(); } AutoCompletePlugin::~AutoCompletePlugin() { diff --git a/src/tools/ecode/plugins/formatter/formatterplugin.cpp b/src/tools/ecode/plugins/formatter/formatterplugin.cpp index 615e0b826..258ecad9c 100644 --- a/src/tools/ecode/plugins/formatter/formatterplugin.cpp +++ b/src/tools/ecode/plugins/formatter/formatterplugin.cpp @@ -86,15 +86,19 @@ void FormatterPlugin::onRegister( UICodeEditor* editor ) { mEditorDocs[editor] = newDoc; } ) ); - listeners.push_back( editor->addEventListener( Event::OnDocumentSave, [this]( - const Event* event ) { - if ( mAutoFormatOnSave && event->getNode()->isType( UI_TYPE_CODEEDITOR ) ) { - UICodeEditor* editor = event->getNode()->asType(); - auto isAutoFormatting = mIsAutoFormatting.find( &editor->getDocument() ); - if ( isAutoFormatting == mIsAutoFormatting.end() || isAutoFormatting->second == false ) - formatDoc( editor ); - } - } ) ); + listeners.push_back( + editor->addEventListener( Event::OnDocumentSave, [this]( const Event* event ) { + if ( mAutoFormatOnSave && event->getNode()->isType( UI_TYPE_CODEEDITOR ) ) { + UICodeEditor* editor = event->getNode()->asType(); + auto isAutoFormatting = mIsAutoFormatting.find( &editor->getDocument() ); + if ( ( isAutoFormatting == mIsAutoFormatting.end() || + isAutoFormatting->second == false ) && + mPluginManager && + !String::startsWith( editor->getDocument().getFilePath(), + mPluginManager->getPluginsPath() ) ) + formatDoc( editor ); + } + } ) ); mEditors.insert( { editor, listeners } ); mEditorDocs[editor] = editor->getDocumentRef().get(); @@ -257,6 +261,7 @@ void FormatterPlugin::loadFormatterConfig( const std::string& path, bool updateC void FormatterPlugin::load( PluginManager* pluginManager ) { BoolScopedOp loading( mLoading, true ); + mPluginManager = pluginManager; pluginManager->subscribeMessages( this, [this]( const auto& notification ) -> PluginRequestHandle { return processMessage( notification ); @@ -284,9 +289,10 @@ void FormatterPlugin::load( PluginManager* pluginManager ) { } } mReady = !mFormatters.empty(); - if ( mReady ) + if ( mReady ) { fireReadyCbs(); - + setReady(); + } subscribeFileSystemListener(); } @@ -380,7 +386,9 @@ void FormatterPlugin::formatDoc( UICodeEditor* editor ) { doc->textInput( data, false ); doc->setSelection( pos ); editor->setScroll( scroll ); - if ( mAutoFormatOnSave ) { + if ( mAutoFormatOnSave && mPluginManager && + !String::startsWith( doc->getFilePath(), + mPluginManager->getPluginsPath() ) ) { mIsAutoFormatting[doc.get()] = true; doc->save(); mIsAutoFormatting[doc.get()] = false; @@ -472,9 +480,9 @@ FormatterPlugin::Formatter FormatterPlugin::supportsFormatter( std::shared_ptrgetFilePath() ) ); const auto& def = doc->getSyntaxDefinition(); - for ( auto& formatter : mFormatters ) { - for ( auto& ext : formatter.files ) { - if ( LuaPattern::find( fileName, ext ).isValid() ) + for ( const auto& formatter : mFormatters ) { + for ( const auto& ext : formatter.files ) { + if ( LuaPattern::matches( fileName, ext ) ) return formatter; auto& files = def.getFiles(); if ( std::find( files.begin(), files.end(), ext ) != files.end() ) diff --git a/src/tools/ecode/plugins/formatter/formatterplugin.hpp b/src/tools/ecode/plugins/formatter/formatterplugin.hpp index dd1376967..7cf917e4b 100644 --- a/src/tools/ecode/plugins/formatter/formatterplugin.hpp +++ b/src/tools/ecode/plugins/formatter/formatterplugin.hpp @@ -6,7 +6,6 @@ #include #include #include -#include using namespace EE; using namespace EE::System; using namespace EE::UI; @@ -86,6 +85,7 @@ class FormatterPlugin : public Plugin { std::map mCapabilities; Mutex mCapabilitiesMutex; String::HashType mConfigHash{ 0 }; + PluginManager* mPluginManager{ nullptr }; bool mAutoFormatOnSave{ false }; diff --git a/src/tools/ecode/plugins/linter/linterplugin.cpp b/src/tools/ecode/plugins/linter/linterplugin.cpp index 0c3badf14..2cd347f9b 100644 --- a/src/tools/ecode/plugins/linter/linterplugin.cpp +++ b/src/tools/ecode/plugins/linter/linterplugin.cpp @@ -573,9 +573,10 @@ void LinterPlugin::load( PluginManager* pluginManager ) { } } mReady = !mLinters.empty(); - if ( mReady ) + if ( mReady ) { fireReadyCbs(); - + setReady(); + } subscribeFileSystemListener(); } diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index c7f5fdaf2..291aa6041 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -763,9 +763,10 @@ void LSPClientPlugin::load( PluginManager* pluginManager ) { if ( mDocs.find( doc.first ) != mDocs.end() ) mClientManager.tryRunServer( doc.second ); mDelayedDocs.clear(); - if ( mReady ) + if ( mReady ) { fireReadyCbs(); - + setReady(); + } subscribeFileSystemListener(); } diff --git a/src/tools/ecode/plugins/pluginmanager.cpp b/src/tools/ecode/plugins/pluginmanager.cpp index 60b2f18a0..f40533b60 100644 --- a/src/tools/ecode/plugins/pluginmanager.cpp +++ b/src/tools/ecode/plugins/pluginmanager.cpp @@ -227,6 +227,14 @@ const PluginManager::OnLoadFileCb& PluginManager::getLoadFileFn() const { return mLoadFileFn; } +bool PluginManager::isPluginReloadEnabled() const { + return mPluginReloadEnabled; +} + +void PluginManager::setPluginReloadEnabled( bool pluginReloadEnabled ) { + mPluginReloadEnabled = pluginReloadEnabled; +} + void PluginManager::subscribeMessages( UICodeEditorPlugin* plugin, std::function cb ) { subscribeMessages( plugin->getId(), cb ); @@ -458,10 +466,16 @@ void Plugin::subscribeFileSystemListener() { std::string fileContents; FileSystem::fileGet( file.getFilepath(), fileContents ); if ( getConfigFileHash() != String::hash( fileContents ) ) { - mConfigFileInfo = file; - mManager->getFileSystemListener()->removeListener( mFileSystemListenerCb ); - mFileSystemListenerCb = 0; - mManager->reload( getId() ); + if ( mManager->isPluginReloadEnabled() ) { + mConfigFileInfo = file; + mManager->getFileSystemListener()->removeListener( mFileSystemListenerCb ); + mFileSystemListenerCb = 0; + mManager->reload( getId() ); + } else { + Log::debug( "Plugin %s: Configuration file has been modified: %s. But " + "plugin reload is not enabled.", + getTitle().c_str(), mConfigPath.c_str() ); + } } else { Log::debug( "Plugin %s: Configuration file has been modified: %s. But contents " "are the same.", @@ -496,6 +510,11 @@ PluginManager* Plugin::getManager() const { return mManager; } +void Plugin::setReady() { + if ( mReady ) + Log::info( "Plugin: %s loaded and ready.", getTitle().c_str() ); +} + PluginBase::~PluginBase() { mShuttingDown = true; unsubscribeFileSystemListener(); diff --git a/src/tools/ecode/plugins/pluginmanager.hpp b/src/tools/ecode/plugins/pluginmanager.hpp index f85cae1db..a2947110b 100644 --- a/src/tools/ecode/plugins/pluginmanager.hpp +++ b/src/tools/ecode/plugins/pluginmanager.hpp @@ -61,11 +61,7 @@ struct PluginDefinition { PluginCreatorFn creatorSyncFn{ nullptr }; }; -enum class PluginCapability { - WorkspaceSymbol, - TextDocumentSymbol, - Max -}; +enum class PluginCapability { WorkspaceSymbol, TextDocumentSymbol, Max }; enum class PluginMessageType { WorkspaceFolderChanged, // Broadcast the workspace folder from the application to the plugins @@ -251,7 +247,7 @@ class PluginRequestHandle { class PluginManager { public: static constexpr int versionNumber( int major, int minor, int patch ) { - return ( (major)*1000 + (minor)*100 + ( patch ) ); + return ( ( major ) * 1000 + ( minor ) * 100 + ( patch ) ); } static std::string versionString( int major, int minor, int patch ) { @@ -332,6 +328,10 @@ class PluginManager { const OnLoadFileCb& getLoadFileFn() const; + bool isPluginReloadEnabled() const; + + void setPluginReloadEnabled( bool pluginReloadEnabled ); + protected: using SubscribedPlugins = std::map>; @@ -349,6 +349,7 @@ class PluginManager { SubscribedPlugins mSubscribedPlugins; OnLoadFileCb mLoadFileFn; bool mClosing{ false }; + bool mPluginReloadEnabled{ false }; bool hasDefinition( const std::string& id ); @@ -427,6 +428,8 @@ class Plugin : public UICodeEditorPlugin { bool mReady{ false }; bool mLoading{ false }; bool mShuttingDown{ false }; + + void setReady(); }; class PluginBase : public Plugin { diff --git a/src/tools/ecode/plugins/xmltools/xmltoolsplugin.cpp b/src/tools/ecode/plugins/xmltools/xmltoolsplugin.cpp index 9804c7287..5795644cf 100644 --- a/src/tools/ecode/plugins/xmltools/xmltoolsplugin.cpp +++ b/src/tools/ecode/plugins/xmltools/xmltoolsplugin.cpp @@ -100,6 +100,7 @@ void XMLToolsPlugin::load( PluginManager* pluginManager ) { mReady = true; fireReadyCbs(); + setReady(); subscribeFileSystemListener(); }