History

fix: keep empty tree changes visible

Tree changes disappeared when their loaded diff had no parent, range, or paths, unlike the clean worktree block. Separate pane rendering from focusability so an available empty Tree block remains visible, reports clean, and stays out of Tab navigation.

Codex committed 3 months ago

Commit 901e69e1 parent 5ebe4eb2 files · +34 −7Browse files

Unified · Split

2 files
  1. gix-tix/spec.md +2 −1
  2. gix-tix/src/ui.rs +32 −6
gix-tix/spec.md+2−1
@@ -436,7 +436,8 @@ space first; changes blocks adapt within the remaining history width. · 435 unmodified lines
436436 - Each block has a top border carrying its compact summary. Tree summaries show
437437 the selected short hash; worktree summaries distinguish staged and unstaged
438438 counts. Kind totals, total files when non-redundant, and non-zero line totals
439− are color-coded. An empty enabled worktree says `Worktree clean` in green.
439+ are color-coded. Empty enabled Tree and Worktree blocks remain visible, say
440+ `clean` in green, and are not focusable.
440441 - Tree paths preserve tree-diff order. Worktree paths show staged entries first in
441442 green and unstaged/untracked/conflicted entries second in bright red, sorted by
442443 raw path within each group.
gix-tix/src/ui.rs+32−6
@@ -290,8 +290,8 @@ pub(crate) fn draw_with_worktree( · 289 unmodified lines
290290 } else {
291291 None
292292 };
293− let tree_visible = app.changes_visible() && tree_changes.is_some_and(Changes::is_visible);
294− let worktree_visible =
293+ let tree_shown = app.changes_visible() && tree_changes.is_some();
294+ let worktree_shown =
295295 app.changes_visible() && app.changes_mode == Some(ChangesMode::Both) && worktree_changes.is_some();
296296 let tree_summary = tree_changes.map(|changes| changes_summary(ChangePane::Tree, app, changes));
297297 let worktree_summary = worktree_changes.map(|changes| changes_summary(ChangePane::Worktree, app, changes));
@@ -310,13 +310,13 @@ pub(crate) fn draw_with_worktree( · 12 unmodified lines
310310 let (changes_layout, changes_panes, _) = changes_pane_areas(
311311 body,
312312 frame.area().height / 2,
313− tree_visible.then(|| {
313+ tree_shown.then(|| {
314314 (
315315 pane_height(tree_changes.expect("visible tree changes exist")),
316316 tree_summary.as_ref().map_or(0, Line::width),
317317 )
318318 }),
319− worktree_visible.then(|| {
319+ worktree_shown.then(|| {
320320 (
321321 pane_height(worktree_changes.expect("visible worktree changes exist")),
322322 worktree_summary.as_ref().map_or(0, Line::width),
@@ -406,7 +406,8 @@ pub(crate) fn draw_with_worktree( · 83 unmodified lines
406406 changes_layout,
407407 changes_panes
408408 .iter()
409− .any(|pane| pane.pane == ChangePane::Tree && pane.outer.height > 0),
409+ .any(|pane| pane.pane == ChangePane::Tree && pane.outer.height > 0)
410+ && tree_changes.is_some_and(Changes::is_visible),
410411 changes_panes
411412 .iter()
412413 .any(|pane| pane.pane == ChangePane::Worktree && pane.outer.height > 0)
@@ -1436,7 +1437,13 @@ fn changes_summary(pane: ChangePane, app: &App, changes: &Changes) -> Line<'stat · 1023 unmodified lines
14361437 },
14371438 |range| format!("{}..{}", range.base.to_hex_with_len(7), range.tip.to_hex_with_len(7)),
14381439 );
1439− vec![Span::raw(format!("─ Tree {label} ── "))]
1440+ let mut spans = vec![Span::raw(format!("─ Tree {label} "))];
1441+ if changes.paths.is_empty() {
1442+ spans.push(Span::styled("clean", color(Color::Green)));
1443+ spans.push(Span::raw(" "));
1444+ }
1445+ spans.push(Span::raw("── "));
1446+ spans
14401447 }
14411448 ChangePane::Worktree if changes.paths.is_empty() => vec![
14421449 Span::raw("─ Worktree "),
@@ -4771,6 +4778,25 @@ mod tests { · 3328 unmodified lines
47714778 "a clean worktree has no empty aggregate"
47724779 );
47734780 assert!(!app.worktree_changes_visible, "an empty block is not focusable");
4781+
4782+ terminal.draw(|frame| {
4783+ super::draw_with_worktree(
4784+ frame,
4785+ &mut app,
4786+ &Decorations::new(),
4787+ &gix::mailmap::Snapshot::default(),
4788+ None,
4789+ Some(&Changes::default()),
4790+ Some(&Changes::default()),
4791+ );
4792+ })?;
4793+ let (clean_y, clean_tree) = (0..8)
4794+ .map(|y| (y, rendered_line(&terminal, y)))
4795+ .find(|(_, line)| line.contains("Tree ------- clean"))
4796+ .expect("an empty tree remains visible and says it is clean");
4797+ let clean_x = clean_tree.find("clean").expect("clean tree label") as u16;
4798+ assert_eq!(terminal.backend().buffer()[(clean_x, clean_y)].fg, Color::Green);
4799+ assert!(!app.tree_changes_visible, "an empty tree block is not focusable");
47744800 Ok(())
47754801 }
47764802

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t