@@ -33,6 +33,8 @@ pub struct Menu<T: Item> {
34 scroll: usize,
34 scroll: usize,
35 size: (u16, u16),
35 size: (u16, u16),
36+ viewport: (u16, u16),
38impl<T: Item> Menu<T> {
40impl<T: Item> Menu<T> {
@@ -51,6 +53,8 @@ impl<T: Item> Menu<T> {
51 callback_fn: Box::new(callback_fn),
53 callback_fn: Box::new(callback_fn),
52 scroll: 0,
54 scroll: 0,
53 size: (0, 0),
55 size: (0, 0),
56 // TODO: scoring on empty input should just use a fastpath
60 // TODO: scoring on empty input should just use a fastpath
@@ -83,6 +87,7 @@ impl<T: Item> Menu<T> {
83 // reset cursor position
87 // reset cursor position
84 self.cursor = None;
88 self.cursor = None;
85 self.scroll = 0;
89 self.scroll = 0;
90+ self.recalculate = true;
88 pub fn move_up(&mut self) {
93 pub fn move_up(&mut self) {
@@ -99,6 +104,41 @@ impl<T: Item> Menu<T> {
99 self.adjust_scroll();
104 self.adjust_scroll();
107+ fn recalculate_size(&mut self, viewport: (u16, u16)) {
111+ .map(|option| option.row().cells.len())
112+ .unwrap_or_default();
113+ let max_lens = self.options.iter().fold(vec![0; n], |mut acc, option| {
114+ let row = option.row();
115+ // maintain max for each column
116+ for (acc, cell) in acc.iter_mut().zip(row.cells.iter()) {
117+ let width = cell.content.width();
125+ let len = max_lens.iter().sum::<usize>() + n + 1; // +1: reserve some space for scrollbar
126+ let width = len.min(viewport.0 as usize);
128+ self.widths = max_lens
130+ .map(|len| Constraint::Length(len as u16))
133+ let height = self.matches.len().min(10).min(viewport.1 as usize);
135+ self.size = (width as u16, height as u16);
137+ // adjust scroll offsets if size changed
138+ self.adjust_scroll();
139+ self.recalculate = false;
102 fn adjust_scroll(&mut self) {
142 fn adjust_scroll(&mut self) {
103 let win_height = self.size.1 as usize;
143 let win_height = self.size.1 as usize;
104 if let Some(cursor) = self.cursor {
144 if let Some(cursor) = self.cursor {
@@ -221,43 +261,13 @@ impl<T: Item + 'static> Component for Menu<T> {
223 fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
263 fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
224− let n = self
264+ if viewport != self.viewport || self.recalculate {
225− .options
265+ self.recalculate_size(viewport);
227− .map(|option| option.row().cells.len())
228− .unwrap_or_default();
229− let max_lens = self.options.iter().fold(vec![0; n], |mut acc, option| {
230− let row = option.row();
231− // maintain max for each column
232− for (acc, cell) in acc.iter_mut().zip(row.cells.iter()) {
233− let width = cell.content.width();
241− let len = max_lens.iter().sum::<usize>() + n + 1; // +1: reserve some space for scrollbar
242− let width = len.min(viewport.0 as usize);
244− self.widths = max_lens
246− .map(|len| Constraint::Length(len as u16))
249− let height = self.options.len().min(10).min(viewport.1 as usize);
251− self.size = (width as u16, height as u16);
253− // adjust scroll offsets if size changed
254− self.adjust_scroll();
256 Some(self.size)
268 Some(self.size)
259− // TODO: required size should re-trigger when we filter items so we can draw a smaller menu
261 fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
271 fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
262 let theme = &cx.editor.theme;
272 let theme = &cx.editor.theme;
263 let style = theme
273 let style = theme