From fa3b08a1bd32f7f75db2cb03618c30942f991f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Wed, 3 Jan 2024 00:06:59 -0300 Subject: [PATCH] Parse git status --- projects/macos/ee.files | 6 +++ src/tools/ecode/plugins/git/git.cpp | 78 +++++++++++++++++++++++++---- src/tools/ecode/plugins/git/git.hpp | 20 +++++++- 3 files changed, 93 insertions(+), 11 deletions(-) diff --git a/projects/macos/ee.files b/projects/macos/ee.files index 19fb7f1c4..2f43db939 100644 --- a/projects/macos/ee.files +++ b/projects/macos/ee.files @@ -1290,6 +1290,10 @@ ../../src/tools/ecode/notificationcenter.cpp ../../src/tools/ecode/notificationcenter.hpp ../../src/tools/ecode/pathhelper.hpp +../../src/tools/ecode/plugins/git/git.cpp +../../src/tools/ecode/plugins/git/git.hpp +../../src/tools/ecode/plugins/git/gitplugin.cpp +../../src/tools/ecode/plugins/git/gitplugin.hpp ../../src/tools/ecode/plugins/linter/linterplugin.cpp ../../src/tools/ecode/plugins/linter/linterplugin.hpp ../../src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -1302,6 +1306,8 @@ ../../src/tools/ecode/plugins/lsp/lspdocumentclient.cpp ../../src/tools/ecode/plugins/lsp/lspdocumentclient.hpp ../../src/tools/ecode/plugins/lsp/lspprotocol.hpp +../../src/tools/ecode/plugins/plugin.cpp +../../src/tools/ecode/plugins/plugin.hpp ../../src/tools/ecode/plugins/pluginmanager.cpp ../../src/tools/ecode/plugins/pluginmanager.hpp ../../src/tools/ecode/plugins/xmltools/xmltoolsplugin.cpp diff --git a/src/tools/ecode/plugins/git/git.cpp b/src/tools/ecode/plugins/git/git.cpp index 8ecf6c5ec..47e434d5a 100644 --- a/src/tools/ecode/plugins/git/git.cpp +++ b/src/tools/ecode/plugins/git/git.cpp @@ -42,6 +42,11 @@ void Git::git( const std::string& args, const std::string& projectDir, std::stri p.readAllStdOut( buf ); } +void Git::gitSubmodules( const std::string& args, const std::string& projectDir, + std::string& buf ) { + git( String::format( "submodule foreach \"git %s\"", args.c_str() ), projectDir, buf ); +} + std::string Git::branch( const std::string& projectDir ) { std::string buf; git( "rev-parse --abbrev-ref HEAD", projectDir, buf ); @@ -83,11 +88,18 @@ const std::string& Git::getGitFolder() const { return mGitFolder; } +bool Git::hasSubmodules( const std::string& projectDir ) { + return ( !projectDir.empty() && FileSystem::fileExists( projectDir + ".gitmodules" ) ) || + ( !mProjectPath.empty() && FileSystem::fileExists( mProjectPath + ".gitmodules" ) ); +} + Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) { + static constexpr auto DIFF_CMD = "diff --numstat"; + static constexpr auto STATUS_CMD = "-c color.status=never status -b -u -s"; Status s; std::string buf; - git( "diff --numstat", projectDir, buf ); - auto parseStatus = [&s, &buf]() { + git( DIFF_CMD, projectDir, buf ); + auto parseNumStat = [&s, &buf]() { auto lastNL = 0; auto nextNL = buf.find_first_of( '\n' ); while ( nextNL != std::string_view::npos ) { @@ -111,16 +123,62 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) } }; + parseNumStat(); + + bool submodules = hasSubmodules( projectDir ); + + if ( recurseSubmodules && submodules ) { + gitSubmodules( DIFF_CMD, projectDir, buf ); + parseNumStat(); + } + + bool modifiedSubmodule = false; + auto parseStatus = [&s, &buf, &modifiedSubmodule]() { + auto lastNL = 0; + auto nextNL = buf.find_first_of( '\n' ); + while ( nextNL != std::string_view::npos ) { + LuaPattern pattern( "\n([%s?][MARTUD?])%s(.*)" ); + LuaPattern::Range matches[3]; + if ( pattern.matches( buf.c_str(), lastNL, matches, nextNL ) ) { + auto status = buf.substr( matches[1].start, matches[1].end - matches[1].start ); + String::trimInPlace( status ); + auto file = buf.substr( matches[2].start, matches[2].end - matches[2].start ); + FileStatus rstatus = FileStatus::Unidentified; + if ( "??" == status ) + rstatus = FileStatus::Untracked; + else if ( "M" == status ) + rstatus = FileStatus::Modified; + else if ( "A" == status ) + rstatus = FileStatus::Added; + else if ( "D" == status ) + rstatus = FileStatus::Deleted; + else if ( "R" == status ) + rstatus = FileStatus::Renamed; + else if ( "T" == status ) + rstatus = FileStatus::TypeChanged; + else if ( "U" == status ) + rstatus = FileStatus::UpdatedUnmerged; + else if ( "m" == status ) + rstatus = FileStatus::ModifiedSubmodule; + + if ( rstatus != FileStatus::Unidentified ) { + if ( rstatus != FileStatus::ModifiedSubmodule ) + modifiedSubmodule = true; + else + s.files.insert( { std::move( file ), rstatus } ); + } + } + lastNL = nextNL; + nextNL = buf.find_first_of( '\n', nextNL + 1 ); + } + }; + + git( STATUS_CMD, projectDir, buf ); parseStatus(); - if ( recurseSubmodules ) { - bool hasSubmodules = - ( !projectDir.empty() && FileSystem::fileExists( projectDir + ".gitmodules" ) ) || - ( !mProjectPath.empty() && FileSystem::fileExists( mProjectPath + ".gitmodules" ) ); - if ( hasSubmodules ) { - git( "submodule foreach \"git diff --numstat\"", projectDir, buf ); - parseStatus(); - } + if ( modifiedSubmodule && submodules ) { + gitSubmodules( STATUS_CMD, projectDir, buf ); + parseStatus(); } return s; diff --git a/src/tools/ecode/plugins/git/git.hpp b/src/tools/ecode/plugins/git/git.hpp index 9f3d03553..c8315a7f3 100644 --- a/src/tools/ecode/plugins/git/git.hpp +++ b/src/tools/ecode/plugins/git/git.hpp @@ -1,3 +1,4 @@ +#include #include #include @@ -32,14 +33,27 @@ class Git { } }; + enum FileStatus { + Unidentified, + Modified = 'M', + Added = 'A', + Renamed = 'R', + TypeChanged = 'T', + UpdatedUnmerged = 'U', + Deleted = 'D', + Untracked = '?', + ModifiedSubmodule = 'm', + }; + struct Status { std::vector modified; int totalInserts{ 0 }; int totalDeletions{ 0 }; + std::map files; bool operator==( const Status& other ) const { return totalInserts == other.totalInserts && totalDeletions == other.totalDeletions && - modified == other.modified; + modified == other.modified && files == other.files; } }; @@ -47,6 +61,8 @@ class Git { void git( const std::string& args, const std::string& projectDir, std::string& buf ) const; + void gitSubmodules( const std::string& args, const std::string& projectDir, std::string& buf ); + Blame blame( const std::string& filepath, std::size_t line ) const; std::string branch( const std::string& projectDir = "" ); @@ -65,6 +81,8 @@ class Git { std::string mGitPath; std::string mProjectPath; std::string mGitFolder; + + bool hasSubmodules( const std::string& projectDir ); }; } // namespace ecode