From bed3581364fd771d7cf67382b18ad8f532502d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Fri, 26 Jan 2024 09:46:00 -0300 Subject: [PATCH] Git status: Detect staged and non-staged for a single file and generate two different statuses. Generate events for row mouse clicks. --- .../eepp/ui/abstract/uiabstracttableview.hpp | 10 +- include/eepp/ui/uitablerow.hpp | 19 ++- include/eepp/ui/uitreeview.hpp | 4 +- src/tools/ecode/plugins/git/git.cpp | 151 ++++++++++-------- src/tools/ecode/plugins/git/gitplugin.cpp | 7 + 5 files changed, 113 insertions(+), 78 deletions(-) diff --git a/include/eepp/ui/abstract/uiabstracttableview.hpp b/include/eepp/ui/abstract/uiabstracttableview.hpp index 05ba1ea61..8831fa9e7 100644 --- a/include/eepp/ui/abstract/uiabstracttableview.hpp +++ b/include/eepp/ui/abstract/uiabstracttableview.hpp @@ -116,6 +116,11 @@ class EE_API UIAbstractTableView : public UIAbstractView { UITableCell* getCellFromIndex( const ModelIndex& index ) const; + virtual void onOpenModelIndex( const ModelIndex& index, const Event* triggerEvent = nullptr ); + + virtual void onOpenMenuModelIndex( const ModelIndex& index, + const Event* triggerEvent = nullptr ); + protected: friend class EE::UI::UITableHeaderColumn; @@ -185,11 +190,6 @@ class EE_API UIAbstractTableView : public UIAbstractView { virtual void onScrollChange(); - virtual void onOpenModelIndex( const ModelIndex& index, const Event* triggerEvent = nullptr ); - - virtual void onOpenMenuModelIndex( const ModelIndex& index, - const Event* triggerEvent = nullptr ); - virtual void onRowCreated( UITableRow* row ); virtual void onSortColumn( const size_t& colIndex ); diff --git a/include/eepp/ui/uitablerow.hpp b/include/eepp/ui/uitablerow.hpp index 5fe7867cf..ca05964fb 100644 --- a/include/eepp/ui/uitablerow.hpp +++ b/include/eepp/ui/uitablerow.hpp @@ -29,14 +29,29 @@ class EE_API UITableRow : public UIWidget { UITableRow() : UIWidget( "table::row" ) {} + static Event::EventType isMouseEvent( Uint32 msg ) { + switch ( msg ) { + case NodeMessage::MouseClick: + return Event::MouseClick; + case NodeMessage::MouseDoubleClick: + return Event::MouseDoubleClick; + case NodeMessage::MouseDown: + return Event::MouseDown; + case NodeMessage::MouseUp: + return Event::MouseUp; + } + return Event::NoEvent; + } + virtual Uint32 onMessage( const NodeMessage* msg ) { EventDispatcher* eventDispatcher = getEventDispatcher(); Node* mouseDownNode = eventDispatcher->getMouseDownNode(); Node* draggingNode = eventDispatcher->getNodeDragging(); - if ( msg->getMsg() == NodeMessage::MouseDown && + auto eventType = isMouseEvent( msg->getMsg() ); + if ( eventType != Event::NoEvent && ( mouseDownNode == nullptr || mouseDownNode == this || isParentOf( mouseDownNode ) ) && draggingNode == nullptr ) { - sendMouseEvent( Event::MouseDown, eventDispatcher->getMousePos(), msg->getFlags() ); + sendMouseEvent( eventType, eventDispatcher->getMousePos(), msg->getFlags() ); } return 0; } diff --git a/include/eepp/ui/uitreeview.hpp b/include/eepp/ui/uitreeview.hpp index acc05ba1b..428555803 100644 --- a/include/eepp/ui/uitreeview.hpp +++ b/include/eepp/ui/uitreeview.hpp @@ -100,6 +100,8 @@ class EE_API UITreeView : public UIAbstractTableView { void updateContentSize(); + virtual void onOpenTreeModelIndex( const ModelIndex& index, bool open ); + protected: enum class IterationDecision { Continue, @@ -145,8 +147,6 @@ class EE_API UITreeView : public UIAbstractTableView { virtual Uint32 onKeyDown( const KeyEvent& event ); - virtual void onOpenTreeModelIndex( const ModelIndex& index, bool open ); - virtual void onSortColumn( const size_t& colIndex ); void setAllExpanded( const ModelIndex& index = {}, bool expanded = true ); diff --git a/src/tools/ecode/plugins/git/git.cpp b/src/tools/ecode/plugins/git/git.cpp index 2827b6eca..f5698238a 100644 --- a/src/tools/ecode/plugins/git/git.cpp +++ b/src/tools/ecode/plugins/git/git.cpp @@ -478,82 +478,21 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) static constexpr auto STATUS_CMD = "-c color.status=never status -b -u -s"; Status s; std::string buf; - if ( EXIT_SUCCESS != git( DIFF_CMD, projectDir, buf ) ) - return s; getSubModules( projectDir ); - - LuaPattern subModulePattern( "^Entering '(.*)'" ); - - auto parseNumStat = [&s, &buf, &projectDir, this, &subModulePattern]() { - LuaPattern pattern( "(%d+)%s+(%d+)%s+(.+)" ); - std::string subModulePath = ""; - readAllLines( buf, [&]( const std::string_view& line ) { - LuaPattern::Range matches[4]; - if ( subModulePattern.matches( line.data(), 0, matches, line.size() ) ) { - subModulePath = String::trim( - line.substr( matches[1].start, matches[1].end - matches[1].start ) ); - FileSystem::dirAddSlashAtEnd( subModulePath ); - } else if ( pattern.matches( line.data(), 0, matches, line.size() ) ) { - auto inserted = line.substr( matches[1].start, matches[1].end - matches[1].start ); - auto deleted = line.substr( matches[2].start, matches[2].end - matches[2].start ); - auto file = line.substr( matches[3].start, matches[3].end - matches[3].start ); - int inserts; - int deletes; - if ( String::fromString( inserts, inserted ) && - String::fromString( deletes, deleted ) && ( inserts || deletes ) ) { - auto filePath = subModulePath + file; - auto repo = repoName( filePath, projectDir ); - auto repoIt = s.files.find( repo ); - GitStatusReport status = { GitStatus::NotSet, GitStatusType::Untracked, - GitStatusChar::Untracked }; - if ( repoIt != s.files.end() ) { - bool found = false; - for ( auto& fileIt : repoIt->second ) { - if ( fileIt.file == filePath ) { - fileIt.inserts = inserts; - fileIt.deletes = deletes; - found = true; - break; - } - } - if ( !found ) { - s.files[repo].push_back( - { std::move( filePath ), inserts, deletes, status } ); - } - } else { - s.files.insert( - { repo, { { std::move( filePath ), inserts, deletes, status } } } ); - } - s.totalInserts += inserts; - s.totalDeletions += deletes; - } - } - } ); - }; - - parseNumStat(); - - git( DIFF_STAGED_CMD, projectDir, buf ); - parseNumStat(); - bool submodules = hasSubmodules( projectDir ); - if ( recurseSubmodules && submodules ) { - gitSubmodules( DIFF_CMD, projectDir, buf ); - parseNumStat(); - - gitSubmodules( DIFF_STAGED_CMD, projectDir, buf ); - parseNumStat(); - } + LuaPattern subModulePattern( "^Entering '(.*)'" ); bool modifiedSubmodule = false; auto parseStatus = [&s, &buf, &modifiedSubmodule, &projectDir, this, &subModulePattern]() { std::string subModulePath = ""; LuaPattern pattern( "^([mMARTUD?%s][mMARTUD?%s])%s(.*)" ); size_t changesCount = countLines( buf ); + if ( changesCount > 1000 ) return; + readAllLines( buf, [&]( const std::string_view& line ) { LuaPattern::Range matches[3]; if ( subModulePattern.matches( line.data(), 0, matches, line.size() ) ) { @@ -576,11 +515,14 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) return; } + bool isStagedAndModified = + status.type == GitStatusType::Staged && statusStr[1] != ' '; + auto filePath = subModulePath + file; auto repo = repoName( filePath, projectDir ); auto repoIt = s.files.find( repo ); + bool found = false; if ( repoIt != s.files.end() ) { - bool found = false; for ( auto& fileIt : repoIt->second ) { if ( fileIt.file == filePath ) { fileIt.report = status; @@ -588,16 +530,23 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) break; } } - if ( !found ) + } + if ( !found ) { + s.files[repo].push_back( { std::move( filePath ), 0, 0, status } ); + + if ( isStagedAndModified ) { + status.type = GitStatusType::Changed; + s.files[repo].push_back( { std::move( filePath ), 0, 0, status } ); - } else { - s.files.insert( { repo, { { std::move( filePath ), 0, 0, status } } } ); + } } } } ); }; - git( STATUS_CMD, projectDir, buf ); + if ( EXIT_SUCCESS != git( STATUS_CMD, projectDir, buf ) ) + return s; + parseStatus(); if ( modifiedSubmodule && recurseSubmodules && submodules ) { @@ -605,6 +554,70 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) parseStatus(); } + auto parseNumStat = [&s, &buf, &projectDir, this, &subModulePattern]( bool isStaged ) { + LuaPattern pattern( "(%d+)%s+(%d+)%s+(.+)" ); + std::string subModulePath = ""; + readAllLines( buf, [&]( const std::string_view& line ) { + LuaPattern::Range matches[4]; + if ( subModulePattern.matches( line.data(), 0, matches, line.size() ) ) { + subModulePath = String::trim( + line.substr( matches[1].start, matches[1].end - matches[1].start ) ); + FileSystem::dirAddSlashAtEnd( subModulePath ); + } else if ( pattern.matches( line.data(), 0, matches, line.size() ) ) { + auto inserted = line.substr( matches[1].start, matches[1].end - matches[1].start ); + auto deleted = line.substr( matches[2].start, matches[2].end - matches[2].start ); + auto file = line.substr( matches[3].start, matches[3].end - matches[3].start ); + int inserts; + int deletes; + if ( String::fromString( inserts, inserted ) && + String::fromString( deletes, deleted ) && ( inserts || deletes ) ) { + auto filePath = subModulePath + file; + auto repo = repoName( filePath, projectDir ); + auto repoIt = s.files.find( repo ); + GitStatusReport status = { GitStatus::NotSet, GitStatusType::Untracked, + GitStatusChar::Untracked }; + bool found = false; + if ( repoIt != s.files.end() ) { + for ( auto& fileIt : repoIt->second ) { + if ( fileIt.file == filePath ) { + if ( isStaged && fileIt.report.type != Git::GitStatusType::Staged ) + continue; + if ( !isStaged && fileIt.report.type == Git::GitStatusType::Staged ) + continue; + fileIt.inserts = inserts; + fileIt.deletes = deletes; + found = true; + break; + } + } + } + if ( !found ) { + s.files[repo].push_back( + { std::move( filePath ), inserts, deletes, status } ); + } + s.totalInserts += inserts; + s.totalDeletions += deletes; + } + } + } ); + }; + + if ( EXIT_SUCCESS != git( DIFF_CMD, projectDir, buf ) ) + return s; + + parseNumStat( false ); + + git( DIFF_STAGED_CMD, projectDir, buf ); + parseNumStat( true ); + + if ( recurseSubmodules && submodules ) { + gitSubmodules( DIFF_CMD, projectDir, buf ); + parseNumStat( false ); + + gitSubmodules( DIFF_STAGED_CMD, projectDir, buf ); + parseNumStat( true ); + } + for ( auto& [_, repo] : s.files ) { for ( auto& val : repo ) { if ( val.report.symbol == GitStatusChar::Added && val.inserts == 0 ) { diff --git a/src/tools/ecode/plugins/git/gitplugin.cpp b/src/tools/ecode/plugins/git/gitplugin.cpp index 93c219e57..8e2b669ec 100644 --- a/src/tools/ecode/plugins/git/gitplugin.cpp +++ b/src/tools/ecode/plugins/git/gitplugin.cpp @@ -959,6 +959,13 @@ void GitPlugin::buildSidePanelTab() { mStatusTree->setAutoColumnsWidth( true ); mStatusTree->setHeadersVisible( false ); mStatusTree->setExpandersAsIcons( true ); + mStatusTree->on( Event::OnRowCreated, [this]( const Event* event ) { + UITableRow* row = event->asRowCreatedEvent()->getRow(); + row->on( Event::MouseUp, [this, row]( const Event* event ) { + if ( event->asMouseEvent()->getFlags() & EE_BUTTON_RMASK ) + mStatusTree->onOpenMenuModelIndex( row->getCurIndex(), event ); + } ); + } ); mStatusTree->on( Event::OnModelEvent, [this]( const Event* event ) { const ModelEvent* modelEvent = static_cast( event ); if ( modelEvent->getModel() == nullptr )