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
436- Each block has a top border carrying its compact summary. Tree summaries show436- Each block has a top border carrying its compact summary. Tree summaries show
437 the selected short hash; worktree summaries distinguish staged and unstaged437 the selected short hash; worktree summaries distinguish staged and unstaged
438 counts. Kind totals, total files when non-redundant, and non-zero line totals438 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.
440- Tree paths preserve tree-diff order. Worktree paths show staged entries first in441- Tree paths preserve tree-diff order. Worktree paths show staged entries first in
441 green and unstaged/untracked/conflicted entries second in bright red, sorted by442 green and unstaged/untracked/conflicted entries second in bright red, sorted by
442 raw path within each group.443 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
290 } else {290 } else {
291 None291 None
292 };292 };
293 let tree_visible = app.changes_visible() && tree_changes.is_some_and(Changes::is_visible);293 let tree_shown = app.changes_visible() && tree_changes.is_some();
294 let worktree_visible =294 let worktree_shown =
295 app.changes_visible() && app.changes_mode == Some(ChangesMode::Both) && worktree_changes.is_some();295 app.changes_visible() && app.changes_mode == Some(ChangesMode::Both) && worktree_changes.is_some();
296 let tree_summary = tree_changes.map(|changes| changes_summary(ChangePane::Tree, app, changes));296 let tree_summary = tree_changes.map(|changes| changes_summary(ChangePane::Tree, app, changes));
297 let worktree_summary = worktree_changes.map(|changes| changes_summary(ChangePane::Worktree, app, changes));297 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
310 let (changes_layout, changes_panes, _) = changes_pane_areas(310 let (changes_layout, changes_panes, _) = changes_pane_areas(
311 body,311 body,
312 frame.area().height / 2,312 frame.area().height / 2,
313 tree_visible.then(|| {313 tree_shown.then(|| {
314 (314 (
315 pane_height(tree_changes.expect("visible tree changes exist")),315 pane_height(tree_changes.expect("visible tree changes exist")),
316 tree_summary.as_ref().map_or(0, Line::width),316 tree_summary.as_ref().map_or(0, Line::width),
317 )317 )
318 }),318 }),
319 worktree_visible.then(|| {319 worktree_shown.then(|| {
320 (320 (
321 pane_height(worktree_changes.expect("visible worktree changes exist")),321 pane_height(worktree_changes.expect("visible worktree changes exist")),
322 worktree_summary.as_ref().map_or(0, Line::width),322 worktree_summary.as_ref().map_or(0, Line::width),
@@ -406,7 +406,8 @@ pub(crate) fn draw_with_worktree( · 83 unmodified lines
406 changes_layout,406 changes_layout,
407 changes_panes407 changes_panes
408 .iter()408 .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),
410 changes_panes411 changes_panes
411 .iter()412 .iter()
412 .any(|pane| pane.pane == ChangePane::Worktree && pane.outer.height > 0)413 .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
1436 },1437 },
1437 |range| format!("{}..{}", range.base.to_hex_with_len(7), range.tip.to_hex_with_len(7)),1438 |range| format!("{}..{}", range.base.to_hex_with_len(7), range.tip.to_hex_with_len(7)),
1438 );1439 );
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
1440 }1447 }
1441 ChangePane::Worktree if changes.paths.is_empty() => vec![1448 ChangePane::Worktree if changes.paths.is_empty() => vec![
1442 Span::raw("─ Worktree "),1449 Span::raw("─ Worktree "),
@@ -4771,6 +4778,25 @@ mod tests { · 3328 unmodified lines
4771 "a clean worktree has no empty aggregate"4778 "a clean worktree has no empty aggregate"
4772 );4779 );
4773 assert!(!app.worktree_changes_visible, "an empty block is not focusable");4780 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");
4774 Ok(())4800 Ok(())
4775 }4801 }
4776 4802

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