Skip to content

Commit 9874773

Browse files
committed
add short flag
1 parent 7eaba8d commit 9874773

File tree

7 files changed

+323
-0
lines changed

7 files changed

+323
-0
lines changed

src/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ int main(int argc, char** argv)
2020

2121
// Sub commands
2222
init_subcommand init(lg2_obj, app);
23+
status_subcommand status(lg2_obj, app);
2324

2425
app.parse(argc, argv);
2526

src/subcommand/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
subcommand_files = files([
22
'init_subcommand.cpp',
3+
'status_subcommand.cpp',
34
])

src/subcommand/status_subcommand.cpp

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#include <iostream>
2+
#include <ostream>
3+
#include <string>
4+
5+
#include <git2.h>
6+
7+
#include "status_subcommand.hpp"
8+
#include "../wrapper/status_wrapper.hpp"
9+
#include "git2/diff.h"
10+
11+
status_subcommand::status_subcommand(const libgit2_object&, CLI::App& app)
12+
{
13+
auto *sub = app.add_subcommand("status", "Show modified files in working directory, staged for your next commit");
14+
// Displays paths that have differences between the index file and the current HEAD commit,
15+
// paths that have differences between the working tree and the index file, and paths in the
16+
// working tree that are not tracked by Git (and are not ignored by gitignore[5]).
17+
// The first are what you would commit by running git commit;
18+
// the second and third are what you could commit by running git add before running git commit.
19+
20+
sub->add_flag("-s,--short", short_flag, "Give the output in the short-format.");
21+
sub->add_flag("--long", long_flag, "Give the output in the long-format. This is the default.");
22+
// sub->add_flag("--porcelain[=<version>]", porcelain, "Give the output in an easy-to-parse format for scripts.
23+
// This is similar to the short output, but will remain stable across Git versions and regardless of user configuration.
24+
// See below for details. The version parameter is used to specify the format version. This is optional and defaults
25+
// to the original version v1 format.");
26+
27+
sub->callback([this]() { this->run(); });
28+
};
29+
30+
std::string untracked_header = "Untracked files:\n";
31+
// "Untracked files:\n (use \"git add <file>...\" to include in what will be committed)";
32+
std::string tobecommited_header = "Changes to be committed:\n";
33+
// "Changes to be committed:\n (use \"git reset HEAD <file>...\" to unstage)";
34+
std::string ignored_header = "Ignored files:\n";
35+
// "Ignored files:\n (use \"git add -f <file>...\" to include in what will be committed)"
36+
std::string notstagged_header = "Changes not staged for commit:\n";
37+
// "Changes not staged for commit:\n (use \"git add%s <file>...\" to update what will be committed)\n (use \"git checkout -- <file>...\" to discard changes in working directory)"
38+
std::string nothingtocommit_message = "No changes added to commit";
39+
// "No changes added to commit (use \"git add\" and/or \"git commit -a\")"
40+
41+
struct status_messages
42+
{
43+
std::string short_mod;
44+
std::string long_mod;
45+
};
46+
47+
const std::map<git_status_t, status_messages> status_msg_map = //TODO : check spaces in short_mod
48+
{
49+
{ GIT_STATUS_CURRENT, {"", ""} },
50+
{ GIT_STATUS_INDEX_NEW, {"A ", "\t new file:"} },
51+
{ GIT_STATUS_INDEX_MODIFIED, {"M ", "\t modified:"} },
52+
{ GIT_STATUS_INDEX_DELETED, {"D ", "\t deleted:"} },
53+
{ GIT_STATUS_INDEX_RENAMED, {"R ", "\t renamed:"} },
54+
{ GIT_STATUS_INDEX_TYPECHANGE, {"T ", "\t typechange:"} },
55+
{ GIT_STATUS_WT_NEW, {"?? ", ""} },
56+
{ GIT_STATUS_WT_MODIFIED, {" M" , "\t modified:"} },
57+
{ GIT_STATUS_WT_DELETED, {" D ", "\t deleted:"} },
58+
{ GIT_STATUS_WT_TYPECHANGE, {" T ", "\t typechange:"} },
59+
{ GIT_STATUS_WT_RENAMED, {" R ", "\t renamed:"} },
60+
{ GIT_STATUS_WT_UNREADABLE, {"", ""} },
61+
{ GIT_STATUS_IGNORED, {"!! ", ""} },
62+
{ GIT_STATUS_CONFLICTED, {"", ""} },
63+
};
64+
65+
void print_entries(git_status_t status, status_list_wrapper& sl, bool head_selector, size_t output_format) // TODO: add different mods
66+
{
67+
const auto& entry_list = sl.get_entry_list(status);
68+
if (!entry_list.empty())
69+
{
70+
for (auto* entry : entry_list)
71+
{
72+
if ((output_format <= 1))
73+
{
74+
std::cout << status_msg_map.at(status).long_mod << "\t";
75+
}
76+
else if (output_format == 2)
77+
{
78+
std::cout << status_msg_map.at(status).short_mod;
79+
}
80+
81+
git_diff_delta* diff_delta;
82+
if (head_selector)
83+
{
84+
diff_delta = entry->head_to_index;
85+
}
86+
else
87+
{
88+
diff_delta = entry->index_to_workdir;
89+
}
90+
const char* old_path = diff_delta->old_file.path;
91+
const char* new_path = diff_delta->new_file.path;
92+
if (old_path && new_path && std::strcmp(old_path, new_path))
93+
{
94+
std::cout << old_path << " -> " << new_path << std::endl;
95+
}
96+
else
97+
{
98+
if (old_path)
99+
{
100+
std::cout << old_path << std::endl;
101+
}
102+
else
103+
{
104+
std::cout << new_path << std::endl;
105+
}
106+
}
107+
}
108+
}
109+
else
110+
{}
111+
}
112+
113+
void status_subcommand::run()
114+
{
115+
auto directory = get_current_git_path();
116+
auto bare = false;
117+
auto repo = repository_wrapper::init(directory, bare);
118+
auto sl = status_list_wrapper::status_list(repo);
119+
120+
// TODO: add branch info
121+
122+
size_t output_format = 0;
123+
if (short_flag)
124+
{
125+
output_format = 2;
126+
}
127+
if (long_flag)
128+
{
129+
output_format = 1;
130+
}
131+
// else if (porcelain_format)
132+
// {
133+
// output_format = 3;
134+
// }
135+
136+
if (sl.has_tobecommited_header())
137+
{
138+
std::cout << tobecommited_header << std::endl;
139+
print_entries(GIT_STATUS_INDEX_NEW, sl, true, output_format);
140+
print_entries(GIT_STATUS_INDEX_MODIFIED, sl, true, output_format);
141+
print_entries(GIT_STATUS_INDEX_DELETED, sl, true, output_format);
142+
print_entries(GIT_STATUS_INDEX_RENAMED, sl, true, output_format);
143+
print_entries(GIT_STATUS_INDEX_TYPECHANGE, sl, true, output_format);
144+
std::cout << std::endl;
145+
}
146+
147+
if (sl.has_notstagged_header())
148+
{
149+
std::cout << notstagged_header << std::endl;
150+
print_entries(GIT_STATUS_WT_MODIFIED, sl, false, output_format);
151+
print_entries(GIT_STATUS_WT_DELETED, sl, false, output_format);
152+
print_entries(GIT_STATUS_WT_TYPECHANGE, sl, false, output_format);
153+
print_entries(GIT_STATUS_WT_RENAMED, sl, false, output_format);
154+
std::cout << std::endl;
155+
}
156+
157+
if (sl.has_untracked_header())
158+
{
159+
std::cout << untracked_header << std::endl;
160+
print_entries(GIT_STATUS_WT_NEW, sl, false, output_format);
161+
std::cout << std::endl;
162+
}
163+
164+
if (sl.has_ignored_header())
165+
{
166+
std::cout << ignored_header << std::endl;
167+
print_entries(GIT_STATUS_IGNORED, sl, false, output_format);
168+
std::cout << std::endl;
169+
}
170+
}

