feat(details): add commit and working tree panels
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
# Build output and editor state
|
# Build output and editor state
|
||||||
/build/
|
/build/
|
||||||
|
/build-*/
|
||||||
/.vs/
|
/.vs/
|
||||||
/.vscode/
|
/.vscode/
|
||||||
/imgui.ini
|
/imgui.ini
|
||||||
|
|||||||
@@ -145,10 +145,44 @@ void GitManager::computeGraphLanes(RepositoryView& repository) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GitManager::loadWorkingTree(RepositoryView& repository) {
|
||||||
|
repository.working_files.clear();
|
||||||
|
git_status_options options{};
|
||||||
|
git_status_options_init(&options, GIT_STATUS_OPTIONS_VERSION);
|
||||||
|
options.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
|
||||||
|
options.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS |
|
||||||
|
GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX | GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR;
|
||||||
|
git_status_list* list = nullptr;
|
||||||
|
if (git_status_list_new(&list, repository.repo, &options) != 0) return;
|
||||||
|
|
||||||
|
auto add_file = [&repository](const char* path, FileChangeKind kind, bool staged) {
|
||||||
|
if (path) repository.working_files.push_back({path, kind, staged});
|
||||||
|
};
|
||||||
|
for (size_t index = 0; index < git_status_list_entrycount(list); ++index) {
|
||||||
|
const git_status_entry* entry = git_status_byindex(list, index);
|
||||||
|
if (!entry) continue;
|
||||||
|
const char* index_path = entry->head_to_index && entry->head_to_index->new_file.path
|
||||||
|
? entry->head_to_index->new_file.path : nullptr;
|
||||||
|
const char* worktree_path = entry->index_to_workdir && entry->index_to_workdir->new_file.path
|
||||||
|
? entry->index_to_workdir->new_file.path : nullptr;
|
||||||
|
if (entry->status & GIT_STATUS_INDEX_NEW) add_file(index_path, FileChangeKind::added, true);
|
||||||
|
else if (entry->status & GIT_STATUS_INDEX_DELETED) add_file(index_path, FileChangeKind::deleted, true);
|
||||||
|
else if (entry->status & GIT_STATUS_INDEX_RENAMED) add_file(index_path, FileChangeKind::renamed, true);
|
||||||
|
else if (entry->status & GIT_STATUS_INDEX_MODIFIED) add_file(index_path, FileChangeKind::modified, true);
|
||||||
|
|
||||||
|
if (entry->status & GIT_STATUS_WT_NEW) add_file(worktree_path, FileChangeKind::added, false);
|
||||||
|
else if (entry->status & GIT_STATUS_WT_DELETED) add_file(worktree_path, FileChangeKind::deleted, false);
|
||||||
|
else if (entry->status & GIT_STATUS_WT_RENAMED) add_file(worktree_path, FileChangeKind::renamed, false);
|
||||||
|
else if (entry->status & GIT_STATUS_WT_MODIFIED) add_file(worktree_path, FileChangeKind::modified, false);
|
||||||
|
}
|
||||||
|
git_status_list_free(list);
|
||||||
|
}
|
||||||
|
|
||||||
bool GitManager::loadRepositoryData(RepositoryView& repository, std::string& error) {
|
bool GitManager::loadRepositoryData(RepositoryView& repository, std::string& error) {
|
||||||
repository.local_branches.clear(); repository.remote_branches.clear(); repository.remotes.clear();
|
repository.local_branches.clear(); repository.remote_branches.clear(); repository.remotes.clear();
|
||||||
repository.worktrees.clear(); repository.worktree_branches.clear(); repository.submodules.clear();
|
repository.worktrees.clear(); repository.worktree_branches.clear(); repository.submodules.clear();
|
||||||
repository.commits.clear(); repository.selected_commit = 0;
|
repository.commits.clear(); repository.selected_commit = 0;
|
||||||
|
loadWorkingTree(repository);
|
||||||
const char* workdir = git_repository_workdir(repository.repo);
|
const char* workdir = git_repository_workdir(repository.repo);
|
||||||
repository.path = workdir ? workdir : git_repository_path(repository.repo);
|
repository.path = workdir ? workdir : git_repository_path(repository.repo);
|
||||||
std::filesystem::path path(repository.path);
|
std::filesystem::path path(repository.path);
|
||||||
|
|||||||
@@ -23,4 +23,5 @@ private:
|
|||||||
void loadRefBadges(RepositoryView& repository);
|
void loadRefBadges(RepositoryView& repository);
|
||||||
void computeGraphLanes(RepositoryView& repository);
|
void computeGraphLanes(RepositoryView& repository);
|
||||||
bool loadRepositoryData(RepositoryView& repository, std::string& error);
|
bool loadRepositoryData(RepositoryView& repository, std::string& error);
|
||||||
|
void loadWorkingTree(RepositoryView& repository);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ struct ChangedFile {
|
|||||||
FileChangeKind kind = FileChangeKind::other;
|
FileChangeKind kind = FileChangeKind::other;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct WorkingFile {
|
||||||
|
std::string path;
|
||||||
|
FileChangeKind kind = FileChangeKind::other;
|
||||||
|
bool staged = false;
|
||||||
|
};
|
||||||
|
|
||||||
struct CommitInfo {
|
struct CommitInfo {
|
||||||
git_oid oid{};
|
git_oid oid{};
|
||||||
std::string short_id;
|
std::string short_id;
|
||||||
@@ -49,6 +55,7 @@ struct RepositoryView {
|
|||||||
std::set<std::string> worktree_branches;
|
std::set<std::string> worktree_branches;
|
||||||
std::vector<std::string> submodules;
|
std::vector<std::string> submodules;
|
||||||
std::vector<CommitInfo> commits;
|
std::vector<CommitInfo> commits;
|
||||||
|
std::vector<WorkingFile> working_files;
|
||||||
int selected_commit = 0;
|
int selected_commit = 0;
|
||||||
|
|
||||||
RepositoryView() = default;
|
RepositoryView() = default;
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ std::string g_notice;
|
|||||||
bool g_init_popup = false;
|
bool g_init_popup = false;
|
||||||
bool g_about_popup = false;
|
bool g_about_popup = false;
|
||||||
bool g_licenses_popup = false;
|
bool g_licenses_popup = false;
|
||||||
|
enum class FileViewMode { path, tree };
|
||||||
|
FileViewMode g_file_view_mode = FileViewMode::path;
|
||||||
|
bool g_view_all_files = false;
|
||||||
|
std::array<char, 128> g_commit_summary{};
|
||||||
|
std::array<char, 1024> g_commit_description{};
|
||||||
float g_ui_scale = 1.0f;
|
float g_ui_scale = 1.0f;
|
||||||
float g_sidebar_width = 230.0f;
|
float g_sidebar_width = 230.0f;
|
||||||
WindowManager* g_window_manager = nullptr;
|
WindowManager* g_window_manager = nullptr;
|
||||||
@@ -354,6 +359,24 @@ void draw_commit_table() {
|
|||||||
ImGui::TableSetupColumn("COMMIT MESSAGE", ImGuiTableColumnFlags_WidthStretch);
|
ImGui::TableSetupColumn("COMMIT MESSAGE", ImGuiTableColumnFlags_WidthStretch);
|
||||||
ImGui::TableSetupColumn("COMMIT DATE / TIME", ImGuiTableColumnFlags_WidthFixed, ui(180.0f));
|
ImGui::TableSetupColumn("COMMIT DATE / TIME", ImGuiTableColumnFlags_WidthFixed, ui(180.0f));
|
||||||
ImGui::TableHeadersRow();
|
ImGui::TableHeadersRow();
|
||||||
|
if (!repo().working_files.empty()) {
|
||||||
|
ImGui::TableNextRow(0, ui(31.0f));
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
if (ImGui::Selectable("##working_tree", repo().selected_commit == -1,
|
||||||
|
ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap))
|
||||||
|
repo().selected_commit = -1;
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
const ImVec2 position = ImGui::GetCursorScreenPos();
|
||||||
|
ImDrawList* draw = ImGui::GetWindowDrawList();
|
||||||
|
const ImVec2 center{position.x + ui(15), position.y + ui(15.5f)};
|
||||||
|
draw->AddCircle(center, ui(7), IM_COL32(90, 180, 195, 210), 12, ui(1.5f));
|
||||||
|
ImGui::Dummy({0, ui(31)});
|
||||||
|
ImGui::TableSetColumnIndex(2);
|
||||||
|
ImGui::TextDisabled("// WIP");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextColored(ImVec4(0.94f, 0.66f, 0.25f, 1), ICON_FA_PEN " %d",
|
||||||
|
static_cast<int>(repo().working_files.size()));
|
||||||
|
}
|
||||||
for (int i = 0; i < static_cast<int>(repo().commits.size()); ++i) {
|
for (int i = 0; i < static_cast<int>(repo().commits.size()); ++i) {
|
||||||
const auto& commit = repo().commits[i];
|
const auto& commit = repo().commits[i];
|
||||||
if (g_filter[0]) {
|
if (g_filter[0]) {
|
||||||
@@ -396,26 +419,138 @@ void draw_commit_table() {
|
|||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_details() {
|
const char* change_icon(FileChangeKind kind) {
|
||||||
ImGui::BeginChild("details", {ui(360.0f), -ui(28.0f)}, ImGuiChildFlags_Borders);
|
if (kind == FileChangeKind::added) return ICON_FA_PLUS;
|
||||||
if (repo().commits.empty()) {
|
if (kind == FileChangeKind::deleted) return ICON_FA_MINUS;
|
||||||
ImGui::TextDisabled("Select a repository with commits");
|
if (kind == FileChangeKind::renamed) return ICON_FA_ARROW_RIGHT_ARROW_LEFT;
|
||||||
ImGui::EndChild();
|
return ICON_FA_PEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec4 change_color(FileChangeKind kind) {
|
||||||
|
if (kind == FileChangeKind::added) return {0.31f, 0.82f, 0.43f, 1};
|
||||||
|
if (kind == FileChangeKind::deleted) return {0.91f, 0.35f, 0.35f, 1};
|
||||||
|
if (kind == FileChangeKind::renamed) return {0.38f, 0.67f, 0.92f, 1};
|
||||||
|
return {0.94f, 0.66f, 0.25f, 1};
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_file_row(const std::string& path, FileChangeKind kind, int id) {
|
||||||
|
ImGui::PushID(id);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, change_color(kind));
|
||||||
|
ImGui::Selectable((std::string(change_icon(kind)) + " " + path).c_str());
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
if (ImGui::BeginPopupContextItem()) {
|
||||||
|
if (ImGui::MenuItem(ICON_FA_COPY " Copy path")) ImGui::SetClipboardText(path.c_str());
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_file_toolbar() {
|
||||||
|
ImGui::TextDisabled(ICON_FA_ARROW_DOWN_A_Z);
|
||||||
|
const float controls_width = ui(225.0f);
|
||||||
|
ImGui::SameLine(std::max(ImGui::GetCursorPosX() + ui(8), ImGui::GetWindowWidth() - controls_width));
|
||||||
|
const bool path_selected = g_file_view_mode == FileViewMode::path;
|
||||||
|
if (path_selected) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.15f, 0.28f, 0.46f, 1));
|
||||||
|
if (ImGui::Button(ICON_FA_BARS " Path")) g_file_view_mode = FileViewMode::path;
|
||||||
|
if (path_selected) ImGui::PopStyleColor();
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
const bool tree_selected = g_file_view_mode == FileViewMode::tree;
|
||||||
|
if (tree_selected) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.15f, 0.28f, 0.46f, 1));
|
||||||
|
if (ImGui::Button(ICON_FA_FOLDER_TREE " Tree")) g_file_view_mode = FileViewMode::tree;
|
||||||
|
if (tree_selected) ImGui::PopStyleColor();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Checkbox("View all files", &g_view_all_files);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename File>
|
||||||
|
void draw_files(const std::vector<File>& files, bool staged_filter = false, bool filter_by_stage = false) {
|
||||||
|
if (g_file_view_mode == FileViewMode::path) {
|
||||||
|
int id = 0;
|
||||||
|
for (const auto& file : files) {
|
||||||
|
if constexpr (requires { file.staged; }) if (filter_by_stage && file.staged != staged_filter) continue;
|
||||||
|
draw_file_row(file.path, file.kind, id++);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
std::map<std::string, std::vector<const File*>> groups;
|
||||||
|
for (const auto& file : files) {
|
||||||
|
if constexpr (requires { file.staged; }) if (filter_by_stage && file.staged != staged_filter) continue;
|
||||||
|
const size_t slash = file.path.find('/');
|
||||||
|
const std::string group = slash == std::string::npos ? "Files" : file.path.substr(0, slash);
|
||||||
|
groups[group].push_back(&file);
|
||||||
|
}
|
||||||
|
int id = 0;
|
||||||
|
for (const auto& [group, entries] : groups) {
|
||||||
|
if (ImGui::TreeNodeEx((std::string(ICON_FA_FOLDER) + " " + group).c_str(), ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
for (const File* file : entries) {
|
||||||
|
const size_t slash = file->path.find('/');
|
||||||
|
draw_file_row(slash == std::string::npos ? file->path : file->path.substr(slash + 1), file->kind, id++);
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_working_details() {
|
||||||
|
int staged = 0;
|
||||||
|
for (const auto& file : repo().working_files) if (file.staged) ++staged;
|
||||||
|
const int unstaged = static_cast<int>(repo().working_files.size()) - staged;
|
||||||
|
ImGui::SetCursorPosX(std::max(ui(8), (ImGui::GetWindowWidth() - ui(210)) * 0.5f));
|
||||||
|
ImGui::Text("%d file changes on", static_cast<int>(repo().working_files.size()));
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextColored(ImVec4(0.25f, 0.80f, 0.86f, 1), "%s", repo().branch.c_str());
|
||||||
|
ImGui::Separator();
|
||||||
|
draw_file_toolbar();
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::BeginChild("working_files", {-1, ui(260)}, false);
|
||||||
|
if (ImGui::TreeNodeEx((std::string("Unstaged Files (") + std::to_string(unstaged) + ")").c_str(),
|
||||||
|
ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||||
|
ImGui::SameLine(std::max(ui(150), ImGui::GetWindowWidth() - ui(135)));
|
||||||
|
if (ImGui::SmallButton("Stage All Changes")) g_notice = "Staging is not wired yet";
|
||||||
|
draw_files(repo().working_files, false, true);
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
if (ImGui::TreeNodeEx((std::string("Staged Files (") + std::to_string(staged) + ")").c_str(),
|
||||||
|
ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||||
|
draw_files(repo().working_files, true, true);
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::TextUnformatted(ICON_FA_CIRCLE_DOT " Commit");
|
||||||
|
ImGui::Separator();
|
||||||
|
static bool amend = false;
|
||||||
|
ImGui::Checkbox("Amend previous commit", &amend);
|
||||||
|
ImGui::InputTextWithHint("##commit_summary", "Commit summary", g_commit_summary.data(), g_commit_summary.size());
|
||||||
|
ImGui::InputTextMultiline("##commit_description", g_commit_description.data(), g_commit_description.size(),
|
||||||
|
{-1, ui(115)});
|
||||||
|
ImGui::BeginDisabled(staged == 0 || g_commit_summary[0] == '\0');
|
||||||
|
if (ImGui::Button("Stage Changes to Commit", {-1, ui(40)})) g_notice = "Commit creation is not wired yet";
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_commit_details() {
|
||||||
const int selected = std::clamp(repo().selected_commit, 0, static_cast<int>(repo().commits.size() - 1));
|
const int selected = std::clamp(repo().selected_commit, 0, static_cast<int>(repo().commits.size() - 1));
|
||||||
g_git_manager->loadCommitChanges(repo(), selected, g_notice);
|
g_git_manager->loadCommitChanges(repo(), selected, g_notice);
|
||||||
const auto& commit = repo().commits[selected];
|
const auto& commit = repo().commits[selected];
|
||||||
ImGui::TextDisabled("COMMIT");
|
ImGui::TextDisabled("commit:");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text("%s", commit.short_id.c_str());
|
ImGui::Text("%s", commit.short_id.c_str());
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Dummy({0, 6});
|
ImGui::BeginChild("message_card", {-1, ui(125)}, ImGuiChildFlags_Borders);
|
||||||
ImGui::PushTextWrapPos();
|
ImGui::PushTextWrapPos();
|
||||||
ImGui::Text("%s", commit.summary.c_str());
|
ImGui::Text("%s", commit.summary.c_str());
|
||||||
ImGui::PopTextWrapPos();
|
ImGui::PopTextWrapPos();
|
||||||
ImGui::Dummy({0, 26});
|
ImGui::EndChild();
|
||||||
ImGui::Separator();
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() - ui(80)) * 0.5f);
|
||||||
|
const ImVec2 handle = ImGui::GetCursorScreenPos();
|
||||||
|
ImGui::GetWindowDrawList()->AddLine(
|
||||||
|
handle,
|
||||||
|
{handle.x + ui(80), handle.y},
|
||||||
|
IM_COL32(72, 80, 94, 255),
|
||||||
|
ui(3));
|
||||||
|
ImGui::Dummy({ui(80), ui(6)});
|
||||||
|
|
||||||
const unsigned int author_texture = g_avatar_cache ? g_avatar_cache->textureFor(commit.email) : 0;
|
const unsigned int author_texture = g_avatar_cache ? g_avatar_cache->textureFor(commit.email) : 0;
|
||||||
if (author_texture) {
|
if (author_texture) {
|
||||||
ImGui::Image(ImTextureRef(static_cast<ImTextureID>(author_texture)), {ui(40), ui(40)});
|
ImGui::Image(ImTextureRef(static_cast<ImTextureID>(author_texture)), {ui(40), ui(40)});
|
||||||
@@ -423,48 +558,37 @@ void draw_details() {
|
|||||||
}
|
}
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
ImGui::TextColored(ImVec4(0.25f, 0.80f, 0.86f, 1), "%s", commit.author.c_str());
|
ImGui::TextColored(ImVec4(0.25f, 0.80f, 0.86f, 1), "%s", commit.author.c_str());
|
||||||
ImGui::TextDisabled("%s", commit.email.c_str());
|
|
||||||
ImGui::TextDisabled("authored %s", commit.date.c_str());
|
ImGui::TextDisabled("authored %s", commit.date.c_str());
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
ImGui::Dummy({0, 24});
|
if (!commit.parent_ids.empty()) {
|
||||||
ImGui::TextColored(ImVec4(0.95f, 0.68f, 0.22f, 1), "%d parent%s", commit.parents, commit.parents == 1 ? "" : "s");
|
char parent[GIT_OID_SHA1_HEXSIZE + 1]{};
|
||||||
ImGui::Separator();
|
git_oid_tostr(parent, sizeof(parent), &commit.parent_ids.front());
|
||||||
int added = 0;
|
ImGui::SameLine(std::max(ui(180), ImGui::GetWindowWidth() - ui(95)));
|
||||||
int modified = 0;
|
ImGui::TextDisabled("parent: %.7s", parent);
|
||||||
int deleted = 0;
|
}
|
||||||
|
ImGui::Dummy({0, ui(14)});
|
||||||
|
int added = 0, modified = 0, deleted = 0;
|
||||||
for (const auto& file : commit.changed_files) {
|
for (const auto& file : commit.changed_files) {
|
||||||
if (file.kind == FileChangeKind::added) ++added;
|
if (file.kind == FileChangeKind::added) ++added;
|
||||||
else if (file.kind == FileChangeKind::deleted) ++deleted;
|
else if (file.kind == FileChangeKind::deleted) ++deleted;
|
||||||
else ++modified;
|
else ++modified;
|
||||||
}
|
}
|
||||||
if (modified) ImGui::TextColored(ImVec4(0.94f, 0.66f, 0.25f, 1), ICON_FA_PEN " %d modified", modified);
|
if (modified) ImGui::TextColored(change_color(FileChangeKind::modified), ICON_FA_PEN " %d modified", modified);
|
||||||
if (added) {
|
if (added) { if (modified) ImGui::SameLine(); ImGui::TextColored(change_color(FileChangeKind::added), ICON_FA_PLUS " %d added", added); }
|
||||||
if (modified) ImGui::SameLine();
|
if (deleted) { if (modified || added) ImGui::SameLine(); ImGui::TextColored(change_color(FileChangeKind::deleted), ICON_FA_MINUS " %d deleted", deleted); }
|
||||||
ImGui::TextColored(ImVec4(0.31f, 0.82f, 0.43f, 1), ICON_FA_PLUS " %d added", added);
|
draw_file_toolbar();
|
||||||
}
|
ImGui::Separator();
|
||||||
if (deleted) {
|
if (g_file_view_mode == FileViewMode::tree) ImGui::TextUnformatted("Collapse All");
|
||||||
if (modified || added) ImGui::SameLine();
|
|
||||||
ImGui::TextColored(ImVec4(0.91f, 0.35f, 0.35f, 1), ICON_FA_MINUS " %d deleted", deleted);
|
|
||||||
}
|
|
||||||
ImGui::BeginChild("changed_files", {-1, -1});
|
ImGui::BeginChild("changed_files", {-1, -1});
|
||||||
for (int index = 0; index < static_cast<int>(commit.changed_files.size()); ++index) {
|
draw_files(commit.changed_files);
|
||||||
const auto& file = commit.changed_files[index];
|
|
||||||
const char* icon = file.kind == FileChangeKind::added ? ICON_FA_PLUS
|
|
||||||
: file.kind == FileChangeKind::deleted ? ICON_FA_MINUS : ICON_FA_PEN;
|
|
||||||
const ImVec4 color = file.kind == FileChangeKind::added ? ImVec4(0.31f, 0.82f, 0.43f, 1)
|
|
||||||
: file.kind == FileChangeKind::deleted ? ImVec4(0.91f, 0.35f, 0.35f, 1)
|
|
||||||
: ImVec4(0.94f, 0.66f, 0.25f, 1);
|
|
||||||
ImGui::PushID(index);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
|
||||||
ImGui::Selectable((std::string(icon) + " " + file.path).c_str());
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
if (ImGui::BeginPopupContextItem()) {
|
|
||||||
if (ImGui::MenuItem(ICON_FA_COPY " Copy path")) ImGui::SetClipboardText(file.path.c_str());
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
ImGui::PopID();
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_details() {
|
||||||
|
ImGui::BeginChild("details", {ui(368.0f), -ui(28.0f)}, ImGuiChildFlags_Borders);
|
||||||
|
if (repo().selected_commit == -1) draw_working_details();
|
||||||
|
else if (!repo().commits.empty()) draw_commit_details();
|
||||||
|
else ImGui::TextDisabled("Select a repository with commits");
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user