Calculate completion popup sizing

Fixes #220
pull/469/head
Blaž Hrastnik 3 years ago
parent bf43fabf65
commit 5292fe0f7d

@ -8,6 +8,7 @@ use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
use fuzzy_matcher::FuzzyMatcher; use fuzzy_matcher::FuzzyMatcher;
use helix_view::{graphics::Rect, Editor}; use helix_view::{graphics::Rect, Editor};
use tui::layout::Constraint;
pub trait Item { pub trait Item {
// TODO: sort_text // TODO: sort_text
@ -26,6 +27,8 @@ pub struct Menu<T: Item> {
/// (index, score) /// (index, score)
matches: Vec<(usize, i64)>, matches: Vec<(usize, i64)>,
widths: Vec<Constraint>,
callback_fn: Box<dyn Fn(&mut Editor, Option<&T>, MenuEvent)>, callback_fn: Box<dyn Fn(&mut Editor, Option<&T>, MenuEvent)>,
scroll: usize, scroll: usize,
@ -44,6 +47,7 @@ impl<T: Item> Menu<T> {
matcher: Box::new(Matcher::default()), matcher: Box::new(Matcher::default()),
matches: Vec::new(), matches: Vec::new(),
cursor: None, cursor: None,
widths: Vec::new(),
callback_fn: Box::new(callback_fn), callback_fn: Box::new(callback_fn),
scroll: 0, scroll: 0,
size: (0, 0), size: (0, 0),
@ -218,8 +222,33 @@ impl<T: Item + 'static> Component for Menu<T> {
EventResult::Ignored EventResult::Ignored
} }
// TODO: completion sorting
fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> { fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
let width = std::cmp::min(30, viewport.0); let n = self
.options
.first()
.map(|option| option.row().cells.len())
.unwrap_or_default();
let max_lens = self.options.iter().fold(vec![0; n], |mut acc, option| {
let row = option.row();
// maintain max for each column
for (i, cell) in row.cells.iter().enumerate() {
let width = cell.content.width();
if width > acc[i] {
acc[i] = width;
}
}
acc
});
let len = (max_lens.iter().sum::<usize>()) + n + 1; // +1: reserve some space for scrollbar
let width = len.min(viewport.0 as usize);
self.widths = max_lens
.into_iter()
.map(|len| Constraint::Length(len as u16))
.collect();
const MAX: usize = 10; const MAX: usize = 10;
let height = std::cmp::min(self.options.len(), MAX); let height = std::cmp::min(self.options.len(), MAX);
@ -263,13 +292,12 @@ impl<T: Item + 'static> Component for Menu<T> {
let scroll_line = (win_height - scroll_height) * scroll let scroll_line = (win_height - scroll_height) * scroll
/ std::cmp::max(1, len.saturating_sub(win_height)); / std::cmp::max(1, len.saturating_sub(win_height));
use tui::layout::Constraint;
let rows = options.iter().map(|option| option.row()); let rows = options.iter().map(|option| option.row());
let table = Table::new(rows) let table = Table::new(rows)
.style(style) .style(style)
.highlight_style(selected) .highlight_style(selected)
.column_spacing(1) .column_spacing(1)
.widths(&[Constraint::Percentage(50), Constraint::Percentage(50)]); .widths(&self.widths);
use tui::widgets::TableState; use tui::widgets::TableState;

@ -36,7 +36,7 @@ use std::collections::HashMap;
/// capabilities of [`Text`]. /// capabilities of [`Text`].
#[derive(Debug, Clone, PartialEq, Default)] #[derive(Debug, Clone, PartialEq, Default)]
pub struct Cell<'a> { pub struct Cell<'a> {
content: Text<'a>, pub content: Text<'a>,
style: Style, style: Style,
} }
@ -81,7 +81,7 @@ where
/// By default, a row has a height of 1 but you can change this using [`Row::height`]. /// By default, a row has a height of 1 but you can change this using [`Row::height`].
#[derive(Debug, Clone, PartialEq, Default)] #[derive(Debug, Clone, PartialEq, Default)]
pub struct Row<'a> { pub struct Row<'a> {
cells: Vec<Cell<'a>>, pub cells: Vec<Cell<'a>>,
height: u16, height: u16,
style: Style, style: Style,
bottom_margin: u16, bottom_margin: u16,

Loading…
Cancel
Save