mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
Display the stashes creation date. Also add a tooltip text for the stash in order to make easier to read the full name.
Fix in Process::create when parsing command arguments from string. Fix text-align in UITooltip. Fix in GitPlugin refreshing repositories during git lock files changes.
This commit is contained in:
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -6,7 +6,7 @@
|
||||
url = https://github.com/SpartanJ/soil2
|
||||
[submodule "premake/premake-ninja"]
|
||||
path = premake/premake-ninja
|
||||
url = ../../jimon/premake-ninja.git
|
||||
url = https://github.com/jimon/premake-ninja.git
|
||||
[submodule "premake/premake-cmake"]
|
||||
path = premake/premake-cmake
|
||||
url = ../../Jarod42/premake-cmake.git
|
||||
url = https://github.com/Jarod42/premake-cmake.git
|
||||
|
||||
@@ -112,6 +112,8 @@ class EE_API Model {
|
||||
|
||||
virtual bool classModelRoleEnabled() { return false; }
|
||||
|
||||
virtual bool tooltipModelRoleEnabled() { return false; }
|
||||
|
||||
void registerView( UIAbstractView* );
|
||||
|
||||
void unregisterView( UIAbstractView* );
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
namespace EE { namespace UI { namespace Models {
|
||||
|
||||
enum class ModelRole { Display, Icon, Sort, Class, Custom };
|
||||
enum class ModelRole { Display, Icon, Sort, Class, Tooltip, TooltipClass, Custom };
|
||||
|
||||
}}} // namespace EE::UI::Models
|
||||
|
||||
|
||||
@@ -130,16 +130,18 @@ class EE_API UITooltip : public UIWidget {
|
||||
bool isWordWrap() const;
|
||||
|
||||
protected:
|
||||
Text* mTextCache;
|
||||
Text* mTextCache{ nullptr };
|
||||
UIFontStyleConfig mStyleConfig;
|
||||
Vector2f mAlignOffset;
|
||||
Time mTooltipTime;
|
||||
UINode* mTooltipOf;
|
||||
UINode* mTooltipOf{ nullptr };
|
||||
String mStringBuffer;
|
||||
TextTransform::Value mTextTransform{ TextTransform::None };
|
||||
bool mDontAutoHideOnMouseMove{ false };
|
||||
bool mUsingCustomStyling{ false };
|
||||
|
||||
virtual void onAlignChange();
|
||||
|
||||
virtual void onAlphaChange();
|
||||
|
||||
virtual void onSizeChange();
|
||||
|
||||
@@ -42,6 +42,42 @@ static bool isFlatpakEnv() {
|
||||
|
||||
#define PROCESS_PTR ( static_cast<struct subprocess_s*>( mProcess ) )
|
||||
|
||||
static std::vector<std::string> parseArgs( const std::string& str ) {
|
||||
bool inquote = false;
|
||||
char quoteChar = 0;
|
||||
std::vector<std::string> res;
|
||||
std::string curstr;
|
||||
|
||||
for ( size_t i = 0; i < str.size(); ++i ) {
|
||||
char c = str[i];
|
||||
if ( inquote ) {
|
||||
if ( c == quoteChar ) {
|
||||
inquote = false;
|
||||
} else if ( c == '\\' && i + 1 < str.size() && str[i + 1] == quoteChar ) {
|
||||
curstr += quoteChar;
|
||||
++i;
|
||||
} else {
|
||||
curstr += c;
|
||||
}
|
||||
} else if ( c == ' ' || c == '\t' ) {
|
||||
if ( !curstr.empty() ) {
|
||||
res.push_back( curstr );
|
||||
curstr.clear();
|
||||
}
|
||||
} else if ( c == '\'' || c == '"' ) {
|
||||
inquote = true;
|
||||
quoteChar = c;
|
||||
} else {
|
||||
curstr += c;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !curstr.empty() )
|
||||
res.push_back( curstr );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Process::Process() {}
|
||||
|
||||
Process::Process( const std::string& command, Uint32 options,
|
||||
@@ -76,8 +112,7 @@ bool Process::create( const std::string& command, Uint32 options,
|
||||
bool Process::create( const std::string& command, const std::string& args, Uint32 options,
|
||||
const std::unordered_map<std::string, std::string>& environment,
|
||||
const std::string& workingDirectory ) {
|
||||
return create( command, String::split( args, " ", "", "\"", true ), options, environment,
|
||||
workingDirectory );
|
||||
return create( command, parseArgs( args ), options, environment, workingDirectory );
|
||||
}
|
||||
|
||||
bool Process::create( const std::string& command, const std::vector<std::string>& cmdArr,
|
||||
|
||||
@@ -600,6 +600,18 @@ UIWidget* UIAbstractTableView::updateCell( const Vector2<Int64>& posIndex, const
|
||||
cell->reportStyleStateChangeRecursive();
|
||||
}
|
||||
|
||||
if ( getModel()->tooltipModelRoleEnabled() ) {
|
||||
Variant tooltip( getModel()->data( index, ModelRole::Tooltip ) );
|
||||
if ( tooltip.isValid() ) {
|
||||
if ( tooltip.is( Variant::Type::String ) )
|
||||
cell->setTooltipText( tooltip.asString() );
|
||||
else if ( tooltip.is( Variant::Type::StringPtr ) )
|
||||
cell->setTooltipText( tooltip.asStringPtr() );
|
||||
else
|
||||
cell->setTooltipText( tooltip.toString() );
|
||||
}
|
||||
}
|
||||
|
||||
Variant txt( getModel()->data( index, ModelRole::Display ) );
|
||||
if ( txt.isValid() ) {
|
||||
if ( txt.is( Variant::Type::String ) )
|
||||
|
||||
@@ -62,11 +62,12 @@ Vector2f UITooltip::getTooltipPosition( UITooltip* toolip, const Vector2f& reque
|
||||
|
||||
UITooltip::UITooltip() :
|
||||
UIWidget( "tooltip" ), mAlignOffset( 0.f, 0.f ), mTooltipTime( Time::Zero ), mTooltipOf() {
|
||||
setFlags( UI_NODE_DEFAULT_FLAGS_CENTERED | UI_AUTO_PADDING | UI_AUTO_SIZE );
|
||||
|
||||
mTextCache = Text::New();
|
||||
mEnabled = false;
|
||||
|
||||
setFlags( UI_NODE_DEFAULT_FLAGS_CENTERED | UI_AUTO_PADDING | UI_AUTO_SIZE );
|
||||
|
||||
UITheme* theme = getUISceneNode()->getUIThemeManager()->getDefaultTheme();
|
||||
|
||||
if ( NULL != theme && NULL != theme->getDefaultFont() ) {
|
||||
@@ -258,6 +259,8 @@ void UITooltip::onAutoSize() {
|
||||
}
|
||||
|
||||
void UITooltip::autoAlign() {
|
||||
if ( mTextCache == nullptr ) return;
|
||||
|
||||
Uint32 Width = mSize.getWidth() - mPaddingPx.Left - mPaddingPx.Right;
|
||||
Uint32 Height = mSize.getHeight() - mPaddingPx.Top - mPaddingPx.Bottom;
|
||||
|
||||
@@ -576,11 +579,11 @@ bool UITooltip::applyProperty( const StyleSheetProperty& attribute ) {
|
||||
case PropertyId::TextAlign: {
|
||||
std::string align = String::toLower( attribute.value() );
|
||||
if ( align == "center" )
|
||||
setFlags( UI_HALIGN_CENTER );
|
||||
setHorizontalAlign( UI_HALIGN_CENTER );
|
||||
else if ( align == "left" )
|
||||
setFlags( UI_HALIGN_LEFT );
|
||||
setHorizontalAlign( UI_HALIGN_LEFT );
|
||||
else if ( align == "right" )
|
||||
setFlags( UI_HALIGN_RIGHT );
|
||||
setHorizontalAlign( UI_HALIGN_RIGHT );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -590,6 +593,11 @@ bool UITooltip::applyProperty( const StyleSheetProperty& attribute ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void UITooltip::onAlignChange() {
|
||||
UIWidget::onAlignChange();
|
||||
autoAlign();
|
||||
}
|
||||
|
||||
void UITooltip::onAlphaChange() {
|
||||
Color color( mStyleConfig.FontColor );
|
||||
color.a = mStyleConfig.FontColor.a * getAlpha() / 255.f;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <eepp/ui/uipushbutton.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uiscrollbar.hpp>
|
||||
#include <eepp/ui/uitooltip.hpp>
|
||||
#include <eepp/ui/uitreeview.hpp>
|
||||
#include <stack>
|
||||
|
||||
@@ -255,6 +256,25 @@ UIWidget* UITreeView::updateCell( const Vector2<Int64>& posIndex, const ModelInd
|
||||
cell->reportStyleStateChangeRecursive();
|
||||
}
|
||||
|
||||
if ( getModel()->tooltipModelRoleEnabled() ) {
|
||||
Variant cls( getModel()->data( index, ModelRole::TooltipClass ) );
|
||||
if ( cls.isValid() ) {
|
||||
cell->createTooltip()->setClass( cls.toString() );
|
||||
} else {
|
||||
cell->createTooltip()->resetClass();
|
||||
}
|
||||
|
||||
Variant tooltip( getModel()->data( index, ModelRole::Tooltip ) );
|
||||
if ( tooltip.isValid() ) {
|
||||
if ( tooltip.is( Variant::Type::String ) )
|
||||
cell->setTooltipText( tooltip.asString() );
|
||||
else if ( tooltip.is( Variant::Type::StringPtr ) )
|
||||
cell->setTooltipText( tooltip.asStringPtr() );
|
||||
else
|
||||
cell->setTooltipText( tooltip.toString() );
|
||||
}
|
||||
}
|
||||
|
||||
Variant txt( getModel()->data( index, ModelRole::Display ) );
|
||||
if ( txt.isValid() ) {
|
||||
if ( txt.is( Variant::Type::String ) )
|
||||
|
||||
@@ -844,16 +844,21 @@ UIWidget* UIWidget::resetClass() {
|
||||
}
|
||||
|
||||
UIWidget* UIWidget::setClass( const std::string& cls ) {
|
||||
size_t oldClassesCount = mClasses.size();
|
||||
if ( mClasses.size() != 1 || mClasses[0] != cls ) {
|
||||
bool isSet = false;
|
||||
mClasses.clear();
|
||||
mClasses.push_back( cls );
|
||||
if ( !cls.empty() ) {
|
||||
mClasses.push_back( cls );
|
||||
isSet = true;
|
||||
|
||||
if ( !isSceneNodeLoading() && !isLoadingState() ) {
|
||||
getUISceneNode()->invalidateStyle( this );
|
||||
getUISceneNode()->invalidateStyleState( this );
|
||||
if ( !isSceneNodeLoading() && !isLoadingState() ) {
|
||||
getUISceneNode()->invalidateStyle( this );
|
||||
getUISceneNode()->invalidateStyleState( this );
|
||||
}
|
||||
}
|
||||
|
||||
onClassChange();
|
||||
if ( oldClassesCount != mClasses.size() || isSet )
|
||||
onClassChange();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -489,6 +489,10 @@ Anchor.error:hover {
|
||||
.indent_tab_listbox_item combobox::dropdownlist::listbox::item {
|
||||
font-family: monospace;
|
||||
}
|
||||
.git-stash-tooltip {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
|
||||
.app_hint {
|
||||
|
||||
@@ -392,7 +392,7 @@ Git::Branch parseLocalBranch( const std::string_view& raw ) {
|
||||
std::string remote( std::string{ split[2] } );
|
||||
std::string commitHash( std::string{ split[3] } );
|
||||
auto ret = Git::Branch{ std::move( name ), std::move( remote ), Git::RefType::Head,
|
||||
std::move( commitHash ) };
|
||||
std::move( commitHash ), "" };
|
||||
if ( split.size() > 4 )
|
||||
parseAheadBehind( split[4], ret );
|
||||
return ret;
|
||||
@@ -406,7 +406,7 @@ static Git::Branch parseRemoteBranch( std::string_view raw ) {
|
||||
std::string remote( std::string{ split[1] } );
|
||||
std::string commitHash( std::string{ split[3] } );
|
||||
auto ret = Git::Branch{ std::move( name ), std::move( remote ), Git::RefType::Remote,
|
||||
std::move( commitHash ) };
|
||||
std::move( commitHash ), "" };
|
||||
if ( split.size() > 4 )
|
||||
parseAheadBehind( split[4], ret );
|
||||
return ret;
|
||||
@@ -460,22 +460,26 @@ std::vector<Git::Branch> Git::getAllBranchesAndTags( RefType ref, std::string_vi
|
||||
} );
|
||||
}
|
||||
|
||||
if ( ( ref & RefType::Stash ) && EXIT_SUCCESS == git( "stash list", projectDir, buf ) ) {
|
||||
if ( ( ref & RefType::Stash ) &&
|
||||
EXIT_SUCCESS == git( "stash list --date=format:\"%Y-%m-%d %H:%M\"", projectDir, buf ) ) {
|
||||
branches.reserve( branches.size() + StringHelper::countLines( buf ) );
|
||||
std::string ptrn( "(stash@{%d+}):%s(.*)" );
|
||||
std::string ptrn( "stash@{(.*)}:%s(.*)" );
|
||||
LuaPattern pattern( ptrn );
|
||||
Uint64 id = 0;
|
||||
StringHelper::readBySeparator( buf, [&]( const std::string_view& line ) {
|
||||
PatternMatcher::Range matches[3];
|
||||
if ( pattern.matches( line.data(), 0, matches, line.size() ) ) {
|
||||
std::string id(
|
||||
std::string date(
|
||||
line.substr( matches[1].start, matches[1].end - matches[1].start ) );
|
||||
std::string name(
|
||||
line.substr( matches[2].start, matches[2].end - matches[2].start ) );
|
||||
Git::Branch newBranch;
|
||||
newBranch.type = RefType::Stash;
|
||||
newBranch.name = std::move( name );
|
||||
newBranch.remote = std::move( id );
|
||||
newBranch.remote = String::format( "stash@{%llu}", id );
|
||||
newBranch.date = date;
|
||||
branches.emplace_back( std::move( newBranch ) );
|
||||
id++;
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@ class Git {
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct Branch {
|
||||
/** Branch name */
|
||||
std::string name;
|
||||
@@ -220,6 +221,10 @@ class Git {
|
||||
RefType type = All;
|
||||
/** last commit on this branch, may be empty **/
|
||||
std::string lastCommit;
|
||||
|
||||
/** date string in yyyy-mm-dd hh:mn */
|
||||
std::string date;
|
||||
|
||||
/** if it's HEAD how much ahead and behind the current local branch is against remote */
|
||||
int64_t ahead{ 0 };
|
||||
int64_t behind{ 0 };
|
||||
|
||||
@@ -8,7 +8,7 @@ size_t GitBranchModel::hashBranches( const std::vector<Git::Branch>& branches )
|
||||
for ( const auto& branch : branches )
|
||||
hash = hashCombine( hash, String::hash( branch.name ), String::hash( branch.remote ),
|
||||
String::hash( branch.lastCommit ), branch.type, branch.ahead,
|
||||
branch.behind );
|
||||
branch.behind, String::hash( branch.date ) );
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -105,6 +105,8 @@ Variant GitBranchModel::data( const ModelIndex& index, ModelRole role ) const {
|
||||
return Variant(
|
||||
String::format( "%s (-%ld)", branch.name, branch.behind ) );
|
||||
}
|
||||
} else if ( branch.type == Git::Stash ) {
|
||||
return Variant( String::format( "%s: %s", branch.date, branch.name ) );
|
||||
}
|
||||
return Variant( branch.name.c_str() );
|
||||
}
|
||||
@@ -128,6 +130,32 @@ Variant GitBranchModel::data( const ModelIndex& index, ModelRole role ) const {
|
||||
case ModelRole::Icon: {
|
||||
return iconFor( index );
|
||||
}
|
||||
case ModelRole::Tooltip: {
|
||||
if ( index.internalId() != -1 ) {
|
||||
const Git::Branch& branch = mBranches[index.internalId()].data[index.row()];
|
||||
switch ( index.column() ) {
|
||||
case Column::Name: {
|
||||
if ( branch.type == Git::Stash ) {
|
||||
return Variant( String::format( "%s:\n%s", branch.date, branch.name ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Variant( GIT_EMPTY );
|
||||
}
|
||||
case ModelRole::TooltipClass: {
|
||||
if ( index.internalId() != -1 ) {
|
||||
const Git::Branch& branch = mBranches[index.internalId()].data[index.row()];
|
||||
switch ( index.column() ) {
|
||||
case Column::Name: {
|
||||
if ( branch.type == Git::Stash ) {
|
||||
return Variant( GIT_STASH_TOOLTIP_CLASS );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Variant( GIT_EMPTY );
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,9 @@ class GitBranchModel : public Model {
|
||||
|
||||
Variant data( const ModelIndex& index, ModelRole role ) const;
|
||||
|
||||
virtual bool classModelRoleEnabled() { return true; }
|
||||
bool classModelRoleEnabled() { return true; }
|
||||
|
||||
bool tooltipModelRoleEnabled() { return true; }
|
||||
|
||||
size_t getHash() const { return mHash; }
|
||||
|
||||
|
||||
@@ -503,8 +503,15 @@ void GitPlugin::onFileSystemEvent( const FileEvent& ev, const FileInfo& file ) {
|
||||
if ( mShuttingDown || isLoading() )
|
||||
return;
|
||||
|
||||
if ( String::startsWith( file.getFilepath(), mGit->getGitFolder() ) &&
|
||||
( file.getExtension() == "lock" || file.isDirectory() ) )
|
||||
if ( file.isDirectory() )
|
||||
return;
|
||||
|
||||
auto inGitFolder = file.getFilepath().find( "/.git/" ) != std::string::npos;
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
inGitFolder |= file.getFilepath().find( "\\.git\\" ) != std::string::npos;
|
||||
#endif
|
||||
|
||||
if ( inGitFolder && file.getExtension() == "lock" )
|
||||
return;
|
||||
|
||||
updateUI();
|
||||
|
||||
@@ -32,6 +32,7 @@ static constexpr const char* GIT_NOT_BOLD = "notbold";
|
||||
static constexpr const char* GIT_TAG = "tag";
|
||||
static constexpr const char* GIT_REPO = "repo";
|
||||
static constexpr const char* GIT_STASH = "git-stash";
|
||||
static constexpr const char* GIT_STASH_TOOLTIP_CLASS = "git-stash-tooltip";
|
||||
|
||||
class GitPlugin : public PluginBase {
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user