mirror of
https://github.com/RGBCube/serenity
synced 2025-07-23 09:27:35 +00:00
HackStudio: Add "commit" and "refresh" actions to Git widget
This commit is contained in:
parent
435c6c6f96
commit
f300b81648
5 changed files with 79 additions and 41 deletions
BIN
Base/res/icons/16x16/commit.png
Normal file
BIN
Base/res/icons/16x16/commit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 190 B |
|
@ -45,7 +45,7 @@ GitRepo::CreateResult GitRepo::try_to_create(const LexicalPath& repository_root)
|
||||||
|
|
||||||
RefPtr<GitRepo> GitRepo::initialize_repository(const LexicalPath& repository_root)
|
RefPtr<GitRepo> GitRepo::initialize_repository(const LexicalPath& repository_root)
|
||||||
{
|
{
|
||||||
auto res = command_wrapper("init", repository_root);
|
auto res = command_wrapper({ "init" }, repository_root);
|
||||||
if (res.is_null())
|
if (res.is_null())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
@ -60,10 +60,10 @@ Vector<LexicalPath> GitRepo::unstaged_files() const
|
||||||
modified.append(move(untracked));
|
modified.append(move(untracked));
|
||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
//
|
||||||
Vector<LexicalPath> GitRepo::staged_files() const
|
Vector<LexicalPath> GitRepo::staged_files() const
|
||||||
{
|
{
|
||||||
auto raw_result = command("diff --cached --name-only");
|
auto raw_result = command({ "diff", "--cached", "--name-only" });
|
||||||
if (raw_result.is_null())
|
if (raw_result.is_null())
|
||||||
return {};
|
return {};
|
||||||
return parse_files_list(raw_result);
|
return parse_files_list(raw_result);
|
||||||
|
@ -71,7 +71,7 @@ Vector<LexicalPath> GitRepo::staged_files() const
|
||||||
|
|
||||||
Vector<LexicalPath> GitRepo::modified_files() const
|
Vector<LexicalPath> GitRepo::modified_files() const
|
||||||
{
|
{
|
||||||
auto raw_result = command("ls-files --modified --exclude-standard");
|
auto raw_result = command({ "ls-files", "--modified", "--exclude-standard" });
|
||||||
if (raw_result.is_null())
|
if (raw_result.is_null())
|
||||||
return {};
|
return {};
|
||||||
return parse_files_list(raw_result);
|
return parse_files_list(raw_result);
|
||||||
|
@ -79,7 +79,7 @@ Vector<LexicalPath> GitRepo::modified_files() const
|
||||||
|
|
||||||
Vector<LexicalPath> GitRepo::untracked_files() const
|
Vector<LexicalPath> GitRepo::untracked_files() const
|
||||||
{
|
{
|
||||||
auto raw_result = command("ls-files --others --exclude-standard");
|
auto raw_result = command({ "ls-files", "--others", "--exclude-standard" });
|
||||||
if (raw_result.is_null())
|
if (raw_result.is_null())
|
||||||
return {};
|
return {};
|
||||||
return parse_files_list(raw_result);
|
return parse_files_list(raw_result);
|
||||||
|
@ -95,37 +95,38 @@ Vector<LexicalPath> GitRepo::parse_files_list(const String& raw_result)
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
String GitRepo::command(const String& git_command) const
|
String GitRepo::command(const Vector<String>& command_parts) const
|
||||||
{
|
{
|
||||||
return command_wrapper(git_command, m_repository_root);
|
return command_wrapper(command_parts, m_repository_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
String GitRepo::command_wrapper(const String& git_command, const LexicalPath& chdir)
|
String GitRepo::command_wrapper(const Vector<String>& command_parts, const LexicalPath& chdir)
|
||||||
{
|
{
|
||||||
return Core::command(String::format("git %s", git_command.characters()), chdir);
|
return Core::command("git", command_parts, chdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GitRepo::git_is_installed()
|
bool GitRepo::git_is_installed()
|
||||||
{
|
{
|
||||||
return !command_wrapper("--help", LexicalPath("/")).is_null();
|
return !command_wrapper({ "--help" }, LexicalPath("/")).is_null();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GitRepo::git_repo_exists(const LexicalPath& repo_root)
|
bool GitRepo::git_repo_exists(const LexicalPath& repo_root)
|
||||||
{
|
{
|
||||||
return !command_wrapper("status", repo_root).is_null();
|
return !command_wrapper({ "status" }, repo_root).is_null();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GitRepo::stage(const LexicalPath& file)
|
bool GitRepo::stage(const LexicalPath& file)
|
||||||
{
|
{
|
||||||
auto cmd = String::format("add %s", file.string().characters());
|
return !command({ "add", file.string() }).is_null();
|
||||||
auto res = command(cmd);
|
|
||||||
return !res.is_null();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GitRepo::unstage(const LexicalPath& file)
|
bool GitRepo::unstage(const LexicalPath& file)
|
||||||
{
|
{
|
||||||
auto cmd = String::format("reset HEAD -- %s", file.string().characters());
|
return !command({ "reset", "HEAD", "--", file.string() }).is_null();
|
||||||
return !command(cmd).is_null();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GitRepo::commit(const String& message)
|
||||||
|
{
|
||||||
|
return !command({ "commit", "-m", message }).is_null();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,9 +54,10 @@ public:
|
||||||
Vector<LexicalPath> staged_files() const;
|
Vector<LexicalPath> staged_files() const;
|
||||||
bool stage(const LexicalPath& file);
|
bool stage(const LexicalPath& file);
|
||||||
bool unstage(const LexicalPath& file);
|
bool unstage(const LexicalPath& file);
|
||||||
|
bool commit(const String& message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static String command_wrapper(const String& git_command, const LexicalPath& chdir);
|
static String command_wrapper(const Vector<String>& command_parts, const LexicalPath& chdir);
|
||||||
static bool git_is_installed();
|
static bool git_is_installed();
|
||||||
static bool git_repo_exists(const LexicalPath& repo_root);
|
static bool git_repo_exists(const LexicalPath& repo_root);
|
||||||
static Vector<LexicalPath> parse_files_list(const String&);
|
static Vector<LexicalPath> parse_files_list(const String&);
|
||||||
|
@ -69,7 +70,7 @@ private:
|
||||||
Vector<LexicalPath> modified_files() const;
|
Vector<LexicalPath> modified_files() const;
|
||||||
Vector<LexicalPath> untracked_files() const;
|
Vector<LexicalPath> untracked_files() const;
|
||||||
|
|
||||||
String command(const String& git_command) const;
|
String command(const Vector<String>& command_parts) const;
|
||||||
|
|
||||||
LexicalPath m_repository_root;
|
LexicalPath m_repository_root;
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
#include <AK/LogStream.h>
|
#include <AK/LogStream.h>
|
||||||
#include <LibGUI/Application.h>
|
#include <LibGUI/Application.h>
|
||||||
#include <LibGUI/BoxLayout.h>
|
#include <LibGUI/BoxLayout.h>
|
||||||
|
#include <LibGUI/Button.h>
|
||||||
|
#include <LibGUI/InputBox.h>
|
||||||
#include <LibGUI/Label.h>
|
#include <LibGUI/Label.h>
|
||||||
#include <LibGUI/MessageBox.h>
|
#include <LibGUI/MessageBox.h>
|
||||||
#include <LibGUI/Model.h>
|
#include <LibGUI/Model.h>
|
||||||
|
@ -37,22 +39,6 @@
|
||||||
|
|
||||||
namespace HackStudio {
|
namespace HackStudio {
|
||||||
|
|
||||||
void GitWidget::stage_file(const LexicalPath& file)
|
|
||||||
{
|
|
||||||
dbg() << "staging: " << file.string();
|
|
||||||
bool rc = m_git_repo->stage(file);
|
|
||||||
ASSERT(rc);
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GitWidget::unstage_file(const LexicalPath& file)
|
|
||||||
{
|
|
||||||
dbg() << "unstaging: " << file.string();
|
|
||||||
bool rc = m_git_repo->unstage(file);
|
|
||||||
ASSERT(rc);
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
GitWidget::GitWidget(const LexicalPath& repo_root)
|
GitWidget::GitWidget(const LexicalPath& repo_root)
|
||||||
: m_repo_root(repo_root)
|
: m_repo_root(repo_root)
|
||||||
{
|
{
|
||||||
|
@ -60,20 +46,43 @@ GitWidget::GitWidget(const LexicalPath& repo_root)
|
||||||
|
|
||||||
auto& unstaged = add<GUI::Widget>();
|
auto& unstaged = add<GUI::Widget>();
|
||||||
unstaged.set_layout<GUI::VerticalBoxLayout>();
|
unstaged.set_layout<GUI::VerticalBoxLayout>();
|
||||||
auto& unstaged_label = unstaged.add<GUI::Label>();
|
auto& unstaged_header = unstaged.add<GUI::Widget>();
|
||||||
|
unstaged_header.set_layout<GUI::HorizontalBoxLayout>();
|
||||||
|
|
||||||
|
auto& refresh_button = unstaged_header.add<GUI::Button>();
|
||||||
|
refresh_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/reload.png"));
|
||||||
|
refresh_button.set_preferred_size({ 16, 16 });
|
||||||
|
refresh_button.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed);
|
||||||
|
refresh_button.set_tooltip("refresh");
|
||||||
|
refresh_button.on_click = [this](int) { refresh(); };
|
||||||
|
|
||||||
|
auto& unstaged_label = unstaged_header.add<GUI::Label>();
|
||||||
unstaged_label.set_text("Unstaged");
|
unstaged_label.set_text("Unstaged");
|
||||||
unstaged_label.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
|
|
||||||
unstaged_label.set_preferred_size(0, 20);
|
unstaged_header.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
|
||||||
|
unstaged_header.set_preferred_size(0, 20);
|
||||||
m_unstaged_files = unstaged.add<GitFilesView>(
|
m_unstaged_files = unstaged.add<GitFilesView>(
|
||||||
[this](const auto& file) { stage_file(file); },
|
[this](const auto& file) { stage_file(file); },
|
||||||
Gfx::Bitmap::load_from_file("/res/icons/16x16/plus.png").release_nonnull());
|
Gfx::Bitmap::load_from_file("/res/icons/16x16/plus.png").release_nonnull());
|
||||||
|
|
||||||
auto& staged = add<GUI::Widget>();
|
auto& staged = add<GUI::Widget>();
|
||||||
staged.set_layout<GUI::VerticalBoxLayout>();
|
staged.set_layout<GUI::VerticalBoxLayout>();
|
||||||
auto& staged_label = staged.add<GUI::Label>();
|
|
||||||
staged_label.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
|
auto& staged_header = staged.add<GUI::Widget>();
|
||||||
staged_label.set_preferred_size(0, 20);
|
staged_header.set_layout<GUI::HorizontalBoxLayout>();
|
||||||
|
|
||||||
|
auto& commit_button = staged_header.add<GUI::Button>();
|
||||||
|
commit_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/commit.png"));
|
||||||
|
commit_button.set_preferred_size({ 16, 16 });
|
||||||
|
commit_button.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed);
|
||||||
|
commit_button.set_tooltip("commit");
|
||||||
|
commit_button.on_click = [this](int) { commit(); };
|
||||||
|
|
||||||
|
auto& staged_label = staged_header.add<GUI::Label>();
|
||||||
staged_label.set_text("Staged");
|
staged_label.set_text("Staged");
|
||||||
|
|
||||||
|
staged_header.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
|
||||||
|
staged_header.set_preferred_size(0, 20);
|
||||||
m_staged_files = staged.add<GitFilesView>(
|
m_staged_files = staged.add<GitFilesView>(
|
||||||
[this](const auto& file) { unstage_file(file); },
|
[this](const auto& file) { unstage_file(file); },
|
||||||
Gfx::Bitmap::load_from_file("/res/icons/16x16/minus.png").release_nonnull());
|
Gfx::Bitmap::load_from_file("/res/icons/16x16/minus.png").release_nonnull());
|
||||||
|
@ -100,4 +109,30 @@ void GitWidget::refresh()
|
||||||
m_staged_files->set_model(GitFilesModel::create(m_git_repo->staged_files()));
|
m_staged_files->set_model(GitFilesModel::create(m_git_repo->staged_files()));
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
void GitWidget::stage_file(const LexicalPath& file)
|
||||||
|
{
|
||||||
|
dbg() << "staging: " << file.string();
|
||||||
|
bool rc = m_git_repo->stage(file);
|
||||||
|
ASSERT(rc);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GitWidget::unstage_file(const LexicalPath& file)
|
||||||
|
{
|
||||||
|
dbg() << "unstaging: " << file.string();
|
||||||
|
bool rc = m_git_repo->unstage(file);
|
||||||
|
ASSERT(rc);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GitWidget::commit()
|
||||||
|
{
|
||||||
|
String message;
|
||||||
|
auto res = GUI::InputBox::show(message, window(), "Commit message:", "Commit");
|
||||||
|
if (res != GUI::InputBox::ExecOK || message.is_empty())
|
||||||
|
return;
|
||||||
|
dbg() << "commit message: " << message;
|
||||||
|
m_git_repo->commit(message);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ private:
|
||||||
|
|
||||||
void stage_file(const LexicalPath&);
|
void stage_file(const LexicalPath&);
|
||||||
void unstage_file(const LexicalPath&);
|
void unstage_file(const LexicalPath&);
|
||||||
|
void commit();
|
||||||
|
|
||||||
LexicalPath m_repo_root;
|
LexicalPath m_repo_root;
|
||||||
RefPtr<GitFilesView> m_unstaged_files;
|
RefPtr<GitFilesView> m_unstaged_files;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue