diff --git a/include/eepp/scene/action.hpp b/include/eepp/scene/action.hpp index c108bdebd..1ba10e3ac 100644 --- a/include/eepp/scene/action.hpp +++ b/include/eepp/scene/action.hpp @@ -3,7 +3,6 @@ #include #include -#include using namespace EE::System; namespace EE { namespace Scene { diff --git a/include/eepp/scene/actionmanager.hpp b/include/eepp/scene/actionmanager.hpp index 5ee92323e..25c323a16 100644 --- a/include/eepp/scene/actionmanager.hpp +++ b/include/eepp/scene/actionmanager.hpp @@ -26,6 +26,9 @@ class EE_API ActionManager { Action* getActionByTag( const Action::UniqueID& tag ); + Action* getActionByTagFromTarget( Node* target, const Action::UniqueID& tag, + bool mustBePending = false ); + bool removeActionByTag( const Action::UniqueID& tag ); bool removeAction( Action* action ); diff --git a/include/eepp/scene/actions/delay.hpp b/include/eepp/scene/actions/delay.hpp index e286ffe5b..c0533375d 100644 --- a/include/eepp/scene/actions/delay.hpp +++ b/include/eepp/scene/actions/delay.hpp @@ -27,6 +27,8 @@ class EE_API Delay : public Action { Action* reverse() const override; + void restart(); + protected: Clock mClock; Time mTime; diff --git a/include/eepp/scene/actions/runnable.hpp b/include/eepp/scene/actions/runnable.hpp index 48619881c..d17e3c4b6 100644 --- a/include/eepp/scene/actions/runnable.hpp +++ b/include/eepp/scene/actions/runnable.hpp @@ -2,6 +2,7 @@ #define EE_SCENE_ACTION_CALLBACK_HPP #include +#include #include namespace EE { namespace Scene { namespace Actions { @@ -21,8 +22,11 @@ class EE_API Runnable : public Delay { Action* reverse() const override; + void setCallback( RunnableFunc&& callback ); + protected: RunnableFunc mCallback; + Mutex mCallbackMutex; bool mCalled{ false }; bool mLoop{ false }; diff --git a/src/eepp/scene/actionmanager.cpp b/src/eepp/scene/actionmanager.cpp index d27bb1947..cec82c57e 100644 --- a/src/eepp/scene/actionmanager.cpp +++ b/src/eepp/scene/actionmanager.cpp @@ -38,6 +38,19 @@ Action* ActionManager::getActionByTag( const Action::UniqueID& tag ) { return NULL; } +Action* ActionManager::getActionByTagFromTarget( Node* target, const Action::UniqueID& tag, + bool mustBePending ) { + Lock l( mMutex ); + + for ( Action* action : mActions ) { + if ( action->getTarget() == target && action->getTag() == tag && + ( !mustBePending || !action->isDone() ) ) + return action; + } + + return NULL; +} + std::vector ActionManager::getActionsFromTarget( Node* target ) { Lock l( mMutex ); diff --git a/src/eepp/scene/actions/delay.cpp b/src/eepp/scene/actions/delay.cpp index 844157b92..4fc532bf3 100644 --- a/src/eepp/scene/actions/delay.cpp +++ b/src/eepp/scene/actions/delay.cpp @@ -43,6 +43,10 @@ Action* Delay::reverse() const { return NULL; // or a time machine } +void Delay::restart() { + mClock.restart(); +} + Delay::Delay( const Time& time ) : mTime( time ) {} }}} // namespace EE::Scene::Actions diff --git a/src/eepp/scene/actions/runnable.cpp b/src/eepp/scene/actions/runnable.cpp index f47e86cd1..22da9e534 100644 --- a/src/eepp/scene/actions/runnable.cpp +++ b/src/eepp/scene/actions/runnable.cpp @@ -1,4 +1,5 @@ #include +#include namespace EE { namespace Scene { namespace Actions { @@ -10,6 +11,7 @@ Runnable::Runnable( Runnable::RunnableFunc callback, const Time& time, bool loop Delay( time ), mCallback( std::move( callback ) ), mLoop( loop ) {} void Runnable::update( const Time& ) { + Lock l( mCallbackMutex ); if ( mCallback && Delay::isDone() && !mCalled ) { mCallback(); if ( mLoop ) { @@ -34,6 +36,11 @@ Action* Runnable::reverse() const { return NULL; // or a time machine } +void Runnable::setCallback( RunnableFunc&& callback ) { + Lock l( mCallbackMutex ); + mCallback = std::move( callback ); +} + void Runnable::onStart() {} }}} // namespace EE::Scene::Actions diff --git a/src/eepp/scene/node.cpp b/src/eepp/scene/node.cpp index 15a1503c6..0555eed9e 100644 --- a/src/eepp/scene/node.cpp +++ b/src/eepp/scene/node.cpp @@ -1574,8 +1574,15 @@ void Node::setTimeout( Actions::Runnable::RunnableFunc runnable, const Time& del void Node::debounce( Actions::Runnable::RunnableFunc runnable, const Time& delay, const Uint32& uniqueIdentifier ) { - removeActionsByTag( uniqueIdentifier ); - setTimeout( std::move( runnable ), std::move( delay ), uniqueIdentifier ); + Action* prevAction = + getActionManager()->getActionByTagFromTarget( this, uniqueIdentifier, true ); + if ( prevAction ) { + auto* action = static_cast( prevAction ); + action->setCallback( std::move( runnable ) ); + action->restart(); + } else { + setTimeout( std::move( runnable ), std::move( delay ), uniqueIdentifier ); + } } void Node::setInterval( Actions::Runnable::RunnableFunc runnable, const Time& interval, diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index cba287f7d..b1adcac3e 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -1526,8 +1526,9 @@ void App::onDocumentSelectionChange( UICodeEditor* editor, TextDocument& doc ) { onDocumentModified( editor, doc ); } -void App::onDocumentCursorPosChange( UICodeEditor*, TextDocument& doc ) { - updateDocInfo( doc ); +void App::onDocumentCursorPosChange( UICodeEditor* editor, TextDocument& doc ) { + if ( mSplitter->curEditorExistsAndFocused() && mSplitter->getCurEditor() == editor ) + updateDocInfo( doc ); } void App::updateDocInfoLocation() { @@ -1545,8 +1546,8 @@ void App::updateDocInfoLocation() { } void App::updateDocInfo( TextDocument& doc ) { - if ( !doc.isRunningTransaction() && mConfig.editor.showDocInfo && mDocInfo && - mSplitter->curEditorExistsAndFocused() ) { + if ( !doc.isRunningTransaction() && !doc.isLoading() && mConfig.editor.showDocInfo && + mDocInfo && mSplitter->curEditorExistsAndFocused() ) { mDocInfo->setVisible( true ); updateDocInfoLocation(); String infoStr( String::format( @@ -1555,7 +1556,8 @@ void App::updateDocInfo( TextDocument& doc ) { i18n( "col_abbr", "col" ).toUtf8().c_str(), mSplitter->getCurEditor()->getCurrentColumnCount(), TextDocument::lineEndingToString( doc.getLineEnding() ).c_str() ) ); - mDocInfo->runOnMainThread( [this, infoStr] { mDocInfo->setText( infoStr ); } ); + mDocInfo->debounce( [this, infoStr] { mDocInfo->setText( infoStr ); }, Time::Zero, + String::hash( "ecode::doc_info::update" ) ); } } diff --git a/src/tools/ecode/plugins/git/git.cpp b/src/tools/ecode/plugins/git/git.cpp index 587fd5c06..8ecf6c5ec 100644 --- a/src/tools/ecode/plugins/git/git.cpp +++ b/src/tools/ecode/plugins/git/git.cpp @@ -35,19 +35,20 @@ Git::Git( const std::string& projectDir, const std::string& gitPath ) : mGitPath } void Git::git( const std::string& args, const std::string& projectDir, std::string& buf ) const { + buf.clear(); Process p; p.create( mGitPath, args, Process::CombinedStdoutStderr | Process::Options::NoWindow, { { "LC_ALL", "en_US.UTF-8" } }, projectDir.empty() ? mProjectPath : projectDir ); p.readAllStdOut( buf ); } -std::string Git::branch( std::string projectDir ) { +std::string Git::branch( const std::string& projectDir ) { std::string buf; git( "rev-parse --abbrev-ref HEAD", projectDir, buf ); return String::rTrim( buf, '\n' ); } -bool Git::setProjectPath( std::string projectPath ) { +bool Git::setProjectPath( const std::string& projectPath ) { mProjectPath = ""; mGitFolder = ""; FileInfo f( projectPath ); @@ -70,35 +71,58 @@ bool Git::setProjectPath( std::string projectPath ) { return false; } +const std::string& Git::getGitPath() const { + return mGitPath; +} + +const std::string& Git::getProjectPath() const { + return mProjectPath; +} + const std::string& Git::getGitFolder() const { return mGitFolder; } -Git::Status Git::status( std::string projectDir ) { +Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) { Status s; std::string buf; git( "diff --numstat", projectDir, buf ); - auto lastNL = 0; - auto nextNL = buf.find_first_of( '\n' ); - while ( nextNL != std::string_view::npos ) { - LuaPattern pattern( "(%d+)%s+(%d+)%s+(.+)" ); - LuaPattern::Range matches[4]; - if ( pattern.matches( buf.c_str(), lastNL, matches, nextNL ) ) { - auto inserted = buf.substr( matches[1].start, matches[1].end - matches[1].start ); - auto deleted = buf.substr( matches[2].start, matches[2].end - matches[2].start ); - auto file = buf.substr( matches[3].start, matches[3].end - matches[3].start ); - int inserts; - int deletes; - if ( String::fromString( inserts, inserted ) && - String::fromString( deletes, deleted ) ) { - s.modified.push_back( { std::move( file ), inserts, deletes } ); - s.totalInserts += inserts; - s.totalDeletions += deletes; + auto parseStatus = [&s, &buf]() { + auto lastNL = 0; + auto nextNL = buf.find_first_of( '\n' ); + while ( nextNL != std::string_view::npos ) { + LuaPattern pattern( "(%d+)%s+(%d+)%s+(.+)" ); + LuaPattern::Range matches[4]; + if ( pattern.matches( buf.c_str(), lastNL, matches, nextNL ) ) { + auto inserted = buf.substr( matches[1].start, matches[1].end - matches[1].start ); + auto deleted = buf.substr( matches[2].start, matches[2].end - matches[2].start ); + auto file = buf.substr( matches[3].start, matches[3].end - matches[3].start ); + int inserts; + int deletes; + if ( String::fromString( inserts, inserted ) && + String::fromString( deletes, deleted ) ) { + s.modified.push_back( { std::move( file ), inserts, deletes } ); + s.totalInserts += inserts; + s.totalDeletions += deletes; + } } + lastNL = nextNL; + nextNL = buf.find_first_of( '\n', nextNL + 1 ); + } + }; + + parseStatus(); + + if ( recurseSubmodules ) { + bool hasSubmodules = + ( !projectDir.empty() && FileSystem::fileExists( projectDir + ".gitmodules" ) ) || + ( !mProjectPath.empty() && FileSystem::fileExists( mProjectPath + ".gitmodules" ) ); + if ( hasSubmodules ) { + git( "submodule foreach \"git diff --numstat\"", projectDir, buf ); + parseStatus(); } - lastNL = nextNL; - nextNL = buf.find_first_of( '\n', nextNL + 1 ); } + return s; } diff --git a/src/tools/ecode/plugins/git/git.hpp b/src/tools/ecode/plugins/git/git.hpp index 7038a76de..9f3d03553 100644 --- a/src/tools/ecode/plugins/git/git.hpp +++ b/src/tools/ecode/plugins/git/git.hpp @@ -49,15 +49,15 @@ class Git { Blame blame( const std::string& filepath, std::size_t line ) const; - std::string branch( std::string projectDir = "" ); + std::string branch( const std::string& projectDir = "" ); - Status status( std::string projectDir = "" ); + Status status( bool recurseSubmodules, const std::string& projectDir = "" ); - bool setProjectPath( std::string projectPath ); + bool setProjectPath( const std::string& projectPath ); - const std::string& getGitPath() const { return mGitPath; } + const std::string& getGitPath() const; - const std::string& getProjectPath() const { return mProjectPath; } + const std::string& getProjectPath() const; const std::string& getGitFolder() const; diff --git a/src/tools/ecode/plugins/git/gitplugin.cpp b/src/tools/ecode/plugins/git/gitplugin.cpp index 3ac1861f0..b9264ef05 100644 --- a/src/tools/ecode/plugins/git/gitplugin.cpp +++ b/src/tools/ecode/plugins/git/gitplugin.cpp @@ -99,6 +99,13 @@ void GitPlugin::load( PluginManager* pluginManager ) { config["statusbar_display_modifications"] = mStatusBarDisplayModifications; updateConfigFile = true; } + + if ( config.contains( "status_recurse_submodules" ) ) + mStatusRecurseSubmodules = config.value( "status_recurse_submodules", true ); + else { + config["status_recurse_submodules"] = mStatusRecurseSubmodules; + updateConfigFile = true; + } } if ( mKeyBindings.empty() ) { @@ -160,12 +167,17 @@ void GitPlugin::updateStatusBar( bool force ) { mThreadPool->run( [this, force] { if ( !mGit ) return; - auto prevBranch = mGitBranch; - mGitBranch = mGit->branch(); - auto prevGitStatus = mGitStatus; - mGitStatus = mGit->status(); - if ( !force && mGitBranch == prevBranch && mGitStatus == prevGitStatus ) + + if ( !mGit->getGitFolder().empty() ) { + auto prevBranch = mGitBranch; + mGitBranch = mGit->branch(); + auto prevGitStatus = mGitStatus; + mGitStatus = mGit->status( mStatusRecurseSubmodules ); + if ( !force && mGitBranch == prevBranch && mGitStatus == prevGitStatus ) + return; + } else if ( !mStatusButton ) { return; + } getUISceneNode()->runOnMainThread( [this] { if ( !mStatusBar ) @@ -191,6 +203,11 @@ void GitPlugin::updateStatusBar( bool force ) { mStatusButton->toPosition( mStatusBar->getChildCount() - 2 ); } + mStatusButton->setVisible( !mGit->getGitFolder().empty() ); + + if ( mGit->getGitFolder().empty() ) + return; + std::string text( mStatusBarDisplayModifications && ( mGitStatus.totalInserts || mGitStatus.totalDeletions ) ? String::format( "%s (+%d / -%d)", mGitBranch.c_str(), @@ -231,8 +248,10 @@ void GitPlugin::updateStatusBar( bool force ) { PluginRequestHandle GitPlugin::processMessage( const PluginMessage& msg ) { switch ( msg.type ) { case PluginMessageType::WorkspaceFolderChanged: { - if ( mGit ) + if ( mGit ) { mGit->setProjectPath( msg.asJSON()["folder"] ); + updateUINow( true ); + } break; } case ecode::PluginMessageType::UIReady: { @@ -285,11 +304,15 @@ void GitPlugin::displayTooltip( UICodeEditor* editor, const Git::Blame& blame, editor->setTooltipText( str ); mTooltipInfoShowing = true; + mOldBackgroundColor = tooltip->getBackgroundColor(); + if ( Color::Transparent == mOldBackgroundColor ) { + tooltip->reloadStyle( true, true, true, true ); + mOldBackgroundColor = tooltip->getBackgroundColor(); + } mOldTextStyle = tooltip->getFontStyle(); mOldTextAlign = tooltip->getHorizontalAlign(); mOldDontAutoHideOnMouseMove = tooltip->dontAutoHideOnMouseMove(); mOldUsingCustomStyling = tooltip->getUsingCustomStyling(); - mOldBackgroundColor = tooltip->getBackgroundColor(); tooltip->setHorizontalAlign( UI_HALIGN_LEFT ); tooltip->setPixelsPosition( tooltip->getTooltipPosition( position ) ); tooltip->setDontAutoHideOnMouseMove( true ); diff --git a/src/tools/ecode/plugins/git/gitplugin.hpp b/src/tools/ecode/plugins/git/gitplugin.hpp index e1f8bd6b4..54340b6e3 100644 --- a/src/tools/ecode/plugins/git/gitplugin.hpp +++ b/src/tools/ecode/plugins/git/gitplugin.hpp @@ -70,6 +70,7 @@ class GitPlugin : public PluginBase { bool mTooltipInfoShowing{ false }; bool mStatusBarDisplayBranch{ true }; bool mStatusBarDisplayModifications{ true }; + bool mStatusRecurseSubmodules{ true }; bool mOldDontAutoHideOnMouseMove{ false }; bool mOldUsingCustomStyling{ false }; Uint32 mOldTextStyle{ 0 }; diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index 8b72ec634..58e4a407b 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -1446,6 +1446,10 @@ void LSPClientPlugin::displayTooltip( UICodeEditor* editor, const LSPHover& resp mOldDontAutoHideOnMouseMove = tooltip->dontAutoHideOnMouseMove(); mOldUsingCustomStyling = tooltip->getUsingCustomStyling(); mOldBackgroundColor = tooltip->getBackgroundColor(); + if ( Color::Transparent == mOldBackgroundColor ) { + tooltip->reloadStyle( true, true, true, true ); + mOldBackgroundColor = tooltip->getBackgroundColor(); + } tooltip->setHorizontalAlign( UI_HALIGN_LEFT ); tooltip->setPixelsPosition( tooltip->getTooltipPosition( position ) ); tooltip->setDontAutoHideOnMouseMove( true );