Skip to content

Commit

Permalink
Git Status displayed with state grouping
Browse files Browse the repository at this point in the history
  • Loading branch information
SpartanJ committed Jan 19, 2024
1 parent ff40471 commit 948ff5a
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 24 deletions.
2 changes: 1 addition & 1 deletion include/eepp/ui/uitreeview.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class EE_API UITreeView : public UIAbstractTableView {

void traverseTree( TreeViewCallback ) const;

mutable std::map<void*, MetadataForIndex> mViewMetadata;
mutable UnorderedMap<void*, MetadataForIndex> mViewMetadata;

virtual size_t getItemCount() const;

Expand Down
18 changes: 11 additions & 7 deletions src/eepp/ui/uitreeview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,13 +280,17 @@ UIWidget* UITreeView::updateCell( const int& rowIndex, const ModelIndex& index,
UIIcon* icon = getIndexMetadata( index ).open ? mExpandIcon : mContractIcon;
Drawable* drawable = icon ? icon->getSize( mExpanderIconSize ) : nullptr;

image->setVisible( true );
image->setPixelsSize( drawable ? drawable->getPixelsSize() : Sizef( 0, 0 ) );
image->setDrawable( drawable );
if ( !mExpandersAsIcons ) {
tcell->setIndentation( tcell->getIndentation() -
image->getPixelsSize().getWidth() -
PixelDensity::dpToPx( image->getLayoutMargin().Right ) );
if ( drawable == nullptr ) {
image->setVisible( false );
} else {
image->setVisible( true );
image->setPixelsSize( drawable ? drawable->getPixelsSize() : Sizef( 0, 0 ) );
image->setDrawable( drawable );
if ( !mExpandersAsIcons ) {
tcell->setIndentation(
tcell->getIndentation() - image->getPixelsSize().getWidth() -
PixelDensity::dpToPx( image->getLayoutMargin().Right ) );
}
}
} else {
image->setVisible( false );
Expand Down
7 changes: 7 additions & 0 deletions src/tools/ecode/plugins/git/git.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ std::string Git::inSubModule( const std::string& file, const std::string& projec

Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) {
static constexpr auto DIFF_CMD = "diff --numstat";
static constexpr auto DIFF_STAGED_CMD = "diff --numstat --staged";
static constexpr auto STATUS_CMD = "-c color.status=never status -b -u -s";
Status s;
std::string buf;
Expand Down Expand Up @@ -327,11 +328,17 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir )

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();
}

bool modifiedSubmodule = false;
Expand Down
4 changes: 2 additions & 2 deletions src/tools/ecode/plugins/git/git.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ class Git {
};

enum class GitStatusType {
Staged,
Changed,
Untracked,
Unmerged,
Changed,
Staged,
Ignored,
};

Expand Down
161 changes: 147 additions & 14 deletions src/tools/ecode/plugins/git/gitplugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <eepp/system/scopedop.hpp>
#include <eepp/ui/doc/syntaxdefinitionmanager.hpp>
#include <eepp/ui/uidropdownlist.hpp>
#include <eepp/ui/uiiconthememanager.hpp>
#include <eepp/ui/uipopupmenu.hpp>
#include <eepp/ui/uistackwidget.hpp>
#include <eepp/ui/uistyle.hpp>
Expand All @@ -30,6 +31,22 @@ static const char* GIT_NOT_BOLD = "notbold";
static const std::string GIT_TAG = "tag";
static const std::string GIT_REPO = "repo";

std::string GitPlugin::statusTypeToString( Git::GitStatusType type ) {
switch ( type ) {
case Git::GitStatusType::Untracked:
return i18n( "git_untracked", "Untracked" );
case Git::GitStatusType::Unmerged:
return i18n( "git_unmerged", "Unmergedd" );
case Git::GitStatusType::Changed:
return i18n( "git_changed", "Changed" );
case Git::GitStatusType::Staged:
return i18n( "git_staged", "Staged" );
case Git::GitStatusType::Ignored:
return i18n( "git_ignored", "Ignored" );
}
return "";
}

static size_t hashBranches( const std::vector<Git::Branch>& branches ) {
size_t hash = 0;
for ( const auto& branch : branches )
Expand Down Expand Up @@ -177,56 +194,153 @@ class GitStatusModel : public Model {
return std::make_shared<GitStatusModel>( std::move( status ), gitPlugin );
}

struct RepoStatusType;
struct RepoStatus;

struct DiffFile : Git::DiffFile {
DiffFile( Git::DiffFile&& df, RepoStatusType* parent ) :
Git::DiffFile( df ), parent( parent ){};
RepoStatusType* parent;
};

struct RepoStatusType {
std::string typeStr;
Git::GitStatusType type;
std::vector<DiffFile> files;
RepoStatus* parent{ nullptr };
};

struct RepoStatus {
std::string repo;
std::vector<Git::DiffFile> files;
std::vector<RepoStatusType> type;
};

enum Column { File, State, Inserted, Removed, RelativeDirectory };

GitStatusModel( Git::FilesStatus&& status, GitPlugin* gitPlugin ) : mPlugin( gitPlugin ) {
mStatus.reserve( status.size() );
std::map<std::string, std::set<Git::GitStatusType>> typesFound;
std::unordered_map<std::string, size_t> repoPos;
std::unordered_map<size_t, std::unordered_map<Git::GitStatusType, size_t>> repoTypePos;

for ( auto& s : status )
mStatus.emplace_back( RepoStatus{ std::move( s.first ), std::move( s.second ) } );
for ( auto& f : s.second )
typesFound[s.first].insert( f.statusType );

for ( const auto& tf : typesFound ) {
RepoStatus rs;
rs.repo = tf.first;
size_t pos = mStatus.size();
repoPos[rs.repo] = pos;
for ( const auto& s : tf.second ) {
RepoStatusType rt;
rt.typeStr = mPlugin->statusTypeToString( s );
rt.type = s;
repoTypePos[pos][s] = rs.type.size();
rs.type.emplace_back( std::move( rt ) );
}
mStatus.emplace_back( std::move( rs ) );
auto parent = &mStatus[mStatus.size() - 1];
for ( auto& t : parent->type )
t.parent = parent;
}

for ( auto& s : status ) {
for ( auto& fv : s.second ) {
auto pos = repoPos[s.first];
auto typePos = repoTypePos[pos][fv.statusType];
DiffFile df( std::move( fv ), &mStatus[pos].type[typePos] );
mStatus[pos].type[typePos].files.emplace_back( std::move( df ) );
}
}
}

size_t treeColumn() const { return Column::File; }

size_t rowCount( const ModelIndex& index ) const {
if ( !index.isValid() )
return mStatus.size();
if ( index.internalId() == -1 )
return mStatus[index.row()].files.size();

if ( index.internalId() == Repo )
return mStatus[index.row()].type.size();

if ( index.internalId() == Status )
return mStatus[index.parent().row()].type[index.row()].files.size();

return 0;
}

size_t columnCount( const ModelIndex& ) const { return 5; }

ModelIndex parentIndex( const ModelIndex& index ) const {
if ( !index.isValid() || index.internalId() == -1 )
if ( !index.isValid() || index.internalId() == Repo )
return {};
return createIndex( index.internalId(), index.column(), &mStatus[index.internalId()], -1 );

if ( index.internalId() == Status ) {
RepoStatusType* status = reinterpret_cast<RepoStatusType*>( index.internalData() );
size_t f = 0;
for ( size_t i = 0; i < mStatus.size(); i++ ) {
if ( &mStatus[i] == status->parent ) {
f = i;
break;
}
}
return createIndex( f, index.column(), status->parent, Repo );
}

if ( index.internalId() == GitFile ) {
DiffFile* file = reinterpret_cast<DiffFile*>( index.internalData() );
RepoStatusType* status = file->parent;
size_t f = 0;
for ( size_t i = 0; i < status->parent->type.size(); i++ ) {
if ( &status->parent->type[i] == status ) {
f = i;
break;
}
}
return createIndex( f, index.column(), status, Status );
}

return {};
}

enum ModelCategory { Repo, Status, GitFile };

ModelIndex index( int row, int column, const ModelIndex& parent ) const {
if ( row < 0 || column < 0 )
return {};

if ( !parent.isValid() )
return createIndex( row, column, &mStatus[row], -1 );
if ( parent.internalData() )
return createIndex( row, column, &mStatus[parent.row()].files[row], parent.row() );
return createIndex( row, column, &mStatus[row], Repo );

if ( parent.internalId() == Repo )
return createIndex( row, column, &mStatus[parent.row()].type[row], Status );

if ( parent.internalId() == Status ) {
size_t pprow = parent.parent().row();
size_t prow = parent.row();
return createIndex( row, column, &mStatus[pprow].type[prow].files[row], GitFile );
}

return {};
}

Variant data( const ModelIndex& index, ModelRole role ) const {
switch ( role ) {
case ModelRole::Display: {
if ( index.internalId() == -1 ) {
if ( index.internalId() == Repo ) {
if ( index.column() == Column::File )
return Variant( mStatus[index.row()].repo.c_str() );
return Variant( GIT_EMPTY );
} else if ( index.internalId() == Status ) {
if ( index.column() == Column::File ) {
return Variant(
mStatus[index.parent().row()].type[index.row()].typeStr.c_str() );
}
return Variant( GIT_EMPTY );
}
const Git::DiffFile& s = mStatus[index.internalId()].files[index.row()];
const Git::DiffFile& s = mStatus[index.parent().parent().row()]
.type[index.parent().row()]
.files[index.row()];
switch ( index.column() ) {
case Column::File:
return Variant( FileSystem::fileNameFromPath( s.file ) );
Expand All @@ -242,7 +356,7 @@ class GitStatusModel : public Model {
break;
}
case ModelRole::Class: {
if ( index.internalId() != -1 ) {
if ( index.internalId() == GitFile ) {
switch ( index.column() ) {
case Column::Inserted:
return Variant( GIT_SUCCESS );
Expand All @@ -254,6 +368,26 @@ class GitStatusModel : public Model {
}
break;
}
case ModelRole::Icon: {
if ( (Int64)treeColumn() == index.column() ) {
if ( index.internalId() == Repo ) {
return Variant(
mPlugin->getManager()->getUISceneNode()->findIcon( "repo" ) );
} else if ( index.internalId() == GitFile ) {
const Git::DiffFile& s = mStatus[index.parent().parent().row()]
.type[index.parent().row()]
.files[index.row()];
std::string iconName =
UIIconThemeManager::getIconNameFromFileName( s.file );
auto* scene = mPlugin->getUISceneNode();
auto* d = scene->findIcon( iconName );
if ( !d )
return scene->findIcon( "file" );
return d;
}
}
break;
}
default:
break;
}
Expand Down Expand Up @@ -897,7 +1031,6 @@ void GitPlugin::buildSidePanelTab() {

mStatusTree->setAutoColumnsWidth( true );
mStatusTree->setHeadersVisible( false );
mStatusTree->setIndentWidth( 0 );
}

} // namespace ecode
2 changes: 2 additions & 0 deletions src/tools/ecode/plugins/git/gitplugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class GitPlugin : public PluginBase {

std::string gitBranch();

std::string statusTypeToString( Git::GitStatusType type );

protected:
std::unique_ptr<Git> mGit;
std::string mGitBranch;
Expand Down

0 comments on commit 948ff5a

Please sign in to comment.