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:
Martín Lucas Golini
2024-10-25 00:10:30 -03:00
parent 8df0462320
commit 9ef654929c
16 changed files with 162 additions and 27 deletions

4
.gitmodules vendored
View File

@@ -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

View File

@@ -112,6 +112,8 @@ class EE_API Model {
virtual bool classModelRoleEnabled() { return false; }
virtual bool tooltipModelRoleEnabled() { return false; }
void registerView( UIAbstractView* );
void unregisterView( UIAbstractView* );

View File

@@ -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

View File

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

View File

@@ -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,

View File

@@ -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 ) )

View File

@@ -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;

View File

@@ -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 ) )

View File

@@ -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;
}

View File

@@ -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 {

View File

@@ -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++;
}
} );
}

View File

@@ -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 };

View File

@@ -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;
}

View File

@@ -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; }

View File

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

View File

@@ -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: