Fix selection reset on background refresh, support per-repo table column widths, fix minimap drag scrolling & colors, indent details panels

This commit is contained in:
2026-06-19 15:52:20 -05:00
parent d338023e59
commit 0fea9ab8a4
4 changed files with 93 additions and 13 deletions

View File

@@ -206,10 +206,33 @@ void UserData::load()
if (const ikv_node_t *widths = object_value(settings, "commit_table_columns", IKV_ARRAY))
{
const uint32_t count = std::min<uint32_t>(
ikv_array_size(widths), static_cast<uint32_t>(commit_table_column_widths_.size()));
ikv_array_size(widths), 4);
for (uint32_t index = 0; index < count; ++index)
commit_table_column_widths_[index] = static_cast<float>(ikv_as_float(ikv_array_get(widths, index)));
}
if (const ikv_node_t *repos = object_value(settings, "repository_settings", IKV_ARRAY))
{
for (uint32_t index = 0; index < ikv_array_size(repos); ++index)
{
const ikv_node_t *repo_entry = ikv_array_get(repos, index);
if (ikv_node_type(repo_entry) != IKV_OBJECT)
continue;
const ikv_node_t *path_node = object_value(repo_entry, "path", IKV_STRING);
const ikv_node_t *widths_node = object_value(repo_entry, "commit_table_columns", IKV_ARRAY);
if (!path_node || !widths_node)
continue;
const char *path_str = ikv_as_string(path_node);
if (path_str && *path_str)
{
std::string normalized_path = normalizePath(path_str);
std::array<float, 4> &arr = repo_column_widths_[normalized_path];
arr = commit_table_column_widths_;
const uint32_t count = std::min<uint32_t>(ikv_array_size(widths_node), 4);
for (uint32_t c = 0; c < count; ++c)
arr[c] = static_cast<float>(ikv_as_float(ikv_array_get(widths_node, c)));
}
}
}
}
if (const ikv_node_t *history = object_value(root, "recently_closed", IKV_ARRAY))
{
@@ -279,6 +302,11 @@ void UserData::load()
height = std::clamp(height, 42.0f, 500.0f);
for (float &width : commit_table_column_widths_)
width = std::clamp(width, 0.0f, 1200.0f);
for (auto &[repo, widths_arr] : repo_column_widths_)
{
for (float &width : widths_arr)
width = std::clamp(width, 0.0f, 1200.0f);
}
if (open_repositories_.empty())
active_repository_ = 0;
else
@@ -570,6 +598,16 @@ void UserData::save() const
for (const float width : commit_table_column_widths_)
ikv_array_add_float(widths, width);
ikv_node_t *repos = ikv_object_add_array(settings, "repository_settings", IKV_OBJECT);
for (const auto &[repo_path, col_widths] : repo_column_widths_)
{
ikv_node_t *repo_entry = ikv_array_add_object(repos);
ikv_object_set_string(repo_entry, "path", repo_path.c_str());
ikv_node_t *repo_widths = ikv_object_add_array(repo_entry, "commit_table_columns", IKV_FLOAT);
for (const float w : col_widths)
ikv_array_add_float(repo_widths, w);
}
ikv_node_t *history = ikv_object_add_array(root, "recently_closed", IKV_STRING);
for (const auto &path : recently_closed_)
ikv_array_add_string(history, path.c_str());
@@ -596,3 +634,32 @@ void UserData::save() const
ikv_free(root);
removeLegacyFiles();
}
float UserData::commitTableColumnWidth(const std::string &repo_path, size_t index) const
{
if (index >= 4)
return 0.0f;
std::string normalized = normalizePath(repo_path);
auto it = repo_column_widths_.find(normalized);
if (it != repo_column_widths_.end())
return it->second[index];
return commit_table_column_widths_[index];
}
void UserData::setCommitTableColumnWidth(const std::string &repo_path, size_t index, float width)
{
if (index >= 4)
return;
std::string normalized = normalizePath(repo_path);
std::array<float, 4> &widths = repo_column_widths_[normalized];
// If this is a new entry, initialize with default global widths first
auto it = repo_column_widths_.find(normalized);
if (it->second[0] == 0.0f && it->second[1] == 0.0f && it->second[2] == 0.0f && it->second[3] == 0.0f)
{
widths = commit_table_column_widths_;
}
widths[index] = width;
save();
}

