style: move diff metadata into pane borders
This commit is contained in:
+346
-121
@@ -409,17 +409,6 @@ impl BufferViewports {
|
||||
let syntax = self.syntax.entry(editor.buffer_id()).or_default();
|
||||
let full_workspace = draw_bars(frame, editor, frame.area(), syntax);
|
||||
let multiple = editor.pane_layout().len() > 1;
|
||||
let diff_header = editor
|
||||
.diff()
|
||||
.filter(|diff| !multiple && diff.phase == Phase::View)
|
||||
.map(|_| {
|
||||
Rect::new(
|
||||
full_workspace.x,
|
||||
full_workspace.y,
|
||||
full_workspace.width,
|
||||
full_workspace.height.min(1),
|
||||
)
|
||||
});
|
||||
let (workspace, dock) = match editor.file_picker() {
|
||||
Some(picker) if picker.presentation == FilePresentation::Docked => dock_layout(
|
||||
full_workspace,
|
||||
@@ -432,13 +421,6 @@ impl BufferViewports {
|
||||
),
|
||||
_ => (full_workspace, None),
|
||||
};
|
||||
let dock = dock.map(|mut panel| {
|
||||
if let Some(header) = diff_header {
|
||||
panel.y = panel.y.saturating_add(header.height);
|
||||
panel.height = panel.height.saturating_sub(header.height);
|
||||
}
|
||||
panel
|
||||
});
|
||||
editor.set_pane_bounds(pane_rect(workspace));
|
||||
self.rects.clear();
|
||||
editor
|
||||
@@ -504,11 +486,6 @@ impl BufferViewports {
|
||||
self.panels.begin_frame();
|
||||
self.document.geometry = None;
|
||||
}
|
||||
if let Some(header) = diff_header
|
||||
&& let Some(diff) = editor.diff()
|
||||
{
|
||||
draw_diff_header(frame, diff, Some(editor), header);
|
||||
}
|
||||
if let Some(panel) = dock
|
||||
&& let Some(picker) = editor.file_picker()
|
||||
{
|
||||
@@ -2035,10 +2012,24 @@ struct DiffGeometry {
|
||||
wrapping: bool,
|
||||
}
|
||||
|
||||
fn diff_panel(frame: &mut Frame, area: Rect, title: &str, focused: bool) -> Rect {
|
||||
fn diff_panel(
|
||||
frame: &mut Frame,
|
||||
area: Rect,
|
||||
title: &str,
|
||||
state: &str,
|
||||
revision: &str,
|
||||
focused: bool,
|
||||
) -> Rect {
|
||||
if area.width < 4 || area.height < 4 {
|
||||
return area;
|
||||
}
|
||||
let title_width = usize::from(area.width - 2)
|
||||
.saturating_sub(UnicodeWidthStr::width(state) + usize::from(!state.is_empty()));
|
||||
let title = if UnicodeWidthStr::width(title) > title_width {
|
||||
Cow::Owned(visible_line(title, 0, title_width))
|
||||
} else {
|
||||
Cow::Borrowed(title)
|
||||
};
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_style(Style::default().fg(if focused {
|
||||
@@ -2046,7 +2037,9 @@ fn diff_panel(frame: &mut Frame, area: Rect, title: &str, focused: bool) -> Rect
|
||||
} else {
|
||||
Color::DarkGray
|
||||
}))
|
||||
.title(title);
|
||||
.title_top(Line::from(title).left_aligned())
|
||||
.title_top(Line::from(state).right_aligned())
|
||||
.title_bottom(Line::from(revision).left_aligned());
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
inner
|
||||
@@ -2296,46 +2289,6 @@ fn draw_diff_popups(
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_diff_header(frame: &mut Frame, diff: &DiffState, editor: Option<&Editor>, header: Rect) {
|
||||
if header.width == 0 || header.height == 0 {
|
||||
return;
|
||||
}
|
||||
let (before, after) = diff.comparison.as_ref().map_or(("", ""), |comparison| {
|
||||
(comparison.before.as_str(), comparison.after.as_str())
|
||||
});
|
||||
frame.render_widget(
|
||||
Paragraph::new(format!(
|
||||
"Diff · {} → {} · {:?} focus · {}",
|
||||
display_text(before),
|
||||
display_text(after),
|
||||
diff.focus,
|
||||
editor
|
||||
.filter(|editor| editor.diff_interacting())
|
||||
.map_or_else(
|
||||
|| "read-only".into(),
|
||||
|editor| format!(
|
||||
"{} · {}{} · {}:{}",
|
||||
if editor.diff_editing() {
|
||||
"editable"
|
||||
} else {
|
||||
"read-only"
|
||||
},
|
||||
if editor.visual_linewise() {
|
||||
"VISUAL LINE".into()
|
||||
} else {
|
||||
editor.mode().to_string()
|
||||
},
|
||||
if editor.dirty() { " [+]" } else { "" },
|
||||
editor.cursor().row + 1,
|
||||
editor.cursor().column + 1,
|
||||
),
|
||||
)
|
||||
))
|
||||
.style(Style::default().fg(Color::Black).bg(Color::Cyan)),
|
||||
header,
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_diff(
|
||||
frame: &mut Frame,
|
||||
diff: &DiffState,
|
||||
@@ -2362,7 +2315,7 @@ fn draw_diff(
|
||||
"After"
|
||||
};
|
||||
let title = format!(" Diff · Choose {stage} ");
|
||||
let content = diff_panel(frame, panel, &title, true);
|
||||
let content = diff_panel(frame, panel, &title, "", "", true);
|
||||
let notice = diff.error.as_deref().or_else(|| {
|
||||
if diff.loading {
|
||||
Some(if diff.after.is_some() {
|
||||
@@ -2526,7 +2479,7 @@ fn draw_diff(
|
||||
}
|
||||
frame.render_widget(
|
||||
Paragraph::new(format!(
|
||||
"{navigation_hint} · Tab categories · type search · Enter select · Esc back/clear · :diff.close"
|
||||
"{navigation_hint} · Tab categories · type search · Enter select · Esc close · Ctrl+p actions"
|
||||
))
|
||||
.style(Style::default().fg(Color::DarkGray)),
|
||||
help,
|
||||
@@ -2559,16 +2512,11 @@ fn draw_diff(
|
||||
syntax_error.or_else(|| selected.and_then(|file| file.notice.as_deref()))
|
||||
}
|
||||
});
|
||||
let [header, notice_area, workspace, help] = Layout::vertical([
|
||||
Constraint::Length(1),
|
||||
let [notice_area, workspace] = Layout::vertical([
|
||||
Constraint::Length(u16::from(notice.is_some() && area.height >= 3)),
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(u16::from(area.height >= 3)),
|
||||
])
|
||||
.areas(area);
|
||||
if !panels.workspace_managed || editor.is_none_or(|editor| editor.pane_layout().len() > 1) {
|
||||
draw_diff_header(frame, diff, editor, header);
|
||||
}
|
||||
if let Some(notice) = notice {
|
||||
frame.render_widget(
|
||||
Paragraph::new(display_text(notice)).style(Style::default().fg(
|
||||
@@ -2740,7 +2688,7 @@ fn draw_diff(
|
||||
&& let Some(syntax) = &panels.diff_syntax
|
||||
{
|
||||
if pane_layout == PaneLayout::Empty {
|
||||
diff_panel(frame, before_area, "", diff.focus == Focus::Before);
|
||||
diff_pane_panel(frame, diff, Some(file), before_area, true);
|
||||
} else {
|
||||
if before_area != Rect::default() {
|
||||
let text_area = draw_diff_pane(
|
||||
@@ -2810,6 +2758,7 @@ fn draw_diff(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let content = diff_pane_panel(frame, diff, selected, panes, true);
|
||||
frame.render_widget(
|
||||
Paragraph::new(if diff.loading {
|
||||
"Loading file…"
|
||||
@@ -2818,16 +2767,9 @@ fn draw_diff(
|
||||
} else {
|
||||
"No changed files"
|
||||
}),
|
||||
panes,
|
||||
content,
|
||||
);
|
||||
}
|
||||
frame.render_widget(
|
||||
Paragraph::new(
|
||||
"Native buffer bindings · Tab focus · [/] expand above/below in Normal · :diff.close",
|
||||
)
|
||||
.style(Style::default().fg(Color::DarkGray)),
|
||||
help,
|
||||
);
|
||||
panels.diff = Some(DiffGeometry {
|
||||
regions: [
|
||||
(navigator.unwrap_or_default(), Focus::Files),
|
||||
@@ -2854,6 +2796,62 @@ fn diff_status(status: FileStatus) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
fn diff_pane_panel(
|
||||
frame: &mut Frame,
|
||||
diff: &DiffState,
|
||||
file: Option<&ChangedFile>,
|
||||
area: Rect,
|
||||
before: bool,
|
||||
) -> Rect {
|
||||
if area.width < 4 || area.height < 4 {
|
||||
return area;
|
||||
}
|
||||
let title = file.map_or_else(
|
||||
|| " Diff ".into(),
|
||||
|file| {
|
||||
let label = if before { "Before" } else { "After" };
|
||||
let path = if before {
|
||||
file.old_path.as_ref().unwrap_or(&file.path)
|
||||
} else {
|
||||
&file.path
|
||||
};
|
||||
format!(
|
||||
" {label} · {} · {} ",
|
||||
diff_status(file.status),
|
||||
display_text(&path.to_string_lossy())
|
||||
)
|
||||
},
|
||||
);
|
||||
let revision = diff
|
||||
.comparison
|
||||
.as_ref()
|
||||
.map_or_else(String::new, |comparison| {
|
||||
if diff.pane_layout() == PaneLayout::Split {
|
||||
format!(
|
||||
" {} ",
|
||||
display_text(if before {
|
||||
&comparison.before
|
||||
} else {
|
||||
&comparison.after
|
||||
})
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
" {} → {} ",
|
||||
display_text(&comparison.before),
|
||||
display_text(&comparison.after)
|
||||
)
|
||||
}
|
||||
});
|
||||
let state = if !before && diff.after_editable() {
|
||||
" editable "
|
||||
} else {
|
||||
" read-only "
|
||||
};
|
||||
let focus = if before { Focus::Before } else { Focus::After };
|
||||
diff_panel(frame, area, &title, state, &revision, diff.focus == focus)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn draw_diff_pane(
|
||||
frame: &mut Frame,
|
||||
@@ -2870,19 +2868,8 @@ fn draw_diff_pane(
|
||||
if area.width == 0 || area.height == 0 {
|
||||
return area;
|
||||
}
|
||||
let label = if before { "Before" } else { "After" };
|
||||
let path = if before {
|
||||
file.old_path.as_ref().unwrap_or(&file.path)
|
||||
} else {
|
||||
&file.path
|
||||
};
|
||||
let title = format!(
|
||||
" {label} · {} · {} ",
|
||||
diff_status(file.status),
|
||||
display_text(&path.to_string_lossy())
|
||||
);
|
||||
let focus = if before { Focus::Before } else { Focus::After };
|
||||
let content = diff_panel(frame, area, &title, diff.focus == focus);
|
||||
let content = diff_pane_panel(frame, diff, Some(file), area, before);
|
||||
if diff.display_rows.is_empty() {
|
||||
frame.render_widget(
|
||||
Paragraph::new(file.notice.as_deref().map(display_text).unwrap_or_else(|| {
|
||||
@@ -4592,6 +4579,178 @@ mod tests {
|
||||
notice: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diff_borders_keep_full_revisions_and_each_panes_own_editability() {
|
||||
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(180, 12)).unwrap();
|
||||
let mut panels = WheelPanels::default();
|
||||
for case in ["working", "unlisted", "historical", "binary"] {
|
||||
let mut file = syntax_diff_file("new.rs", "fn old() {}", "fn new() {}");
|
||||
file.status = FileStatus::Renamed;
|
||||
file.old_path = Some("old.rs".into());
|
||||
if case == "binary" {
|
||||
file.notice = Some("Binary or non-UTF-8 file; text comparison unavailable".into());
|
||||
}
|
||||
let mut diff = diff_comparison(vec![file]);
|
||||
diff.files_visible = false;
|
||||
let comparison = diff.comparison.as_mut().unwrap();
|
||||
comparison.before = "abcdef0123456789 (baseline)".into();
|
||||
comparison.after = "fedcba9876543210 (destination)".into();
|
||||
if case != "unlisted" {
|
||||
comparison.editable_paths.insert("new.rs".into());
|
||||
}
|
||||
if case == "historical" {
|
||||
diff.after.as_mut().unwrap().target =
|
||||
crate::diff::RevisionTarget::Commit("fedcba9876543210".into());
|
||||
}
|
||||
let writable = case == "working";
|
||||
assert_eq!(diff.after_editable(), writable, "{case}");
|
||||
for focus in [Focus::Before, Focus::After] {
|
||||
diff.focus = focus;
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
let regions = panels.diff.as_ref().unwrap().regions;
|
||||
for (index, label, path, state) in [
|
||||
(1, "abcdef0123456789 (baseline)", "old.rs", "read-only"),
|
||||
(
|
||||
2,
|
||||
"fedcba9876543210 (destination)",
|
||||
"new.rs",
|
||||
if writable { "editable" } else { "read-only" },
|
||||
),
|
||||
] {
|
||||
let pane = regions[index].0;
|
||||
let top = pane_screen(&terminal, Rect::new(pane.x, pane.y, pane.width, 1));
|
||||
let bottom = pane_screen(
|
||||
&terminal,
|
||||
Rect::new(pane.x, pane.bottom() - 1, pane.width, 1),
|
||||
);
|
||||
assert!(top.contains(path), "{case}: {top}");
|
||||
assert!(
|
||||
pane_screen(&terminal, Rect::new(pane.right() - 13, pane.y, 12, 1),)
|
||||
.contains(state),
|
||||
"{case}: {top}",
|
||||
);
|
||||
assert!(
|
||||
bottom.find(label).is_some_and(|offset| {
|
||||
UnicodeWidthStr::width(&bottom[..offset]) <= 2
|
||||
}),
|
||||
"{bottom}",
|
||||
);
|
||||
assert!(!top.contains(label));
|
||||
assert!(!bottom.contains('→'));
|
||||
assert_eq!(screen_text(&terminal).matches(label).count(), 1);
|
||||
assert_eq!(
|
||||
terminal.backend().buffer()[(pane.x, pane.y)].fg,
|
||||
if regions[index].1 == focus {
|
||||
Color::Cyan
|
||||
} else {
|
||||
Color::DarkGray
|
||||
},
|
||||
);
|
||||
}
|
||||
assert!(!screen_text(&terminal).contains("Native buffer bindings"));
|
||||
assert!(!screen_text(&terminal).contains("focus ·"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diff_workspace_reclaims_header_and_footer_without_hiding_notices() {
|
||||
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(120, 14)).unwrap();
|
||||
let mut panels = WheelPanels::default();
|
||||
let mut diff = diff_comparison(vec![deletion_file()]);
|
||||
for notice in [None, Some("comparison failed"), Some("loading")] {
|
||||
diff.error = notice
|
||||
.filter(|notice| *notice != "loading")
|
||||
.map(str::to_owned);
|
||||
diff.loading = notice == Some("loading");
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
let area = terminal.backend().buffer().area;
|
||||
let regions = panels.diff.as_ref().unwrap().regions;
|
||||
for (pane, _) in regions {
|
||||
assert_eq!(pane.y, area.y + u16::from(notice.is_some()));
|
||||
assert_eq!(pane.bottom(), area.bottom());
|
||||
}
|
||||
if let Some(notice) = notice {
|
||||
let row = pane_screen(&terminal, Rect::new(area.x, area.y, area.width, 1));
|
||||
assert!(row.contains(if notice == "loading" {
|
||||
"Loading file"
|
||||
} else {
|
||||
notice
|
||||
}));
|
||||
}
|
||||
let [_, before, after] = regions.map(|(pane, _)| pane);
|
||||
assert_eq!(before.right(), after.x);
|
||||
assert_eq!(
|
||||
diff_inner(before).height,
|
||||
area.height - 2 - u16::from(notice.is_some()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diff_border_titles_clip_unicode_without_overwriting_state_or_text() {
|
||||
let mut file = syntax_diff_file(
|
||||
&format!("界e\u{301}👩🚀\n\t{}", "long-path".repeat(12)),
|
||||
"old",
|
||||
"new",
|
||||
);
|
||||
file.old_path = Some(format!("e\u{301}界👩🚀\u{1b}{}", "old-path".repeat(12)).into());
|
||||
let mut diff = diff_comparison(vec![file]);
|
||||
diff.files_visible = false;
|
||||
let comparison = diff.comparison.as_mut().unwrap();
|
||||
comparison.before = "before 界e\u{301}👩🚀\n\t\u{1b}".into();
|
||||
comparison.after = "after e\u{301}界👩🚀\r\u{7f}".into();
|
||||
let mut panels = WheelPanels::default();
|
||||
for (width, height) in [(180, 10), (64, 8), (36, 6), (8, 4), (3, 3), (1, 1)] {
|
||||
let mut terminal =
|
||||
Terminal::new(ratatui::backend::TestBackend::new(width, height)).unwrap();
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
for (pane, _) in panels.diff.as_ref().unwrap().regions.into_iter().skip(1) {
|
||||
assert!(pane.right() <= width && pane.bottom() <= height);
|
||||
let buffer = terminal.backend().buffer();
|
||||
for y in pane.y..pane.bottom() {
|
||||
for x in pane.x..pane.right() {
|
||||
let symbol = buffer[(x, y)].symbol();
|
||||
assert!(!symbol.chars().any(char::is_control), "{symbol:?}");
|
||||
assert!(!symbol.starts_with('\u{301}'), "{symbol:?}");
|
||||
assert!(!symbol.starts_with('\u{200d}'), "{symbol:?}");
|
||||
if symbol.contains('👩') || symbol.contains('🚀') {
|
||||
assert_eq!(symbol, "👩🚀");
|
||||
}
|
||||
}
|
||||
}
|
||||
if width >= 36 {
|
||||
assert!(
|
||||
pane_screen(&terminal, Rect::new(pane.right() - 13, pane.y, 12, 1))
|
||||
.contains("read-only")
|
||||
);
|
||||
let inner = diff_inner(pane);
|
||||
assert_eq!(buffer[(inner.x, inner.y)].symbol(), "1");
|
||||
assert_eq!(
|
||||
buffer[(inner.x + 3, inner.y)].symbol(),
|
||||
if pane.x == 0 { "o" } else { "n" },
|
||||
);
|
||||
}
|
||||
if width == 180 {
|
||||
let bottom = pane_screen(
|
||||
&terminal,
|
||||
Rect::new(pane.x, pane.bottom() - 1, pane.width, 1),
|
||||
);
|
||||
for grapheme in [
|
||||
if pane.x == 0 { "before" } else { "after" },
|
||||
"界",
|
||||
"e\u{301}",
|
||||
"👩🚀",
|
||||
] {
|
||||
assert!(bottom.contains(grapheme), "{bottom}");
|
||||
}
|
||||
assert_eq!(bottom.matches('�').count(), if pane.x == 0 { 3 } else { 2 });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diff_status_layouts_hide_absent_panes_and_leave_unchanged_renames_blank() {
|
||||
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(160, 12)).unwrap();
|
||||
@@ -4621,6 +4780,11 @@ mod tests {
|
||||
}];
|
||||
let mut diff = diff_comparison(vec![file]);
|
||||
diff.files_visible = false;
|
||||
diff.comparison
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.editable_paths
|
||||
.insert("deleted-lines.txt".into());
|
||||
diff.focus = if added { Focus::After } else { Focus::Before };
|
||||
diff.left_after = 2;
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
@@ -4653,6 +4817,17 @@ mod tests {
|
||||
}));
|
||||
assert!(text.contains(if added { "After · A" } else { "Before · D" }));
|
||||
assert!(!text.contains(if added { "Before ·" } else { "After ·" }));
|
||||
let bottom = pane_screen(
|
||||
&terminal,
|
||||
Rect::new(present.x, present.bottom() - 1, present.width, 1),
|
||||
);
|
||||
assert!(bottom.contains("old revision → Working checkout"));
|
||||
assert_eq!(text.matches("old revision").count(), 1);
|
||||
assert_eq!(text.matches("Working checkout").count(), 1);
|
||||
assert!(
|
||||
pane_screen(&terminal, Rect::new(present.right() - 13, present.y, 12, 1),)
|
||||
.contains(if added { "editable" } else { "read-only" })
|
||||
);
|
||||
assert!(!text.contains('╱'));
|
||||
}
|
||||
let mut empty_added = deletion_file();
|
||||
@@ -4669,6 +4844,14 @@ mod tests {
|
||||
assert_eq!(geometry.regions[1].0, Rect::default());
|
||||
assert_eq!(geometry.regions[2].0.width, 160);
|
||||
assert!(screen_text(&terminal).contains("metadata-only addition"));
|
||||
let pane = geometry.regions[2].0;
|
||||
assert!(
|
||||
pane_screen(
|
||||
&terminal,
|
||||
Rect::new(pane.x, pane.bottom() - 1, pane.width, 1),
|
||||
)
|
||||
.contains("old revision → Working checkout")
|
||||
);
|
||||
|
||||
let mut renamed = deletion_file();
|
||||
renamed.status = FileStatus::Renamed;
|
||||
@@ -4699,8 +4882,13 @@ mod tests {
|
||||
}
|
||||
}
|
||||
let text = screen_text(&terminal);
|
||||
assert!(!text.contains("Before ·"));
|
||||
assert!(!text.contains("After ·"));
|
||||
assert!(
|
||||
pane_screen(
|
||||
&terminal,
|
||||
Rect::new(blank.x, blank.bottom() - 1, blank.width, 1),
|
||||
)
|
||||
.contains("old revision → Working checkout")
|
||||
);
|
||||
assert!(!text.contains("unchanged rename content"));
|
||||
assert!(!text.contains('╱'));
|
||||
|
||||
@@ -4842,6 +5030,8 @@ mod tests {
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
let text = screen_text(&terminal);
|
||||
assert!(text.contains("Choose Before"));
|
||||
assert!(text.contains("Tab categories"));
|
||||
assert!(text.contains("Enter select"));
|
||||
assert!(text.contains("Working checkout · pinned"));
|
||||
assert!(text.contains("> commit-19"));
|
||||
assert!(!text.contains("commit-00"));
|
||||
@@ -4857,6 +5047,8 @@ mod tests {
|
||||
diff.handle(Input::Enter);
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
assert!(screen_text(&terminal).contains("Choose After · Before: commit-19"));
|
||||
assert!(screen_text(&terminal).contains("Tab categories"));
|
||||
assert!(screen_text(&terminal).contains("Enter select"));
|
||||
diff.handle(Input::Ctrl('u'));
|
||||
diff.handle(Input::Char('\t'));
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
@@ -4977,7 +5169,7 @@ mod tests {
|
||||
}
|
||||
assert_eq!(buffer[(before.x, before.y)].fg, Color::Cyan);
|
||||
assert_eq!(buffer[(after.x, after.y)].fg, Color::DarkGray);
|
||||
assert!(screen_text(&terminal).contains("Before focus"));
|
||||
assert_eq!(diff.focus, Focus::Before);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -5149,9 +5341,6 @@ mod tests {
|
||||
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(100, 12)).unwrap();
|
||||
let mut panels = WheelPanels::default();
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
let text = screen_text(&terminal);
|
||||
assert!(text.contains("Before · R · old-name.txt"));
|
||||
assert!(text.contains("After · R · new-name.txt"));
|
||||
let geometry = panels.diff.as_ref().unwrap();
|
||||
let before = geometry.regions[1].0;
|
||||
let after = geometry.regions[2].0;
|
||||
@@ -5163,7 +5352,7 @@ mod tests {
|
||||
assert_eq!(buffer[(after.x + 8, after.y + 1)].fg, Color::Reset);
|
||||
diff.handle(Input::Char('\t'));
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
assert!(screen_text(&terminal).contains("After focus"));
|
||||
assert_eq!(diff.focus, Focus::After);
|
||||
assert_eq!(
|
||||
terminal.backend().buffer()[(after.x, after.y)].fg,
|
||||
Color::Cyan
|
||||
@@ -5184,7 +5373,7 @@ mod tests {
|
||||
let navigator = regions[0].0;
|
||||
let before = regions[1].0;
|
||||
let after = regions[2].0;
|
||||
let workspace = Rect::new(0, 1, 120, 16);
|
||||
let workspace = terminal.backend().buffer().area;
|
||||
let (panes, dock) = dock_layout(workspace, DockSide::Right, true);
|
||||
assert_eq!(Some(navigator), dock);
|
||||
assert_eq!(before.x, panes.x);
|
||||
@@ -5424,10 +5613,40 @@ mod tests {
|
||||
}]);
|
||||
render_diff(&mut terminal, &blank, &mut panels);
|
||||
assert!(screen_text(&terminal).contains("Empty file"));
|
||||
let mut unloaded_file = deletion_file();
|
||||
unloaded_file.loaded = false;
|
||||
let mut unloaded = diff_comparison(vec![unloaded_file]);
|
||||
unloaded.loading = false;
|
||||
render_diff(&mut terminal, &unloaded, &mut panels);
|
||||
assert!(screen_text(&terminal).contains("File details unavailable"));
|
||||
for state in [&empty, &binary, &blank, &unloaded] {
|
||||
render_diff(&mut terminal, state, &mut panels);
|
||||
let pane = panels
|
||||
.diff
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.regions
|
||||
.into_iter()
|
||||
.skip(1)
|
||||
.find(|(pane, _)| *pane != Rect::default())
|
||||
.unwrap()
|
||||
.0;
|
||||
assert!(
|
||||
pane_screen(
|
||||
&terminal,
|
||||
Rect::new(pane.x, pane.bottom() - 1, pane.width, 1),
|
||||
)
|
||||
.contains("old revision → Working checkout")
|
||||
);
|
||||
assert!(
|
||||
pane_screen(&terminal, Rect::new(pane.right() - 13, pane.y, 12, 1),)
|
||||
.contains("read-only")
|
||||
);
|
||||
}
|
||||
for (width, height) in [(1, 1), (2, 2), (3, 3), (8, 4), (39, 5)] {
|
||||
let mut tiny =
|
||||
Terminal::new(ratatui::backend::TestBackend::new(width, height)).unwrap();
|
||||
for state in [&diff, &empty, &binary, &blank] {
|
||||
for state in [&diff, &empty, &binary, &blank, &unloaded] {
|
||||
render_diff(&mut tiny, state, &mut panels);
|
||||
if let Some(geometry) = &panels.diff {
|
||||
for (rect, _) in geometry.regions {
|
||||
@@ -7118,7 +7337,7 @@ mod tests {
|
||||
);
|
||||
}
|
||||
}
|
||||
assert_eq!(views.panels.files.unwrap().0.y, 2);
|
||||
assert_eq!(views.panels.files.unwrap().0.y, views.rects[0].1.y);
|
||||
let title = pane_screen(&terminal, Rect::new(0, 0, 120, 1));
|
||||
editor.handle(Input::Char(' '));
|
||||
editor.handle(Input::Char('o'));
|
||||
@@ -7242,8 +7461,6 @@ mod tests {
|
||||
.draw(|frame| views.draw_session(frame, &mut session))
|
||||
.unwrap();
|
||||
assert!(views.diff_visible);
|
||||
assert_eq!(terminal.backend().buffer()[(0, 1)].bg, Color::Cyan);
|
||||
assert_eq!(views.panels.files.unwrap().0.y, 2);
|
||||
|
||||
session.execute("diff");
|
||||
terminal
|
||||
@@ -7279,22 +7496,30 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn native_diff_dock_stays_below_the_full_width_header() {
|
||||
let mut editor = readonly_diff_editor(deletion_file());
|
||||
let mut views = BufferViewports::default();
|
||||
fn native_diff_dock_and_panes_fill_the_workspace_below_only_configured_chrome() {
|
||||
for (width, height) in [(120, 30), (32, 9)] {
|
||||
let mut terminal =
|
||||
Terminal::new(ratatui::backend::TestBackend::new(width, height)).unwrap();
|
||||
terminal
|
||||
.draw(|frame| views.draw(frame, &mut editor))
|
||||
.unwrap();
|
||||
let dock = views.panels.files.unwrap().0;
|
||||
let before = views.panels.diff.as_ref().unwrap().regions[1].0;
|
||||
assert_eq!(dock.y, before.y);
|
||||
assert_eq!(dock.y, 1);
|
||||
assert_eq!(dock.right(), width);
|
||||
for x in 0..width {
|
||||
assert_eq!(terminal.backend().buffer()[(x, 0)].bg, Color::Cyan);
|
||||
for chrome in [false, true] {
|
||||
let mut editor = readonly_diff_editor(deletion_file());
|
||||
if chrome {
|
||||
editor.set_label("battery".into(), "live".into()).unwrap();
|
||||
}
|
||||
let mut views = BufferViewports::default();
|
||||
let mut terminal =
|
||||
Terminal::new(ratatui::backend::TestBackend::new(width, height)).unwrap();
|
||||
terminal
|
||||
.draw(|frame| views.draw(frame, &mut editor))
|
||||
.unwrap();
|
||||
let dock = views.panels.files.unwrap().0;
|
||||
let workspace = views.rects[0].1;
|
||||
let regions = views.panels.diff.as_ref().unwrap().regions;
|
||||
assert_eq!(dock.y, workspace.y);
|
||||
assert_eq!(dock.right(), width);
|
||||
assert_eq!(dock.bottom(), workspace.bottom());
|
||||
for (pane, _) in regions.into_iter().skip(1) {
|
||||
assert_eq!(pane.y, workspace.y);
|
||||
assert_eq!(pane.bottom(), workspace.bottom());
|
||||
assert_eq!(pane.y, u16::from(chrome));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user