From 4cd44bf04123d70432b35e67dadba1bf1e8302cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sat, 27 Jan 2024 17:58:48 -0300 Subject: [PATCH] More fixes in Git plugin. --- include/eepp/ui/uilistbox.hpp | 2 + src/eepp/core/memorymanager.cpp | 8 +- src/eepp/ui/uilistbox.cpp | 4 + src/tools/ecode/plugins/git/git.cpp | 29 ++++-- src/tools/ecode/plugins/git/git.hpp | 24 ++++- src/tools/ecode/plugins/git/gitplugin.cpp | 106 +++++++++++++++++----- 6 files changed, 135 insertions(+), 38 deletions(-) diff --git a/include/eepp/ui/uilistbox.hpp b/include/eepp/ui/uilistbox.hpp index a052ab1c2..951fc1fb0 100644 --- a/include/eepp/ui/uilistbox.hpp +++ b/include/eepp/ui/uilistbox.hpp @@ -59,6 +59,8 @@ class EE_API UIListBox : public UITouchDraggableWidget { String getItemSelectedText() const; + const std::vector& getItemsText() const; + Uint32 getItemSelectedIndex() const; bool hasSelection() const; diff --git a/src/eepp/core/memorymanager.cpp b/src/eepp/core/memorymanager.cpp index 91d1708e7..99a08d022 100644 --- a/src/eepp/core/memorymanager.cpp +++ b/src/eepp/core/memorymanager.cpp @@ -108,15 +108,15 @@ bool MemoryManager::removePointer( void* data, const char* file, const size_t& l AllocatedPointerMapIt it = sMapPointers.find( data ); - if ( it->second.mTrack ) - eePRINTL( "Deleting pointer %p at '%s' %d", data, file, line ); - if ( it == sMapPointers.end() ) { eePRINTL( "Trying to delete pointer %p created that does not exist!", data ); - + eeASSERT( false ); return false; } + if ( it->second.mTrack ) + eePRINTL( "Deleting pointer %p at '%s' %d", data, file, line ); + sTotalMemoryUsage -= it->second.mMemory; sMapPointers.erase( it ); diff --git a/src/eepp/ui/uilistbox.cpp b/src/eepp/ui/uilistbox.cpp index ee4ac42dd..35fd11c97 100644 --- a/src/eepp/ui/uilistbox.cpp +++ b/src/eepp/ui/uilistbox.cpp @@ -727,6 +727,10 @@ String UIListBox::getItemSelectedText() const { return tstr; } +const std::vector& UIListBox::getItemsText() const { + return mTexts; +} + std::vector UIListBox::getItemsSelectedIndex() const { return mSelected; } diff --git a/src/tools/ecode/plugins/git/git.cpp b/src/tools/ecode/plugins/git/git.cpp index aa6a3ac04..babadc398 100644 --- a/src/tools/ecode/plugins/git/git.cpp +++ b/src/tools/ecode/plugins/git/git.cpp @@ -1,6 +1,7 @@ #include "git.hpp" #include #include +#include #include #include #include @@ -107,6 +108,8 @@ bool Git::setProjectPath( const std::string& projectPath ) { auto lastProjectPath = mProjectPath; mProjectPath = ""; mGitFolder = ""; + mSubModules = {}; + mSubModulesUpdated = true; FileInfo f( projectPath ); if ( !f.isDirectory() ) return false; @@ -233,7 +236,7 @@ Git::Result Git::deleteBranch( const std::string& branch, const std::string& pro return gitSimple( String::format( "branch -D %s", branch ), projectDir ); } -Git::Result Git::commit( const std::string& commitMsg, bool ammend, +Git::Result Git::commit( const std::string& commitMsg, bool ammend, bool byPassCommitHook, const std::string& projectDir ) { auto tmpPath = Sys::getTempPath() + ".ecode-git-commit-" + String::randString( 16 ); if ( !FileSystem::fileWrite( tmpPath, commitMsg ) ) { @@ -243,9 +246,16 @@ Git::Result Git::commit( const std::string& commitMsg, bool ammend, return res; } std::string buf; - int retCode = git( String::format( "commit %s --cleanup=whitespace --allow-empty --file=%s", - ammend ? "--ammend" : "", tmpPath ), - projectDir, buf ); + std::string opts; + if ( ammend ) + opts += " --ammend"; + + if ( byPassCommitHook ) + opts += " --no-verify"; + + int retCode = git( + String::format( "commit %s --cleanup=whitespace --allow-empty --file=%s", opts, tmpPath ), + projectDir, buf ); FileSystem::fileRemove( tmpPath ); Git::Result res; res.returnCode = retCode; @@ -439,6 +449,7 @@ std::vector Git::fetchSubModules( const std::string& projectDir ) { } std::vector Git::getSubModules( const std::string& projectDir ) { + Lock l( mSubModulesMutex ); if ( !mSubModulesUpdated ) { mSubModules = fetchSubModules( projectDir ); mSubModulesUpdated = true; @@ -451,9 +462,11 @@ bool Git::hasSubmodules( const std::string& projectDir ) { ( !mProjectPath.empty() && FileSystem::fileExists( mProjectPath + ".gitmodules" ) ); } -std::string Git::repoName( const std::string& file, const std::string& projectDir ) { +std::string Git::repoName( const std::string& file, bool allowExactMatch, + const std::string& projectDir ) { for ( const auto& subRepo : mSubModules ) { - if ( String::startsWith( file, subRepo ) && file.size() != subRepo.size() ) + if ( String::startsWith( file, subRepo ) && + ( allowExactMatch || file.size() != subRepo.size() ) ) return subRepo; } return FileSystem::fileNameFromPath( !projectDir.empty() ? projectDir : mProjectPath ); @@ -523,7 +536,7 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) status.type == GitStatusType::Staged && statusStr[1] != ' '; auto filePath = subModulePath + file; - auto repo = repoName( filePath, projectDir ); + auto repo = repoName( filePath, false, projectDir ); auto repoIt = s.files.find( repo ); bool found = false; if ( repoIt != s.files.end() ) { @@ -576,7 +589,7 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) if ( String::fromString( inserts, inserted ) && String::fromString( deletes, deleted ) && ( inserts || deletes ) ) { auto filePath = subModulePath + file; - auto repo = repoName( filePath, projectDir ); + auto repo = repoName( filePath, false, projectDir ); auto repoIt = s.files.find( repo ); GitStatusReport status = { GitStatus::NotSet, GitStatusType::Untracked, GitStatusChar::Untracked }; diff --git a/src/tools/ecode/plugins/git/git.hpp b/src/tools/ecode/plugins/git/git.hpp index 10d0e6e12..a2cda1e6e 100644 --- a/src/tools/ecode/plugins/git/git.hpp +++ b/src/tools/ecode/plugins/git/git.hpp @@ -7,6 +7,10 @@ #include #include +#include + +using namespace EE::System; + namespace ecode { #define git_xy( x, y ) ( ( (uint16_t)x ) << 8 | y ) @@ -137,6 +141,19 @@ class Git { return totalInserts == other.totalInserts && totalDeletions == other.totalDeletions && files == other.files; } + + bool empty() { return totalInserts == 0 && totalDeletions == 0 && files.empty(); } + + bool hasStagedChanges( const std::string& repoName ) { + auto found = files.find( repoName ); + if ( found != files.end() ) { + for ( const auto& file : found->second ) { + if ( file.report.type == GitStatusType::Staged ) + return true; + } + } + return false; + } }; struct Result { @@ -228,7 +245,8 @@ class Git { Result deleteBranch( const std::string& branch, const std::string& projectDir = "" ); - Result commit( const std::string& commitMsg, bool ammend, const std::string& projectDir = "" ); + Result commit( const std::string& commitMsg, bool ammend, bool byPassCommitHook, + const std::string& projectDir = "" ); Result fetch( const std::string& projectDir = "" ); @@ -284,7 +302,8 @@ class Git { std::vector getSubModules( const std::string& projectDir = "" ); - std::string repoName( const std::string& file, const std::string& projectDir = "" ); + std::string repoName( const std::string& file, bool allowExactMatch = false, + const std::string& projectDir = "" ); std::string repoPath( const std::string& file ); @@ -299,6 +318,7 @@ class Git { std::string mProjectPath; std::string mGitFolder; std::vector mSubModules; + Mutex mSubModulesMutex; bool mSubModulesUpdated{ false }; }; diff --git a/src/tools/ecode/plugins/git/gitplugin.cpp b/src/tools/ecode/plugins/git/gitplugin.cpp index 2e5627cc2..3f8c9351b 100644 --- a/src/tools/ecode/plugins/git/gitplugin.cpp +++ b/src/tools/ecode/plugins/git/gitplugin.cpp @@ -216,6 +216,8 @@ void GitPlugin::updateStatusBarSync() { mStatusTree->setModel( GitStatusModel::asModel( mGitStatus.files, this ) ); } mStatusTree->expandAll(); + } else { + return; } if ( !mStatusBarDisplayBranch ) @@ -295,8 +297,10 @@ void GitPlugin::updateStatus( bool force ) { mRunningUpdateStatus++; mThreadPool->run( [this, force] { - if ( !mGit || mGit->getGitFolder().empty() ) + if ( !mGit || mGit->getGitFolder().empty() ) { + getUISceneNode()->runOnMainThread( [this] { updateStatusBarSync(); } ); return; + } auto prevBranch = updateReposBranches(); Git::Status prevGitStatus; @@ -323,11 +327,21 @@ PluginRequestHandle GitPlugin::processMessage( const PluginMessage& msg ) { if ( mGit ) { mGit->setProjectPath( msg.asJSON()["folder"] ); + { + Lock l( mGitBranchMutex ); + mGitBranches.clear(); + } + { Lock l( mRepoMutex ); mProjectPath = mRepoSelected = mGit->getProjectPath(); } + { + Lock l( mReposMutex ); + mRepos.clear(); + } + updateUINow( true ); mInitialized = true; } @@ -626,45 +640,66 @@ void GitPlugin::branchCreate() { } void GitPlugin::commit( const std::string& repoPath ) { + if ( !mGitStatus.hasStagedChanges( mGit->repoName( repoPath, true ) ) ) { + UIMessageBox* msgBox = UIMessageBox::New( + UIMessageBox::OK, i18n( "git_nothing_to_commit", "Nothing to Commit" ) ); + msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); + msgBox->setTitle( i18n( "git_nothing_to_commit", "Nothing to Commit" ) ); + msgBox->center(); + msgBox->showWhenReady(); + return; + } + UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::TEXT_EDIT, i18n( "git_commit_message", "Commit Message:" ) ); - UICheckBox* chkBox = UICheckBox::New(); - chkBox->setLayoutMargin( Rectf( 0, 8, 0, 0 ) ) + UICheckBox* chkAmmend = UICheckBox::New(); + chkAmmend->setLayoutMargin( Rectf( 0, 8, 0, 0 ) ) ->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::WrapContent ) ->setLayoutGravity( UI_HALIGN_LEFT | UI_VALIGN_CENTER ) ->setClipType( ClipType::None ) ->setParent( msgBox->getLayoutCont()->getFirstChild() ) ->setId( "git-ammend" ); - chkBox->setText( i18n( "git_ammend", "Ammend last commit" ) ); - chkBox->toPosition( 2 ); + chkAmmend->setText( i18n( "git_ammend", "Ammend last commit" ) ); + chkAmmend->toPosition( 2 ); + + UICheckBox* chkBypassHook = UICheckBox::New(); + chkBypassHook->setLayoutMargin( Rectf( 0, 8, 0, 0 ) ) + ->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::WrapContent ) + ->setLayoutGravity( UI_HALIGN_LEFT | UI_VALIGN_CENTER ) + ->setClipType( ClipType::None ) + ->setParent( msgBox->getLayoutCont()->getFirstChild() ) + ->setId( "git-bypass-hook" ); + chkBypassHook->setText( i18n( "git_bypass_hook", "Bypass commit hook" ) ); + chkBypassHook->toPosition( 3 ); if ( !repoPath.empty() ) { auto branchName = mGitBranches[repoPath]; if ( !branchName.empty() ) { - if ( repoPath != repoSelected() || mBranchesTree->getModel() == nullptr ) { - + if ( repoPath != repoSelected() || !mBranchesTree->getModel() ) { auto branch = mGit->getAllBranchesAndTags( Git::RefType::All, "refs/heads/" + branchName, repoPath ); if ( !branch.empty() ) - chkBox->setEnabled( branch.front().ahead > 0 ); - + chkAmmend->setEnabled( branch.front().ahead > 0 ); } else { auto model = static_cast( mBranchesTree->getModel() ); auto branch = model->branch( branchName ); if ( !branch.name.empty() ) - chkBox->setEnabled( branch.ahead > 0 ); + chkAmmend->setEnabled( branch.ahead > 0 ); } } } - msgBox->on( Event::OnConfirm, [this, msgBox, chkBox]( const Event* ) { + msgBox->on( Event::OnConfirm, [this, msgBox, chkAmmend, chkBypassHook]( const Event* ) { std::string msg( msgBox->getTextEdit()->getText().toUtf8() ); if ( msg.empty() ) return; + bool ammend = chkAmmend->isChecked(); + bool bypassHook = chkBypassHook->isChecked(); msgBox->closeWindow(); - runAsync( [this, msg, chkBox]() { return mGit->commit( msg, chkBox->isChecked() ); }, true, - true ); + runAsync( + [this, msg, ammend, bypassHook]() { return mGit->commit( msg, ammend, bypassHook ); }, + true, true ); } ); msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); @@ -859,15 +894,17 @@ void GitPlugin::updateBranches( bool force ) { mRunningUpdateBranches++; mThreadPool->run( [this] { - if ( !mGit || mGit->getGitFolder().empty() ) + if ( !mGit || mGit->getGitFolder().empty() ) { + getUISceneNode()->runOnMainThread( [this] { updateBranchesUI( nullptr ); } ); return; + } auto prevBranch = updateReposBranches(); auto branches = mGit->getAllBranchesAndTags( Git::RefType::All, {}, repoSelected() ); auto hash = GitBranchModel::hashBranches( branches ); auto model = GitBranchModel::asModel( std::move( branches ), hash, this ); - if ( mBranchesTree && + if ( mBranchesTree && mBranchesTree->getModel() && static_cast( mBranchesTree->getModel() )->getHash() == hash ) { if ( prevBranch != mGitBranches ) mBranchesTree->getModel()->invalidate( Model::DontInvalidateIndexes ); @@ -903,17 +940,38 @@ void GitPlugin::updateRepos() { void GitPlugin::updateBranchesUI( std::shared_ptr model ) { buildSidePanelTab(); - mBranchesTree->setModel( model ); - mBranchesTree->setColumnsVisible( { GitBranchModel::Name } ); - mBranchesTree->expandAll(); + + if ( !model ) { + mBranchesTree->setModel( model ); + } else { + mBranchesTree->setModel( model ); + mBranchesTree->setColumnsVisible( { GitBranchModel::Name } ); + mBranchesTree->expandAll(); + } + updateRepos(); + std::vector items; - for ( const auto& repo : mRepos ) + std::unordered_map repos; + { + Lock l( mReposMutex ); + repos = mRepos; + } + + for ( const auto& repo : repos ) items.push_back( repo.second ); - mRepoDropDown->getListBox()->clear(); - mRepoDropDown->getListBox()->addListBoxItems( items ); - mRepoDropDown->getListBox()->setSelected( mRepos[repoSelected()] ); + if ( repos.empty() || ( repos.size() == 1 && repos.begin()->second == "" ) ) { + if ( !mRepoDropDown->getListBox()->isEmpty() ) + mRepoDropDown->getListBox()->clear(); + return; + } + + if ( mRepoDropDown->getListBox()->getItemsText() != items ) { + mRepoDropDown->getListBox()->clear(); + mRepoDropDown->getListBox()->addListBoxItems( items ); + mRepoDropDown->getListBox()->setSelected( mRepos[repoSelected()] ); + } } void GitPlugin::buildSidePanelTab() { @@ -998,7 +1056,7 @@ void GitPlugin::buildSidePanelTab() { mBranchesTree->on( Event::KeyDown, [this]( const Event* event ) { const KeyEvent* keyEvent = event->asKeyEvent(); ModelIndex modelIndex = mBranchesTree->getSelection().first(); - if ( !modelIndex.isValid() || modelIndex.internalId() == -1 ) + if ( !modelIndex.isValid() || modelIndex.internalId() == -1 || !mBranchesTree->getModel() ) return; Git::Branch branch = static_cast( mBranchesTree->getModel() )->branch( modelIndex ); @@ -1224,7 +1282,7 @@ void GitPlugin::runAsync( std::function fn, bool _updateStatus, b mLoader->setVisible( true ); mThreadPool->run( [this, fn, _updateStatus, _updateBranches, displaySuccessMsg] { auto res = fn(); - getUISceneNode()->runOnMainThread( [this] { mLoader->setVisible( false ); } ); + mLoader->runOnMainThread( [this] { mLoader->setVisible( false ); } ); if ( res.fail() || displaySuccessMsg ) { showMessage( LSPMessageType::Warning, res.result ); return;