src/subcommand/status_subcommand.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#pragma once
2+
3+
#include <CLI/CLI.hpp>
4+
5+
#include "../utils/common.hpp"
6+
7+
class status_subcommand
8+
{
9+
public:
10+
11+
explicit status_subcommand(const libgit2_object&, CLI::App& app);
12+
void run();
13+
14+
private:
15+
bool short_flag = false;
16+
bool long_flag = false;
17+
};

src/wrapper/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
wrapper_files = files([
22
'repository_wrapper.cpp',
3+
'status_wrapper.cpp',
34
])

src/wrapper/status_wrapper.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#include "../utils/git_exception.hpp"
2+
#include "../wrapper/status_wrapper.hpp"
3+
4+
status_list_wrapper::~status_list_wrapper()
5+
{
6+
git_status_list_free(p_ressource);
7+
p_ressource = nullptr;
8+
}
9+
10+
status_list_wrapper status_list_wrapper::status_list(const repository_wrapper& rw)
11+
{
12+
status_list_wrapper res;
13+
throwIfError(git_status_list_new(&(res.p_ressource), rw, nullptr));
14+
15+
std::size_t status_list_size = git_status_list_entrycount(res.p_ressource);
16+
for (std::size_t i = 0; i < status_list_size; ++i)
17+
{
18+
auto entry = git_status_byindex(res.p_ressource, i);
19+
res.m_entries[entry->status].push_back(entry);
20+
}
21+
22+
if (!res.get_entry_list(GIT_STATUS_INDEX_NEW).empty() || !res.get_entry_list(GIT_STATUS_INDEX_MODIFIED).empty() || !res.get_entry_list(GIT_STATUS_INDEX_DELETED).empty() || !res.get_entry_list(GIT_STATUS_INDEX_RENAMED).empty() || !res.get_entry_list(GIT_STATUS_INDEX_TYPECHANGE).empty())
23+
{
24+
res.m_tobecommited_header_flag = true;
25+
}
26+
if (!res.get_entry_list(GIT_STATUS_WT_NEW).empty())
27+
{
28+
res.m_untracked_header_flag = true;
29+
}
30+
if (!res.get_entry_list(GIT_STATUS_WT_MODIFIED).empty() || !res.get_entry_list(GIT_STATUS_WT_DELETED).empty() || !res.get_entry_list(GIT_STATUS_WT_TYPECHANGE).empty() || !res.get_entry_list(GIT_STATUS_WT_RENAMED).empty())
31+
{
32+
res.m_notstagged_header_flag = true;
33+
}
34+
if (!res.get_entry_list(GIT_STATUS_IGNORED).empty())
35+
{
36+
res.m_ignored_header_flag = true;
37+
}
38+
// if (!res.tobecommited_header_flag)
39+
// {
40+
// res.m_nothingtocommit_message_flag = true;
41+
// }
42+
43+
return res;
44+
}
45+
46+
bool status_list_wrapper::has_untracked_header() const
47+
{
48+
return m_untracked_header_flag;
49+
}
50+
bool status_list_wrapper::has_tobecommited_header() const
51+
{
52+
return m_tobecommited_header_flag;
53+
}
54+
bool status_list_wrapper::has_ignored_header() const
55+
{
56+
return m_ignored_header_flag;
57+
}
58+
bool status_list_wrapper::has_notstagged_header() const
59+
{
60+
return m_notstagged_header_flag;
61+
}
62+
bool status_list_wrapper::has_nothingtocommit_message() const
63+
{
64+
return m_nothingtocommit_message_flag;
65+
}
66+
67+
auto status_list_wrapper::get_entry_list(git_status_t status) const -> const status_entry_list&
68+
{
69+
if (auto search = m_entries.find(status); search != m_entries.end())
70+
{
71+
return search->second;
72+
}
73+
else
74+
{
75+
return m_empty;
76+
}
77+
}
78+
79+
80+
81+
// std::ostream& operator<<(std::ostream& out, const status_list_wrapper& slw)
82+
// {
83+
// std::size_t status_list_size = git_status_list_entrycount(slw);
84+
// for (std::size_t i = 0; i < status_list_size; ++i)
85+
// {
86+
// std::cout << i << " ";
87+
// auto entry = git_status_byindex(slw, i);
88+
89+
// }
90+
// return out;
91+
// };

