@@ -34,6 +34,8 @@ type Terminal = tui::Terminal<CrosstermBackend<std::io::Stdout>>;
3434
3535static EX: smol::Executor = smol::Executor::new();
3636
37+const BASE_WIDTH: u16 = 30;
38+
3739pub struct Application {
3840 editor: Editor,
3941 prompt: Option<Prompt>,
@@ -235,7 +237,52 @@ impl Renderer {
235237 .set_string(1, self.size.1 - 2, mode, self.text_color);
236238 }
237239
238− pub fn render_prompt(&mut self, prompt: &Prompt) {
240+ pub fn render_prompt(&mut self, view: &View, prompt: &Prompt) {
241+ // completion
242+ if !prompt.completion.is_empty() {
243+ // TODO: find out better way of clearing individual lines of the screen
244+ let mut row = 0;
245+ let mut col = 0;
246+ let max_col = self.size.0 / BASE_WIDTH;
247+ let col_height = ((prompt.completion.len() as u16 + max_col - 1) / max_col);
248+
249+ for i in (3..col_height + 3) {
250+ self.surface.set_string(
251+ 0,
252+ self.size.1 - i as u16,
253+ " ".repeat(self.size.0 as usize),
254+ self.text_color,
255+ );
256+ }
257+ self.surface.set_style(
258+ Rect::new(0, self.size.1 - col_height - 2, self.size.0, col_height),
259+ view.theme.get("ui.statusline"),
260+ );
261+ for (i, command) in prompt.completion.iter().enumerate() {
262+ let color = if prompt.completion_selection_index.is_some()
263+ && i == prompt.completion_selection_index.unwrap()
264+ {
265+ Style::default().bg(Color::Rgb(104, 060, 232))
266+ } else {
267+ self.text_color
268+ };
269+ self.surface.set_stringn(
270+ 1 + col * BASE_WIDTH,
271+ self.size.1 - col_height - 2 + row,
272+ &command,
273+ BASE_WIDTH as usize - 1,
274+ color,
275+ );
276+ row += 1;
277+ if row > col_height - 1 {
278+ row = 0;
279+ col += 1;
280+ }
281+ if col > max_col {
282+ break;
283+ }
284+ }
285+ }
239286 // render buffer text
240287 self.surface
241288 .set_string(1, self.size.1 - 1, &prompt.prompt, self.text_color);
@@ -309,10 +356,13 @@ impl Application {
309356
310357 if let Some(view) = &mut self.editor.view {
311358 self.terminal.render_view(view, viewport);
312− }
313−
314− if let Some(prompt) = &self.prompt {
315− self.terminal.render_prompt(prompt);
359+ if let Some(prompt) = &self.prompt {
360+ if prompt.should_close {
361+ self.prompt = None;
362+ } else {
363+ self.terminal.render_prompt(view, prompt);
364+ }
365+ }
316366 }
317367
318368 self.terminal.draw();
@@ -383,7 +433,46 @@ impl Application {
383433 {
384434 let prompt = Prompt::new(
385435 ":".to_owned(),
386− |_input: &str| None, // completion
436+ |_input: &str| {
437+ // TODO: i need this duplicate list right now to avoid borrow checker issues
438+ let command_list = vec![
439+ String::from("q"),
440+ String::from("aaa"),
441+ String::from("bbb"),
442+ String::from("ccc"),
443+ String::from("ddd"),
444+ String::from("eee"),
445+ String::from("averylongcommandaverylongcommandaverylongcommandaverylongcommandaverylongcommand"),
446+ String::from("q"),
447+ String::from("aaa"),
448+ String::from("bbb"),
449+ String::from("ccc"),
450+ String::from("ddd"),
451+ String::from("eee"),
452+ String::from("q"),
453+ String::from("aaa"),
454+ String::from("bbb"),
455+ String::from("ccc"),
456+ String::from("ddd"),
457+ String::from("eee"),
458+ String::from("q"),
459+ String::from("aaa"),
460+ String::from("bbb"),
461+ String::from("ccc"),
462+ String::from("ddd"),
463+ String::from("eee"),
464+ String::from("q"),
465+ String::from("aaa"),
466+ String::from("bbb"),
467+ String::from("ccc"),
468+ String::from("ddd"),
469+ String::from("eee"),
470+ ];
471+ command_list
472+ .into_iter()
473+ .filter(|command| command.contains(_input))
474+ .collect()
475+ }, // completion
387476 |editor: &mut Editor, input: &str| match input {
388477 "q" => editor.should_close = true,
389478 _ => (),