View File

@@ -30,7 +30,7 @@ public:
[[nodiscard]] float sidebarSectionHeight(size_t index) const { return sidebar_section_heights_.at(index); }
[[nodiscard]] bool sidebarCollapsed() const { return sidebar_collapsed_; }
[[nodiscard]] bool sidebarSectionOpen(size_t index) const { return sidebar_section_open_.at(index); }
[[nodiscard]] float commitTableColumnWidth(size_t index) const { return commit_table_column_widths_.at(index); }
[[nodiscard]] float commitTableColumnWidth(const std::string &repo_path, size_t index) const;
[[nodiscard]] int pullMode() const { return pull_mode_; }
[[nodiscard]] int zoomPercent() const { return zoom_percent_; }
[[nodiscard]] std::optional<SavedGitCredential> remoteCredential(const std::string &remote_url) const;
@@ -41,7 +41,7 @@ public:
void setSidebarSectionHeight(size_t index, float height) { sidebar_section_heights_.at(index) = height; }
void setSidebarCollapsed(bool collapsed) { sidebar_collapsed_ = collapsed; }
void setSidebarSectionOpen(size_t index, bool open) { sidebar_section_open_.at(index) = open; }
void setCommitTableColumnWidth(size_t index, float width) { commit_table_column_widths_.at(index) = width; }
void setCommitTableColumnWidth(const std::string &repo_path, size_t index, float width);
void setPullMode(int mode)
{
pull_mode_ = mode;
@@ -76,6 +76,7 @@ private:
std::array<float, 4> sidebar_section_heights_ = {110.0f, 220.0f, 90.0f, 150.0f};
bool sidebar_collapsed_ = false;
std::array<bool, 4> sidebar_section_open_ = {true, true, true, true};
std::unordered_map<std::string, std::array<float, 4>> repo_column_widths_;
std::array<float, 4> commit_table_column_widths_ = {0.0f, 0.0f, 0.0f, 0.0f};
int pull_mode_ = 1;
int zoom_percent_ = 100;

View File

@@ -439,7 +439,7 @@ std::vector<MinimapSegment> buildMinimapSegments(const std::string& text, Syntax
if (std::isspace(value)) {
size_t end = cursor + 1;
while (end < text.size() && std::isspace(static_cast<unsigned char>(text[end]))) ++end;
addMinimapSegment(segments, std::max(0.04f, static_cast<float>(end - cursor) * 0.18f), IM_COL32(0, 0, 0, 0));
addMinimapSegment(segments, static_cast<float>(end - cursor) * 0.22f, IM_COL32(0, 0, 0, 0));
cursor = end;
continue;
}
@@ -588,7 +588,9 @@ void drawMinimap(const std::vector<MinimapEntry>& entries, const ImVec2& viewpor
if ((hovered || active) && ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
const float mouse_ratio = std::clamp((ImGui::GetIO().MousePos.y - minimum.y) / std::max(1.0f, content_size.y), 0.0f, 1.0f);
const float target = std::clamp(mouse_ratio * rendered_height - clamped_visible_height * 0.5f, 0.0f, max_scroll_y);
ImGui::BeginChild("diff_content_main");
ImGui::SetScrollY(target);
ImGui::EndChild();
}
draw->AddRectFilled({minimum.x + scaled(1.0f, scale), viewport_y},
{minimum.x + viewport_size.x - scaled(1.0f, scale), viewport_y + viewport_height},

View File

@@ -368,8 +368,9 @@ void transfer_repository_state(RepositoryView& source, RepositoryView& target) {
target.undo_action = std::move(source.undo_action);
target.redo_action = std::move(source.redo_action);
}
std::string selected_commit_hash(const RepositoryView& repository) {
if (repository.selected_commit == -1)
return "working_tree";
if (repository.selected_commit < 0 || repository.selected_commit >= static_cast<int>(repository.commits.size()))
return {};
return oid_string(repository.commits[static_cast<size_t>(repository.selected_commit)].oid);
@@ -377,6 +378,10 @@ std::string selected_commit_hash(const RepositoryView& repository) {
void restore_selected_commit(RepositoryView& repository, const std::string& hash) {
if (hash.empty()) return;
if (hash == "working_tree") {
repository.selected_commit = -1;
return;
}
git_oid target{};
if (git_oid_fromstr(&target, hash.c_str()) != 0) return;
for (size_t index = 0; index < repository.commits.size(); ++index) {
@@ -1954,15 +1959,15 @@ void draw_commit_table() {
float graph_width = default_graph_width;
float date_width = default_date_width;
if (g_user_data) {
reference_width = std::clamp(ui(g_user_data->commitTableColumnWidth(0)),
reference_width = std::clamp(ui(g_user_data->commitTableColumnWidth(repo().path, 0)),
ui(120.0f), std::max(ui(120.0f), available_table_width * 0.45f));
graph_width = std::clamp(ui(g_user_data->commitTableColumnWidth(1)),
graph_width = std::clamp(ui(g_user_data->commitTableColumnWidth(repo().path, 1)),
ui(90.0f), std::max(ui(90.0f), available_table_width * 0.35f));
date_width = std::clamp(ui(g_user_data->commitTableColumnWidth(3)),
date_width = std::clamp(ui(g_user_data->commitTableColumnWidth(repo().path, 3)),
ui(130.0f), std::max(ui(130.0f), available_table_width * 0.30f));
if (g_user_data->commitTableColumnWidth(0) <= 0.0f) reference_width = default_reference_width;
if (g_user_data->commitTableColumnWidth(1) <= 0.0f) graph_width = default_graph_width;
if (g_user_data->commitTableColumnWidth(3) <= 0.0f) date_width = default_date_width;
if (g_user_data->commitTableColumnWidth(repo().path, 0) <= 0.0f) reference_width = default_reference_width;
if (g_user_data->commitTableColumnWidth(repo().path, 1) <= 0.0f) graph_width = default_graph_width;
if (g_user_data->commitTableColumnWidth(repo().path, 3) <= 0.0f) date_width = default_date_width;
}
if (reference_width + graph_width + date_width > available_table_width - ui(120.0f)) {
const float scale = std::max(0.5f, (available_table_width - ui(120.0f)) /
@@ -2020,7 +2025,7 @@ void draw_commit_table() {
ImGui::TableHeadersRow();
if (g_user_data) {
for (int column = 0; column < 4; ++column)
g_user_data->setCommitTableColumnWidth(static_cast<size_t>(column),
g_user_data->setCommitTableColumnWidth(repo().path, static_cast<size_t>(column),
ImGui::GetColumnWidth(column) / g_ui_scale);
}
ImGui::PopStyleColor();
@@ -2033,8 +2038,9 @@ void draw_commit_table() {
const float row_left = cursor.x - ImGui::GetStyle().CellPadding.x;
const float row_top = cursor.y - ImGui::GetStyle().CellPadding.y;
const float message_left = row_left + reference_width + graph_width;
const float scrollbar_size = ImGui::GetWindowWidth() - ImGui::GetWindowContentRegionMax().x > 0.0f ? ImGui::GetStyle().ScrollbarSize : 0.0f;
const float row_right = message_left + message_width + date_width +
ImGui::GetStyle().CellPadding.x * 2.0f;
ImGui::GetStyle().CellPadding.x * 2.0f - scrollbar_size;
const ImVec2 mouse = ImGui::GetIO().MousePos;
hovered = ImGui::IsWindowHovered() && mouse.x >= row_left && mouse.x < row_right &&
mouse.y >= row_top && mouse.y < row_top + row_height;
@@ -2594,6 +2600,7 @@ void draw_files(const std::vector<File>& files, bool staged_filter = false,
}
void draw_working_details() {
ImGui::Indent(ui(10.0f));
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;
@@ -2804,9 +2811,11 @@ void draw_working_details() {
ImGui::EndDisabled();
ImGui::Unindent(ui(8.0f));
ImGui::EndChild();
ImGui::Unindent(ui(10.0f));
}
void draw_commit_details() {
ImGui::Indent(ui(10.0f));
const int selected = std::clamp(repo().selected_commit, 0, static_cast<int>(repo().commits.size() - 1));
g_git_manager->loadCommitChanges(repo(), selected, g_notice);
auto& commit = repo().commits[selected];
@@ -2918,6 +2927,7 @@ void draw_commit_details() {
? commit.all_files : commit.changed_files;
draw_files(displayed_files, false, false, oid_string(commit.oid));
ImGui::EndChild();
ImGui::Unindent(ui(10.0f));
}
void draw_details(float width) {