src/wrapper/status_wrapper.hpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#pragma once
2+
3+
#include <map>
4+
#include <vector>
5+
6+
#include <git2.h>
7+
8+
#include "../wrapper/repository_wrapper.hpp"
9+
10+
class status_list_wrapper : public wrapper_base<git_status_list>
11+
{
12+
public:
13+
using status_entry_list = std::vector<const git_status_entry*>;
14+
15+
~status_list_wrapper();
16+
17+
status_list_wrapper(status_list_wrapper&&) = default;
18+
status_list_wrapper& operator=(status_list_wrapper&&) = default;
19+
20+
static status_list_wrapper status_list(const repository_wrapper& wrapper);
21+
22+
const status_entry_list& get_entry_list(git_status_t status) const;
23+
24+
bool has_untracked_header() const;
25+
bool has_tobecommited_header() const;
26+
bool has_ignored_header() const;
27+
bool has_notstagged_header() const;
28+
bool has_nothingtocommit_message() const;
29+
30+
private:
31+
32+
status_list_wrapper() = default;
33+
34+
using status_entry_map = std::map<git_status_t, status_entry_list>;
35+
status_entry_map m_entries;
36+
status_entry_list m_empty = {};
37+
bool m_untracked_header_flag = false;
38+
bool m_tobecommited_header_flag = false;
39+
bool m_ignored_header_flag = false;
40+
bool m_notstagged_header_flag = false;
41+
bool m_nothingtocommit_message_flag = false;
42+
};

0 commit comments

Comments
 (0)