mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-01 18:50:16 +03:00
More Git plugin WIP. Added commit.
This commit is contained in:
@@ -1124,21 +1124,23 @@ static void addCMake() {
|
||||
for ( const auto& keyword : cmake_literals )
|
||||
cmake_symbols[keyword] = "literal";
|
||||
|
||||
SyntaxDefinitionManager::instance()->add( { "CMake",
|
||||
{ "%.cmake$", "CMakeLists.txt$" },
|
||||
{
|
||||
{ { "#", "[^\\]\n" }, "comment" },
|
||||
{ { "\"", "\"", "\\" }, "string" },
|
||||
{ { "'", "'", "\\" }, "string" },
|
||||
{ { "[%a_][%w_]*%s?%f[(]" }, "function" },
|
||||
{ { "CMAKE_[%w%d_]+" }, "keyword" },
|
||||
{ { "CTEST_[%w%d_]+" }, "keyword" },
|
||||
{ { "%u[%u%d_]*_[%u%d_]+" }, "keyword" },
|
||||
{ { "%${[%a_][%w_]*%}" }, "keyword2" },
|
||||
{ { "[%a_][%w_]*" }, "symbol" },
|
||||
},
|
||||
std::move( cmake_symbols ),
|
||||
"//" } );
|
||||
SyntaxDefinitionManager::instance()->add(
|
||||
{ "CMake",
|
||||
{ "%.cmake$", "CMakeLists.txt$" },
|
||||
{
|
||||
{ { "#", "[^\\]\n" }, "comment" },
|
||||
{ { "\"", "\"", "\\" }, "string" },
|
||||
{ { "'", "'", "\\" }, "string" },
|
||||
{ { "[%a_][%w_]*%s?%f[(]" }, "function" },
|
||||
{ { "CMAKE_[%w%d_]+" }, "keyword" },
|
||||
{ { "CTEST_[%w%d_]+" }, "keyword" },
|
||||
{ { "%u[%u%d_]*_[%u%d_]+" }, "keyword" },
|
||||
{ { "%${[%a_][%w_]*%}" }, "keyword2" },
|
||||
{ { "[%a_][%w_]*" }, "symbol" },
|
||||
},
|
||||
std::move( cmake_symbols ),
|
||||
"//",
|
||||
{ "^cmake_minimum_required.*%c" } } );
|
||||
}
|
||||
|
||||
static void addJSX() {
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
#include <eepp/ui/uilayout.hpp>
|
||||
#include <eepp/ui/uilinearlayout.hpp>
|
||||
#include <eepp/ui/uimessagebox.hpp>
|
||||
#include <eepp/ui/uipushbutton.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uistyle.hpp>
|
||||
#include <eepp/ui/uitextedit.hpp>
|
||||
#include <eepp/ui/uitextinput.hpp>
|
||||
#include <eepp/ui/uitextview.hpp>
|
||||
#include <eepp/ui/uitheme.hpp>
|
||||
|
||||
namespace EE { namespace UI {
|
||||
@@ -12,7 +17,7 @@ UIMessageBox* UIMessageBox::New( const Type& type, const String& message,
|
||||
}
|
||||
|
||||
UIMessageBox::UIMessageBox( const Type& type, const String& message, const Uint32& windowFlags ) :
|
||||
UIWindow(), mMsgBoxType( type ), mTextInput( NULL ), mCloseShortcut( KEY_UNKNOWN ) {
|
||||
UIWindow(), mMsgBoxType( type ), mCloseShortcut( KEY_UNKNOWN ) {
|
||||
mVisible = false;
|
||||
|
||||
mStyleConfig.WinFlags = windowFlags;
|
||||
@@ -41,6 +46,12 @@ UIMessageBox::UIMessageBox( const Type& type, const String& message, const Uint3
|
||||
->setParent( vlay )
|
||||
->addEventListener( Event::OnPressEnter,
|
||||
[this]( const Event* ) { sendCommonEvent( Event::OnConfirm ); } );
|
||||
} else if ( mMsgBoxType == TEXT_EDIT ) {
|
||||
mTextEdit = UITextEdit::New();
|
||||
mTextEdit->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed )
|
||||
->setLayoutMargin( Rectf( 0, 4, 0, 4 ) )
|
||||
->setSize( PixelDensity::dpToPx( Vector2f{ 400, 100 } ) )
|
||||
->setParent( vlay );
|
||||
}
|
||||
|
||||
UILinearLayout* hlay = UILinearLayout::NewHorizontal();
|
||||
@@ -58,6 +69,7 @@ UIMessageBox::UIMessageBox( const Type& type, const String& message, const Uint3
|
||||
|
||||
switch ( mMsgBoxType ) {
|
||||
case UIMessageBox::INPUT:
|
||||
case UIMessageBox::TEXT_EDIT:
|
||||
case UIMessageBox::OK_CANCEL: {
|
||||
mButtonOK->setText( getTranslatorString( "@string/msg_box_ok", "Ok" ) );
|
||||
mButtonCancel->setText( getTranslatorString( "@string/msg_box_cancel", "Cancel" ) );
|
||||
@@ -180,6 +192,10 @@ UITextInput* UIMessageBox::getTextInput() const {
|
||||
return mTextInput;
|
||||
}
|
||||
|
||||
UITextEdit* UIMessageBox::getTextEdit() const {
|
||||
return mTextEdit;
|
||||
}
|
||||
|
||||
UILayout* UIMessageBox::getLayoutCont() const {
|
||||
return mLayoutCont;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <eepp/core/string.hpp>
|
||||
#include <eepp/graphics/fontmanager.hpp>
|
||||
#include <eepp/graphics/fonttruetype.hpp>
|
||||
#include <eepp/graphics/text.hpp>
|
||||
#include <eepp/network/http.hpp>
|
||||
#include <eepp/network/uri.hpp>
|
||||
#include <eepp/scene/scenemanager.hpp>
|
||||
|
||||
@@ -9,11 +9,14 @@
|
||||
#include <eepp/scene/scenenode.hpp>
|
||||
#include <eepp/ui/css/propertydefinition.hpp>
|
||||
#include <eepp/ui/uilinearlayout.hpp>
|
||||
#include <eepp/ui/uipushbutton.hpp>
|
||||
#include <eepp/ui/uirelativelayout.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uistyle.hpp>
|
||||
#include <eepp/ui/uitextview.hpp>
|
||||
#include <eepp/ui/uithememanager.hpp>
|
||||
#include <eepp/ui/uiwindow.hpp>
|
||||
|
||||
#define PUGIXML_HEADER_ONLY
|
||||
#include <pugixml/pugixml.hpp>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <eepp/maps/mapeditor/tilemapproperties.hpp>
|
||||
#include <eepp/scene/scenemanager.hpp>
|
||||
#include <eepp/ui/uipushbutton.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uithememanager.hpp>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <eepp/maps/mapeditor/uigotypenew.hpp>
|
||||
#include <eepp/scene/scenemanager.hpp>
|
||||
#include <eepp/ui/uipushbutton.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uithememanager.hpp>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <eepp/maps/mapeditor/uimaplayernew.hpp>
|
||||
#include <eepp/scene/scenemanager.hpp>
|
||||
#include <eepp/ui/uipushbutton.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uithememanager.hpp>
|
||||
|
||||
|
||||
@@ -206,6 +206,7 @@ void IconManager::init( UISceneNode* sceneNode, FontTrueType* iconFont, FontTrue
|
||||
{ "repo", 0xea62 },
|
||||
{ "repo-pull", 0xeb40 },
|
||||
{ "repo-push", 0xeb41 },
|
||||
{ "repo-forked", 0xea63 },
|
||||
{ "tag", 0xea66 } };
|
||||
|
||||
for ( const auto& icon : codIcons )
|
||||
|
||||
@@ -182,16 +182,30 @@ Git::CheckoutResult Git::checkoutAndCreateLocalBranch( const std::string& remote
|
||||
return checkout( newBranchName, projectDir );
|
||||
}
|
||||
|
||||
Git::Result Git::add( const std::string& file, const std::string& projectDir ) {
|
||||
return gitSimple( String::format( "add --force -- \"%s\"", file ), projectDir );
|
||||
static std::string asList( std::vector<std::string>& files ) {
|
||||
for ( auto& file : files )
|
||||
file = "\"" + file + "\"";
|
||||
return String::join( files );
|
||||
}
|
||||
|
||||
Git::Result Git::add( std::vector<std::string> files, const std::string& projectDir ) {
|
||||
return gitSimple( String::format( "add --force -- %s", asList( files ) ), projectDir );
|
||||
}
|
||||
|
||||
Git::Result Git::restore( const std::string& file, const std::string& projectDir ) {
|
||||
return gitSimple( String::format( "restore \"%s\"", file ), projectDir );
|
||||
}
|
||||
|
||||
Git::Result Git::reset( const std::string& file, const std::string& projectDir ) {
|
||||
return gitSimple( String::format( "reset -q HEAD -- \"%s\"", file ), projectDir );
|
||||
Git::Result Git::reset( std::vector<std::string> files, const std::string& projectDir ) {
|
||||
return gitSimple( String::format( "reset -q HEAD -- %s", asList( files ) ), projectDir );
|
||||
}
|
||||
|
||||
Git::Result Git::createBranch( const std::string& branchName, bool _checkout,
|
||||
const std::string& projectDir ) {
|
||||
auto res = gitSimple( String::format( "branch --no-track %s", branchName ), projectDir );
|
||||
if ( _checkout )
|
||||
checkout( branchName );
|
||||
return res;
|
||||
}
|
||||
|
||||
Git::Result Git::renameBranch( const std::string& branch, const std::string& newName,
|
||||
@@ -230,6 +244,12 @@ Git::Result Git::fastForwardMerge( const std::string& projectDir ) {
|
||||
return gitSimple( "merge --no-commit --ff --ff-only", projectDir );
|
||||
}
|
||||
|
||||
Git::Result Git::updateRef( const std::string& headBranch, const std::string& toCommit,
|
||||
const std::string& projectDir ) {
|
||||
return gitSimple( String::format( "update-ref refs/heads/%s %s", headBranch, toCommit ),
|
||||
projectDir );
|
||||
}
|
||||
|
||||
Git::CountResult Git::branchHistoryPosition( const std::string& localBranch,
|
||||
const std::string& remoteBranch,
|
||||
const std::string& projectDir ) {
|
||||
@@ -345,16 +365,22 @@ static Git::Branch parseTag( std::string_view raw ) {
|
||||
return newBranch;
|
||||
}
|
||||
|
||||
std::vector<Git::Branch> Git::getAllBranchesAndTags( RefType ref, const std::string& projectDir ) {
|
||||
std::vector<Git::Branch> Git::getAllBranchesAndTags( RefType ref, std::string_view filterBranch,
|
||||
const std::string& projectDir ) {
|
||||
// clang-format off
|
||||
std::string args( "for-each-ref --format '%(refname) %(refname:short) %(upstream:short) %(objectname) %(upstream:track,nobracket)' --sort=v:refname" );
|
||||
// clang-format on
|
||||
if ( ref & RefType::Head )
|
||||
args.append( " refs/heads" );
|
||||
if ( ref & RefType::Remote )
|
||||
args.append( " refs/remotes" );
|
||||
if ( ref & RefType::Tag )
|
||||
args.append( " refs/tags" );
|
||||
|
||||
if ( filterBranch.empty() ) {
|
||||
if ( ref & RefType::Head )
|
||||
args.append( " refs/heads" );
|
||||
if ( ref & RefType::Remote )
|
||||
args.append( " refs/remotes" );
|
||||
if ( ref & RefType::Tag )
|
||||
args.append( " refs/tags" );
|
||||
} else {
|
||||
args.append( " " + filterBranch );
|
||||
}
|
||||
|
||||
std::vector<Branch> branches;
|
||||
std::string buf;
|
||||
@@ -406,7 +432,7 @@ bool Git::hasSubmodules( const std::string& projectDir ) {
|
||||
( !mProjectPath.empty() && FileSystem::fileExists( mProjectPath + ".gitmodules" ) );
|
||||
}
|
||||
|
||||
std::string Git::inSubModule( const std::string& file, const std::string& projectDir ) {
|
||||
std::string Git::repoName( const std::string& file, const std::string& projectDir ) {
|
||||
for ( const auto& subRepo : mSubModules ) {
|
||||
if ( String::startsWith( file, subRepo ) && file.size() != subRepo.size() )
|
||||
return subRepo;
|
||||
@@ -454,7 +480,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 = inSubModule( filePath, projectDir );
|
||||
auto repo = repoName( filePath, projectDir );
|
||||
auto repoIt = s.files.find( repo );
|
||||
if ( repoIt != s.files.end() ) {
|
||||
bool found = false;
|
||||
@@ -660,7 +686,7 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir )
|
||||
modifiedSubmodule = true;
|
||||
else {
|
||||
auto filePath = subModulePath + file;
|
||||
auto repo = inSubModule( filePath, projectDir );
|
||||
auto repo = repoName( filePath, projectDir );
|
||||
auto repoIt = s.files.find( repo );
|
||||
if ( repoIt != s.files.end() ) {
|
||||
bool found = false;
|
||||
|
||||
@@ -201,11 +201,14 @@ class Git {
|
||||
|
||||
Status status( bool recurseSubmodules, const std::string& projectDir = "" );
|
||||
|
||||
Result add( const std::string& file, const std::string& projectDir = "" );
|
||||
Result add( std::vector<std::string> files, const std::string& projectDir = "" );
|
||||
|
||||
Result restore( const std::string& file, const std::string& projectDir = "" );
|
||||
|
||||
Result reset( const std::string& file, const std::string& projectDir = "" );
|
||||
Result reset( std::vector<std::string> files, const std::string& projectDir = "" );
|
||||
|
||||
Result createBranch( const std::string& branchName, bool checkout = false,
|
||||
const std::string& projectDir = "" );
|
||||
|
||||
Result renameBranch( const std::string& branch, const std::string& newName,
|
||||
const std::string& projectDir = "" );
|
||||
@@ -218,6 +221,9 @@ class Git {
|
||||
|
||||
Result fastForwardMerge( const std::string& projectDir = "" );
|
||||
|
||||
Result updateRef( const std::string& headBranch, const std::string& toCommit,
|
||||
const std::string& projectDir = "" );
|
||||
|
||||
CountResult branchHistoryPosition( const std::string& localBranch,
|
||||
const std::string& remoteBranch,
|
||||
const std::string& projectDir = "" );
|
||||
@@ -256,12 +262,19 @@ class Git {
|
||||
* @brief get all local and remote branches + tags
|
||||
*/
|
||||
std::vector<Branch> getAllBranchesAndTags( RefType ref = RefType::All,
|
||||
std::string_view filterBranch = {},
|
||||
const std::string& projectDir = "" );
|
||||
|
||||
std::vector<std::string> fetchSubModules( const std::string& projectDir );
|
||||
|
||||
std::vector<std::string> getSubModules( const std::string& projectDir = "" );
|
||||
|
||||
std::string repoName( const std::string& file, const std::string& projectDir = "" );
|
||||
|
||||
bool hasSubmodules( const std::string& projectDir );
|
||||
|
||||
Result gitSimple( const std::string& cmd, const std::string& projectDir );
|
||||
|
||||
protected:
|
||||
std::string mGitPath;
|
||||
std::string mProjectPath;
|
||||
@@ -269,12 +282,6 @@ class Git {
|
||||
std::string mLastProjectPath;
|
||||
std::vector<std::string> mSubModules;
|
||||
bool mSubModulesUpdated{ false };
|
||||
|
||||
bool hasSubmodules( const std::string& projectDir );
|
||||
|
||||
std::string inSubModule( const std::string& file, const std::string& projectDir );
|
||||
|
||||
Result gitSimple( const std::string& cmd, const std::string& projectDir );
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <eepp/ui/uipopupmenu.hpp>
|
||||
#include <eepp/ui/uistackwidget.hpp>
|
||||
#include <eepp/ui/uistyle.hpp>
|
||||
#include <eepp/ui/uitextedit.hpp>
|
||||
#include <eepp/ui/uitooltip.hpp>
|
||||
#include <eepp/ui/uitreeview.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
@@ -52,7 +53,9 @@ std::string GitPlugin::statusTypeToString( Git::GitStatusType type ) {
|
||||
static size_t hashBranches( const std::vector<Git::Branch>& branches ) {
|
||||
size_t hash = 0;
|
||||
for ( const auto& branch : branches )
|
||||
hash = hashCombine( hash, String::hash( branch.name ) );
|
||||
hash = hashCombine( hash, String::hash( branch.name ), String::hash( branch.remote ),
|
||||
String::hash( branch.lastCommit ), branch.type, branch.ahead,
|
||||
branch.behind );
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -254,9 +257,6 @@ class GitStatusModel : public Model {
|
||||
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 ) {
|
||||
@@ -267,6 +267,15 @@ class GitStatusModel : public Model {
|
||||
mStatus[pos].type[typePos].files.emplace_back( std::move( df ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Set the parents after the addreses are stable
|
||||
for ( auto& status : mStatus ) {
|
||||
for ( auto& type : status.type ) {
|
||||
for ( auto& f : type.files )
|
||||
f.parent = &type;
|
||||
type.parent = &status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t treeColumn() const { return Column::File; }
|
||||
@@ -293,7 +302,8 @@ class GitStatusModel : public Model {
|
||||
if ( index.internalId() == Status ) {
|
||||
RepoStatusType* status = reinterpret_cast<RepoStatusType*>( index.internalData() );
|
||||
size_t f = 0;
|
||||
for ( size_t i = 0; i < mStatus.size(); i++ ) {
|
||||
size_t statusSize = mStatus.size();
|
||||
for ( size_t i = 0; i < statusSize; i++ ) {
|
||||
if ( &mStatus[i] == status->parent ) {
|
||||
f = i;
|
||||
break;
|
||||
@@ -305,8 +315,10 @@ class GitStatusModel : public Model {
|
||||
if ( index.internalId() == GitFile ) {
|
||||
DiffFile* file = reinterpret_cast<DiffFile*>( index.internalData() );
|
||||
RepoStatusType* status = file->parent;
|
||||
RepoStatus* repoStatus = status->parent;
|
||||
size_t typeSize = repoStatus->type.size();
|
||||
size_t f = 0;
|
||||
for ( size_t i = 0; i < status->parent->type.size(); i++ ) {
|
||||
for ( size_t i = 0; i < typeSize; i++ ) {
|
||||
if ( &status->parent->type[i] == status ) {
|
||||
f = i;
|
||||
break;
|
||||
@@ -410,6 +422,18 @@ class GitStatusModel : public Model {
|
||||
|
||||
virtual bool classModelRoleEnabled() { return true; }
|
||||
|
||||
const RepoStatus* repo( const ModelIndex& index ) const {
|
||||
if ( index.internalId() != Repo )
|
||||
return nullptr;
|
||||
return &mStatus[index.row()];
|
||||
}
|
||||
|
||||
const RepoStatusType* statusType( const ModelIndex& index ) const {
|
||||
if ( index.internalId() != Status )
|
||||
return nullptr;
|
||||
return &mStatus[index.parent().row()].type[index.row()];
|
||||
}
|
||||
|
||||
const DiffFile* file( const ModelIndex& index ) const {
|
||||
if ( index.internalId() != GitFile )
|
||||
return nullptr;
|
||||
@@ -418,6 +442,23 @@ class GitStatusModel : public Model {
|
||||
.files[index.row()];
|
||||
}
|
||||
|
||||
std::vector<std::string> getFiles( const std::string& repo, uint32_t statusType ) const {
|
||||
std::vector<std::string> files;
|
||||
for ( const auto& status : mStatus ) {
|
||||
if ( status.repo == repo ) {
|
||||
for ( const auto& type : status.type ) {
|
||||
if ( static_cast<uint32_t>( type.type ) & statusType ) {
|
||||
for ( const auto& file : type.files )
|
||||
files.push_back( file.file );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<RepoStatus> mStatus;
|
||||
GitPlugin* mPlugin{ nullptr };
|
||||
@@ -935,12 +976,62 @@ void GitPlugin::fetch() {
|
||||
runAsync( [this]() { return mGit->fetch(); }, true, true );
|
||||
}
|
||||
|
||||
void GitPlugin::stage( const std::string& file ) {
|
||||
runAsync( [this, file]() { return mGit->add( file ); }, true, false );
|
||||
void GitPlugin::branchCreate() {
|
||||
UIMessageBox* msgBox = UIMessageBox::New(
|
||||
UIMessageBox::INPUT,
|
||||
i18n( "git_create_branch_ask",
|
||||
"Create new branch at current branch (HEAD).\nEnter the name for the branch:" ) );
|
||||
msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) {
|
||||
std::string newName( msgBox->getTextInput()->getText().toUtf8() );
|
||||
if ( newName.empty() )
|
||||
return;
|
||||
msgBox->closeWindow();
|
||||
runAsync( [this, newName]() { return mGit->createBranch( newName, true ); }, false, true );
|
||||
} );
|
||||
msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } );
|
||||
msgBox->setTitle( i18n( "git_add_branch", "Add Branch" ) );
|
||||
msgBox->center();
|
||||
msgBox->showWhenReady();
|
||||
}
|
||||
|
||||
void GitPlugin::unstage( const std::string& file ) {
|
||||
runAsync( [this, file]() { return mGit->reset( file ); }, true, false );
|
||||
void GitPlugin::commit() {
|
||||
UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::TEXT_EDIT,
|
||||
i18n( "git_commit_message", "Commit Message:" ) );
|
||||
msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) {
|
||||
std::string msg( msgBox->getTextEdit()->getText().toUtf8() );
|
||||
if ( msg.empty() )
|
||||
return;
|
||||
msgBox->closeWindow();
|
||||
runAsync( [this, msg]() { return mGit->commit( msg ); }, false, true );
|
||||
} );
|
||||
msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } );
|
||||
msgBox->setTitle( i18n( "git_commit", "Commit" ) );
|
||||
msgBox->center();
|
||||
msgBox->showWhenReady();
|
||||
}
|
||||
|
||||
void GitPlugin::stage( const std::vector<std::string>& files ) {
|
||||
runAsync( [this, files]() { return mGit->add( files ); }, true, false );
|
||||
}
|
||||
|
||||
void GitPlugin::unstage( const std::vector<std::string>& files ) {
|
||||
runAsync( [this, files]() { return mGit->reset( files ); }, true, false );
|
||||
}
|
||||
|
||||
void GitPlugin::fastForwardMerge( Git::Branch branch ) {
|
||||
runAsync(
|
||||
[this, branch]() {
|
||||
if ( branch.name == mGitBranch )
|
||||
return mGit->fastForwardMerge();
|
||||
|
||||
auto remoteBranch = mGit->getAllBranchesAndTags( Git::RefType::Remote,
|
||||
"refs/remotes/" + branch.remote );
|
||||
if ( remoteBranch.empty() )
|
||||
return Git::Result{ "", -1 };
|
||||
|
||||
return mGit->updateRef( branch.name, remoteBranch[0].lastCommit );
|
||||
},
|
||||
false, true );
|
||||
}
|
||||
|
||||
void GitPlugin::discard( const std::string& file ) {
|
||||
@@ -985,7 +1076,9 @@ void GitPlugin::onRegister( UICodeEditor* editor ) {
|
||||
if ( mTab )
|
||||
mTab->setTabSelected();
|
||||
} );
|
||||
doc.setCommand( "git-pull", [this]() { pull(); } );
|
||||
doc.setCommand( "git-pull", [this] { pull(); } );
|
||||
doc.setCommand( "git-fetch", [this] { fetch(); } );
|
||||
doc.setCommand( "git-commit", [this] { commit(); } );
|
||||
}
|
||||
|
||||
void GitPlugin::onUnregister( UICodeEditor* editor ) {
|
||||
@@ -1042,10 +1135,10 @@ void GitPlugin::updateBranches() {
|
||||
if ( !mGit || mGit->getGitFolder().empty() )
|
||||
return;
|
||||
|
||||
auto prevBranch = mGitBranch;
|
||||
{
|
||||
Lock l( mGitBranchMutex );
|
||||
if ( mGitBranch.empty() )
|
||||
mGitBranch = mGit->branch();
|
||||
mGitBranch = mGit->branch();
|
||||
}
|
||||
|
||||
auto branches = mGit->getAllBranchesAndTags();
|
||||
@@ -1053,8 +1146,11 @@ void GitPlugin::updateBranches() {
|
||||
auto model = GitBranchModel::asModel( std::move( branches ), hash, this );
|
||||
|
||||
if ( mBranchesTree &&
|
||||
static_cast<GitBranchModel*>( mBranchesTree->getModel() )->getHash() == hash )
|
||||
static_cast<GitBranchModel*>( mBranchesTree->getModel() )->getHash() == hash ) {
|
||||
if ( prevBranch != mGitBranch )
|
||||
mBranchesTree->getModel()->invalidate( Model::DontInvalidateIndexes );
|
||||
return;
|
||||
}
|
||||
|
||||
getUISceneNode()->runOnMainThread( [this, model] { updateBranchesUI( model ); } );
|
||||
},
|
||||
@@ -1085,6 +1181,7 @@ void GitPlugin::buildSidePanelTab() {
|
||||
<hbox lw="mp" lh="wc" margin-bottom="4dp" padding="4dp">
|
||||
<Widget lw="0" lh="0" lw8="1" />
|
||||
<PushButton id="branch_pull" text="@string(pull_branch, Pull)" tooltip="@string(pull_branch, Pull Branch)" text-as-fallback="true" icon="icon(repo-pull, 12dp)" margin-left="2dp" />
|
||||
<PushButton id="branch_push" text="@string(push_branch, Push)" tooltip="@string(push_branch, Push Branch)" text-as-fallback="true" icon="icon(repo-push, 12dp)" margin-left="2dp" />
|
||||
<PushButton id="branch_add" text="@string(add_branch, Add Branch)" tooltip="@string(add_branch, Add Branch)" text-as-fallback="true" icon="icon(add, 12dp)" margin-left="2dp" />
|
||||
</hbox>
|
||||
-->
|
||||
@@ -1159,25 +1256,77 @@ void GitPlugin::buildSidePanelTab() {
|
||||
mStatusTree->setExpandersAsIcons( true );
|
||||
mStatusTree->on( Event::OnModelEvent, [this]( const Event* event ) {
|
||||
const ModelEvent* modelEvent = static_cast<const ModelEvent*>( event );
|
||||
if ( modelEvent->getModel() == nullptr ||
|
||||
modelEvent->getModelIndex().internalId() != GitStatusModel::GitFile )
|
||||
return;
|
||||
auto model = static_cast<const GitStatusModel*>( modelEvent->getModel() );
|
||||
const Git::DiffFile* file = model->file( modelEvent->getModelIndex() );
|
||||
if ( file == nullptr )
|
||||
if ( modelEvent->getModel() == nullptr )
|
||||
return;
|
||||
|
||||
switch ( modelEvent->getModelEventType() ) {
|
||||
case Abstract::ModelEventType::OpenMenu: {
|
||||
bool focusOnSelection = mStatusTree->getFocusOnSelection();
|
||||
mStatusTree->setFocusOnSelection( false );
|
||||
mStatusTree->getSelection().set( modelEvent->getModelIndex() );
|
||||
mStatusTree->setFocusOnSelection( focusOnSelection );
|
||||
openFileStatusMenu( *file );
|
||||
break;
|
||||
auto model = static_cast<const GitStatusModel*>( modelEvent->getModel() );
|
||||
if ( modelEvent->getModelIndex().internalId() == GitStatusModel::GitFile ) {
|
||||
const Git::DiffFile* file = model->file( modelEvent->getModelIndex() );
|
||||
if ( file == nullptr )
|
||||
return;
|
||||
|
||||
switch ( modelEvent->getModelEventType() ) {
|
||||
case Abstract::ModelEventType::OpenMenu: {
|
||||
bool focusOnSelection = mStatusTree->getFocusOnSelection();
|
||||
mStatusTree->setFocusOnSelection( false );
|
||||
mStatusTree->getSelection().set( modelEvent->getModelIndex() );
|
||||
mStatusTree->setFocusOnSelection( focusOnSelection );
|
||||
openFileStatusMenu( *file );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if ( modelEvent->getModelIndex().internalId() == GitStatusModel::Status ) {
|
||||
switch ( modelEvent->getModelEventType() ) {
|
||||
case Abstract::ModelEventType::OpenMenu: {
|
||||
bool focusOnSelection = mStatusTree->getFocusOnSelection();
|
||||
mStatusTree->setFocusOnSelection( false );
|
||||
mStatusTree->getSelection().set( modelEvent->getModelIndex() );
|
||||
mStatusTree->setFocusOnSelection( focusOnSelection );
|
||||
|
||||
const auto* status = model->statusType( modelEvent->getModelIndex() );
|
||||
if ( status->type == Git::GitStatusType::Staged ||
|
||||
status->type == Git::GitStatusType::Untracked ||
|
||||
status->type == Git::GitStatusType::Changed ) {
|
||||
UIPopUpMenu* menu = UIPopUpMenu::New();
|
||||
menu->setId( "git_status_type_menu" );
|
||||
|
||||
if ( status->type == Git::GitStatusType::Staged ) {
|
||||
addMenuItem( menu, "git-commit", "Commit" );
|
||||
|
||||
addMenuItem( menu, "git-unstage-all", "Unstage All" );
|
||||
}
|
||||
|
||||
if ( status->type == Git::GitStatusType::Untracked ||
|
||||
status->type == Git::GitStatusType::Changed )
|
||||
addMenuItem( menu, "git-stage-all", "Stage All" );
|
||||
|
||||
menu->on( Event::OnItemClicked, [this, model]( const Event* event ) {
|
||||
if ( !mGit )
|
||||
return;
|
||||
UIMenuItem* item = event->getNode()->asType<UIMenuItem>();
|
||||
std::string id( item->getId() );
|
||||
if ( id == "git-commit" ) {
|
||||
commit();
|
||||
} else if ( id == "git-stage-all" ) {
|
||||
stage( model->getFiles( mGit->repoName( "" ),
|
||||
(Uint32)Git::GitStatusType::Untracked |
|
||||
(Uint32)Git::GitStatusType::Changed ) );
|
||||
} else if ( id == "git-unstage-all" ) {
|
||||
unstage( model->getFiles( mGit->repoName( "" ),
|
||||
(Uint32)Git::GitStatusType::Staged ) );
|
||||
}
|
||||
} );
|
||||
|
||||
menu->showOverMouseCursor();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} );
|
||||
}
|
||||
@@ -1186,27 +1335,24 @@ void GitPlugin::openBranchMenu( const Git::Branch& branch ) {
|
||||
UIPopUpMenu* menu = UIPopUpMenu::New();
|
||||
menu->setId( "git_branch_menu" );
|
||||
|
||||
auto addFn = [this, menu]( const std::string& txtKey, const std::string& txtVal,
|
||||
const std::string& icon = "" ) {
|
||||
menu->add( i18n( txtKey, txtVal ), iconDrawable( icon, 12 ),
|
||||
KeyBindings::keybindFormat( mKeyBindings[txtKey] ) )
|
||||
->setId( txtKey );
|
||||
};
|
||||
|
||||
addFn( "git-fetch", "Fetch" );
|
||||
addMenuItem( menu, "git-fetch", "Fetch" );
|
||||
addMenuItem( menu, "git-create-branch", "Create Branch", "repo-forked" );
|
||||
|
||||
if ( mGitBranch != branch.name ) {
|
||||
addFn( "git-checkout", "Check Out..." );
|
||||
addMenuItem( menu, "git-checkout", "Check Out..." );
|
||||
if ( branch.type == Git::RefType::Head ) {
|
||||
addFn( "git-branch-rename", "Rename" );
|
||||
addFn( "git-branch-delete", "Delete" );
|
||||
addMenuItem( menu, "git-branch-rename", "Rename" );
|
||||
addMenuItem( menu, "git-branch-delete", "Delete" );
|
||||
}
|
||||
} else {
|
||||
if ( branch.type == Git::RefType::Head ) {
|
||||
addFn( "git-pull", "Pull", "repo-pull" );
|
||||
addMenuItem( menu, "git-pull", "Pull", "repo-pull" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( branch.type == Git::RefType::Head && branch.behind )
|
||||
addMenuItem( menu, "git-fast-forward-merge", "Fast Forward Merge" );
|
||||
|
||||
menu->on( Event::OnItemClicked, [this, branch]( const Event* event ) {
|
||||
if ( !mGit )
|
||||
return;
|
||||
@@ -1222,6 +1368,10 @@ void GitPlugin::openBranchMenu( const Git::Branch& branch ) {
|
||||
branchRename( branch );
|
||||
} else if ( id == "git-fetch" ) {
|
||||
fetch();
|
||||
} else if ( id == "git-fast-forward-merge" ) {
|
||||
fastForwardMerge( branch );
|
||||
} else if ( id == "git-create-branch" ) {
|
||||
branchCreate();
|
||||
}
|
||||
} );
|
||||
|
||||
@@ -1232,24 +1382,17 @@ void GitPlugin::openFileStatusMenu( const Git::DiffFile& file ) {
|
||||
UIPopUpMenu* menu = UIPopUpMenu::New();
|
||||
menu->setId( "git_file_status_menu" );
|
||||
|
||||
auto addFn = [this, menu]( const std::string& txtKey, const std::string& txtVal,
|
||||
const std::string& icon = "" ) {
|
||||
menu->add( i18n( txtKey, txtVal ), iconDrawable( icon, 12 ),
|
||||
KeyBindings::keybindFormat( mKeyBindings[txtKey] ) )
|
||||
->setId( txtKey );
|
||||
};
|
||||
|
||||
addFn( "git-open-file", "Open File" );
|
||||
addMenuItem( menu, "git-open-file", "Open File" );
|
||||
|
||||
if ( file.statusType != Git::GitStatusType::Staged ) {
|
||||
addFn( "git-stage", "Stage" );
|
||||
addMenuItem( menu, "git-stage", "Stage" );
|
||||
} else {
|
||||
addFn( "git-unstage", "Unstage" );
|
||||
addMenuItem( menu, "git-unstage", "Unstage" );
|
||||
}
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
addFn( "git-discard", "Discard" );
|
||||
addMenuItem( menu, "git-discard", "Discard" );
|
||||
|
||||
menu->on( Event::OnItemClicked, [this, file]( const Event* event ) {
|
||||
if ( !mGit )
|
||||
@@ -1257,9 +1400,9 @@ void GitPlugin::openFileStatusMenu( const Git::DiffFile& file ) {
|
||||
UIMenuItem* item = event->getNode()->asType<UIMenuItem>();
|
||||
std::string id( item->getId() );
|
||||
if ( id == "git-stage" ) {
|
||||
stage( file.file );
|
||||
stage( { file.file } );
|
||||
} else if ( id == "git-unstage" ) {
|
||||
unstage( file.file );
|
||||
unstage( { file.file } );
|
||||
} else if ( id == "git-discard" ) {
|
||||
discard( file.file );
|
||||
} else if ( id == "git-open-file" ) {
|
||||
@@ -1289,4 +1432,11 @@ void GitPlugin::runAsync( std::function<Git::Result()> fn, bool _updateStatus,
|
||||
} );
|
||||
}
|
||||
|
||||
void GitPlugin::addMenuItem( UIMenu* menu, const std::string& txtKey, const std::string& txtVal,
|
||||
const std::string& icon ) {
|
||||
menu->add( i18n( txtKey, txtVal ), iconDrawable( icon, 12 ),
|
||||
KeyBindings::keybindFormat( mKeyBindings[txtKey] ) )
|
||||
->setId( txtKey );
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -16,6 +16,7 @@ class UITreeView;
|
||||
class UIDropDownList;
|
||||
class UIStackWidget;
|
||||
class UIListBoxItem;
|
||||
class UIMenu;
|
||||
} // namespace EE::UI
|
||||
|
||||
namespace ecode {
|
||||
@@ -62,26 +63,8 @@ class GitPlugin : public PluginBase {
|
||||
std::unique_ptr<Git> mGit;
|
||||
std::string mGitBranch;
|
||||
Git::Status mGitStatus;
|
||||
UILinearLayout* mStatusBar{ nullptr };
|
||||
UIPushButton* mStatusButton{ nullptr };
|
||||
|
||||
Time mRefreshFreq{ Seconds( 5 ) };
|
||||
|
||||
GitPlugin( PluginManager* pluginManager, bool sync );
|
||||
|
||||
void load( PluginManager* pluginManager );
|
||||
|
||||
PluginRequestHandle processMessage( const PluginMessage& msg );
|
||||
|
||||
void displayTooltip( UICodeEditor* editor, const Git::Blame& blame, const Vector2f& position );
|
||||
|
||||
void hideTooltip( UICodeEditor* editor );
|
||||
|
||||
void onRegisterListeners( UICodeEditor*, std::vector<Uint32>& listeners ) override;
|
||||
|
||||
void onBeforeUnregister( UICodeEditor* ) override;
|
||||
|
||||
void onUnregisterDocument( TextDocument* ) override;
|
||||
|
||||
bool mGitFound{ false };
|
||||
bool mTooltipInfoShowing{ false };
|
||||
bool mStatusBarDisplayBranch{ true };
|
||||
@@ -96,6 +79,8 @@ class GitPlugin : public PluginBase {
|
||||
UITabWidget* mSidePanel{ nullptr };
|
||||
UITab* mTab{ nullptr };
|
||||
|
||||
UILinearLayout* mStatusBar{ nullptr };
|
||||
UIPushButton* mStatusButton{ nullptr };
|
||||
UITreeView* mBranchesTree{ nullptr };
|
||||
UITreeView* mStatusTree{ nullptr };
|
||||
UIDropDownList* mPanelSwicher{ nullptr };
|
||||
@@ -116,6 +101,22 @@ class GitPlugin : public PluginBase {
|
||||
std::optional<CustomTokenizer> mStatusCustomTokenizer;
|
||||
std::optional<SyntaxDefinition> mTooltipCustomSyntaxDef;
|
||||
|
||||
GitPlugin( PluginManager* pluginManager, bool sync );
|
||||
|
||||
void load( PluginManager* pluginManager );
|
||||
|
||||
PluginRequestHandle processMessage( const PluginMessage& msg );
|
||||
|
||||
void displayTooltip( UICodeEditor* editor, const Git::Blame& blame, const Vector2f& position );
|
||||
|
||||
void hideTooltip( UICodeEditor* editor );
|
||||
|
||||
void onRegisterListeners( UICodeEditor*, std::vector<Uint32>& listeners ) override;
|
||||
|
||||
void onBeforeUnregister( UICodeEditor* ) override;
|
||||
|
||||
void onUnregisterDocument( TextDocument* ) override;
|
||||
|
||||
Color getVarColor( const std::string& var );
|
||||
|
||||
void blame( UICodeEditor* editor );
|
||||
@@ -126,13 +127,19 @@ class GitPlugin : public PluginBase {
|
||||
|
||||
void branchDelete( Git::Branch branch );
|
||||
|
||||
void fastForwardMerge( Git::Branch branch );
|
||||
|
||||
void pull();
|
||||
|
||||
void fetch();
|
||||
|
||||
void stage( const std::string& file );
|
||||
void branchCreate();
|
||||
|
||||
void unstage( const std::string& file );
|
||||
void commit();
|
||||
|
||||
void stage( const std::vector<std::string>& files );
|
||||
|
||||
void unstage( const std::vector<std::string>& files );
|
||||
|
||||
void discard( const std::string& file );
|
||||
|
||||
@@ -157,6 +164,9 @@ class GitPlugin : public PluginBase {
|
||||
void openFileStatusMenu( const Git::DiffFile& file );
|
||||
|
||||
void runAsync( std::function<Git::Result()> fn, bool updateStatus, bool updateBranches );
|
||||
|
||||
void addMenuItem( UIMenu* menu, const std::string& txtKey, const std::string& txtVal,
|
||||
const std::string& icon = "" );
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
Reference in New Issue
Block a user