feat: align buffer picker with editor UI
This commit is contained in:
+127
-31
@@ -4357,35 +4357,49 @@ fn draw_palette(
|
||||
if area.width == 0 || area.height == 0 {
|
||||
return;
|
||||
}
|
||||
let [_, column, _] = Layout::horizontal([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(area.width.min(100)),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(area);
|
||||
let [_, panel, _] = Layout::vertical([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(area.height.min(16)),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(column);
|
||||
let panel = if palette.buffers {
|
||||
floating_panel(area)
|
||||
} else {
|
||||
let [_, column, _] = Layout::horizontal([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(area.width.min(100)),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(area);
|
||||
let [_, panel, _] = Layout::vertical([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(area.height.min(16)),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(column);
|
||||
panel
|
||||
};
|
||||
frame.render_widget(Clear, panel);
|
||||
let bordered = panel.height >= 4 && panel.width >= 4;
|
||||
let padding =
|
||||
u16::from(palette.buffers && panel.width.saturating_sub(2 * u16::from(bordered)) >= 3);
|
||||
let block = Block::default()
|
||||
.borders(if bordered {
|
||||
Borders::ALL
|
||||
} else {
|
||||
Borders::NONE
|
||||
})
|
||||
.title(format!(
|
||||
" {} · {mode} ",
|
||||
if palette.buffers {
|
||||
"Buffers"
|
||||
} else {
|
||||
"Commands"
|
||||
}
|
||||
));
|
||||
let content = if bordered { block.inner(panel) } else { panel };
|
||||
.border_style(if palette.buffers {
|
||||
Style::default().fg(Color::Cyan)
|
||||
} else {
|
||||
Style::default()
|
||||
})
|
||||
.padding(ratatui::widgets::Padding::horizontal(padding))
|
||||
.title(if palette.buffers {
|
||||
" Buffers ".into()
|
||||
} else {
|
||||
format!(" Commands · {mode} ")
|
||||
});
|
||||
let content = if bordered {
|
||||
block.inner(panel)
|
||||
} else {
|
||||
panel.inner(ratatui::layout::Margin::new(padding, 0))
|
||||
};
|
||||
if bordered {
|
||||
frame.render_widget(block, panel);
|
||||
}
|
||||
@@ -4398,7 +4412,7 @@ fn draw_palette(
|
||||
let query = format!("> {}", palette.query);
|
||||
let query_width = display_column(&query, usize::MAX);
|
||||
let width = usize::from(query_area.width);
|
||||
let offset = query_width.saturating_sub(width - 1);
|
||||
let offset = query_width.saturating_sub(width.saturating_sub(1));
|
||||
frame.render_widget(
|
||||
Paragraph::new(visible_line(&query, offset, width))
|
||||
.style(Style::default().fg(Color::Yellow)),
|
||||
@@ -4422,6 +4436,11 @@ fn draw_palette(
|
||||
};
|
||||
let count = usize::from(results_area.height) / row_height;
|
||||
let first = palette.selected.saturating_sub(count - 1);
|
||||
let id_width = palette
|
||||
.entries
|
||||
.last()
|
||||
.and_then(|entry| entry.buffer.as_ref())
|
||||
.map_or(1, |buffer| buffer.id.ilog10() as usize + 1);
|
||||
let mut lines = Vec::with_capacity(count * row_height);
|
||||
for (index, entry) in palette.entries.iter().enumerate().skip(first).take(count) {
|
||||
let mut style = Style::default();
|
||||
@@ -4431,13 +4450,28 @@ fn draw_palette(
|
||||
if index == palette.selected {
|
||||
style = style.bg(Color::Blue).add_modifier(Modifier::BOLD);
|
||||
}
|
||||
if palette.buffers {
|
||||
if let Some(buffer) = &entry.buffer {
|
||||
lines.push(
|
||||
Line::from(format!(
|
||||
"{} {}",
|
||||
if index == palette.selected { ">" } else { " " },
|
||||
entry.label,
|
||||
))
|
||||
Line::from(vec![
|
||||
Span::raw(if index == palette.selected {
|
||||
"> "
|
||||
} else {
|
||||
" "
|
||||
}),
|
||||
Span::styled(
|
||||
format!("{:>id_width$} ", buffer.id),
|
||||
Style::default().fg(Color::DarkGray),
|
||||
),
|
||||
Span::styled(
|
||||
if buffer.active { "%" } else { " " },
|
||||
Style::default().fg(Color::Cyan),
|
||||
),
|
||||
Span::styled(
|
||||
if buffer.dirty { "+ " } else { " " },
|
||||
Style::default().fg(Color::Yellow),
|
||||
),
|
||||
Span::raw(&entry.label),
|
||||
])
|
||||
.style(style),
|
||||
);
|
||||
continue;
|
||||
@@ -4470,9 +4504,16 @@ fn draw_palette(
|
||||
frame.render_widget(Paragraph::new(lines), results_area);
|
||||
}
|
||||
frame.render_widget(
|
||||
Paragraph::new(format!(
|
||||
"{mode} · {navigation_hint} · Enter accept · Esc/Ctrl+p cancel"
|
||||
)),
|
||||
Paragraph::new(if palette.buffers {
|
||||
format!("{navigation_hint} · Enter open · Esc/^P cancel · ^U clear")
|
||||
} else {
|
||||
format!("{mode} · {navigation_hint} · Enter accept · Esc/Ctrl+p cancel")
|
||||
})
|
||||
.style(if palette.buffers {
|
||||
Style::default().fg(Color::DarkGray)
|
||||
} else {
|
||||
Style::default()
|
||||
}),
|
||||
help_area,
|
||||
);
|
||||
}
|
||||
@@ -14419,6 +14460,61 @@ end
|
||||
assert_eq!(editor.mode(), Mode::Insert);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_picker_keeps_selected_status_and_paths_visible_after_resize_and_filter() {
|
||||
let mut editor = Editor::open(None, vec![]).unwrap();
|
||||
for id in 2..=12 {
|
||||
editor.execute(&format!("edit picker-{id}.txt"));
|
||||
}
|
||||
editor
|
||||
.apply(vec![crate::editor::Effect::Replace("unsaved".into())])
|
||||
.unwrap();
|
||||
editor.execute("buffers");
|
||||
editor.handle(Input::Ctrl('k'));
|
||||
for (width, height) in [(80, 12), (32, 6), (1, 1), (4, 4), (80, 12)] {
|
||||
let area = Rect::new(3, 2, width, height);
|
||||
let mut terminal = Terminal::with_options(
|
||||
ratatui::backend::TestBackend::new(90, 30),
|
||||
ratatui::TerminalOptions {
|
||||
viewport: ratatui::Viewport::Fixed(area),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
terminal
|
||||
.draw(|frame| {
|
||||
draw_palette(
|
||||
frame,
|
||||
editor.palette().unwrap(),
|
||||
area,
|
||||
editor.mode(),
|
||||
editor.selection_navigation_hint(),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
assert!(area.contains(terminal.get_cursor_position().unwrap()));
|
||||
if width >= 32 {
|
||||
let buffer = terminal.backend().buffer();
|
||||
let selected_y = (area.y..area.bottom())
|
||||
.find(|&y| buffer[(area.x + 7, y)].symbol() == "%")
|
||||
.unwrap();
|
||||
assert_eq!(buffer[(area.x + 7, selected_y)].fg, Color::Cyan);
|
||||
assert_eq!(buffer[(area.x + 8, selected_y)].symbol(), "+");
|
||||
assert_eq!(buffer[(area.x + 8, selected_y)].fg, Color::Yellow);
|
||||
assert_eq!(buffer[(area.x + 10, selected_y)].bg, Color::Blue);
|
||||
assert!(
|
||||
pane_screen(&terminal, Rect::new(area.x, selected_y, width, 1))
|
||||
.contains("picker-12.txt")
|
||||
);
|
||||
}
|
||||
}
|
||||
editor.handle(Input::Char('2'));
|
||||
editor.handle(Input::Ctrl('j'));
|
||||
editor.handle(Input::Enter);
|
||||
assert_eq!(editor.buffer_id(), 12);
|
||||
assert_eq!(editor.context().text, "unsaved");
|
||||
assert!(editor.dirty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn palette_query_scrolls_graphemes_tabs_and_wide_cells_on_tiny_offset_areas() {
|
||||
let editor = Editor::open(None, vec![]).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user