From c05e6fd9e206c7c8112e2e4b0e88646964227a43 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Tue, 29 May 2018 19:35:35 +0200 Subject: [PATCH 1/3] Simple tab completion cycling --- src/editor.rs | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/editor.rs b/src/editor.rs index f5c297f..4a1d18e 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -76,8 +76,8 @@ pub struct Editor<'a, W: Write> { // If the cursor is on the line below the prompt, `term_cursor_line == 2`. term_cursor_line: usize, - // If this is true, on the next tab we print the completion list. - show_completions_hint: bool, + // The next completion to suggest, or none + show_completions_hint: Option<(Vec, usize)>, // Show autosuggestions based on history show_autosuggestions: bool, @@ -123,7 +123,7 @@ impl<'a, W: Write> Editor<'a, W> { new_buf: buffer.into(), cur_history_loc: None, context: context, - show_completions_hint: false, + show_completions_hint: None, show_autosuggestions: true, term_cursor_line: 1, no_eol: false, @@ -163,6 +163,11 @@ impl<'a, W: Write> Editor<'a, W> { // XXX: Returning a bool to indicate doneness is a bit awkward, maybe change it pub fn handle_newline(&mut self) -> io::Result { + if self.show_completions_hint.is_some() { + self.show_completions_hint = None; + return Ok(false); + } + let char_before_cursor = cur_buf!(self).char_before(self.cursor); if char_before_cursor == Some('\\') { // self.insert_after_cursor('\r')?; @@ -172,7 +177,7 @@ impl<'a, W: Write> Editor<'a, W> { self.cursor = cur_buf!(self).num_chars(); self._display(false)?; try!(self.out.write(b"\r\n")); - self.show_completions_hint = false; + self.show_completions_hint = None; Ok(true) } } @@ -246,12 +251,21 @@ impl<'a, W: Write> Editor<'a, W> { } pub fn skip_completions_hint(&mut self) { - self.show_completions_hint = false; + self.show_completions_hint = None; } pub fn complete(&mut self, handler: &mut EventHandler) -> io::Result<()> { handler(Event::new(self, EventKind::BeforeComplete)); + if let Some((completions, i)) = self.show_completions_hint.take() { + try!(self.delete_word_before_cursor(false)); + let ret = self.insert_str_after_cursor(&completions[i]); + + let i = (i+1) % completions.len(); + self.show_completions_hint = Some((completions, i)); + return ret; + } + let (word, completions) = { let word_range = self.get_word_before_cursor(false); let buf = cur_buf_mut!(self); @@ -273,10 +287,10 @@ impl<'a, W: Write> Editor<'a, W> { if completions.len() == 0 { // Do nothing. - self.show_completions_hint = false; + self.show_completions_hint = None; Ok(()) } else if completions.len() == 1 { - self.show_completions_hint = false; + self.show_completions_hint = None; try!(self.delete_word_before_cursor(false)); self.insert_str_after_cursor(completions[0].as_ref()) } else { @@ -296,16 +310,12 @@ impl<'a, W: Write> Editor<'a, W> { } } - if self.show_completions_hint { - try!(write!(self.out, "\r\n")); - try!(self.print_completion_list(&completions[..])); - try!(write!(self.out, "\r\n")); - try!(self.display()); + try!(write!(self.out, "\r\n")); + try!(self.print_completion_list(&completions[..])); + try!(write!(self.out, "\r\n")); + try!(self.display()); - self.show_completions_hint = false; - } else { - self.show_completions_hint = true; - } + self.show_completions_hint = Some((completions, 0)); Ok(()) } } From f02426cb644d2f858ff9fdd4a35acb3c228aa61a Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Tue, 29 May 2018 21:10:47 +0200 Subject: [PATCH 2/3] Make cool highlighting thing ooo --- src/editor.rs | 58 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/src/editor.rs b/src/editor.rs index 4a1d18e..74c41bc 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -77,7 +77,7 @@ pub struct Editor<'a, W: Write> { term_cursor_line: usize, // The next completion to suggest, or none - show_completions_hint: Option<(Vec, usize)>, + show_completions_hint: Option<(Vec, Option)>, // Show autosuggestions based on history show_autosuggestions: bool, @@ -220,7 +220,7 @@ impl<'a, W: Write> Editor<'a, W> { Ok(did) } - fn print_completion_list(&mut self, completions: &[String]) -> io::Result<()> { + fn print_completion_list(out: &mut W, completions: &[String], highlighted: Option) -> io::Result { use std::cmp::max; let (w, _) = try!(termion::terminal_size()); @@ -231,23 +231,30 @@ impl<'a, W: Write> Editor<'a, W> { let col_width = 2 + w as usize / cols; let cols = max(1, w as usize / col_width); + let mut lines = 0; + let mut i = 0; - for com in completions { + for (index, com) in completions.iter().enumerate() { if i == cols { - try!(write!(self.out, "\r\n")); + try!(write!(out, "\r\n")); + lines += 1; i = 0; } else if i > cols { unreachable!() } - try!(write!(self.out, "{:<1$}", com, col_width)); + if Some(index) == highlighted { + try!(write!(out, "{}{}", color::Fg(color::Black), color::Bg(color::White))); + } + try!(write!(out, "{:<1$}", com, col_width)); + if Some(index) == highlighted { + try!(write!(out, "{}{}", color::Bg(color::Reset), color::Fg(color::Reset))); + } i += 1; } - self.term_cursor_line = 1; - - Ok(()) + Ok(lines) } pub fn skip_completions_hint(&mut self) { @@ -258,12 +265,16 @@ impl<'a, W: Write> Editor<'a, W> { handler(Event::new(self, EventKind::BeforeComplete)); if let Some((completions, i)) = self.show_completions_hint.take() { + let i = i.map_or(0, |i| (i+1) % completions.len()); + try!(self.delete_word_before_cursor(false)); - let ret = self.insert_str_after_cursor(&completions[i]); + try!(self.insert_str_after_cursor(&completions[i])); - let i = (i+1) % completions.len(); - self.show_completions_hint = Some((completions, i)); - return ret; + self.show_completions_hint = Some((completions, Some(i))); + } + if self.show_completions_hint.is_some() { + try!(self.display()); + return Ok(()); } let (word, completions) = { @@ -310,12 +321,9 @@ impl<'a, W: Write> Editor<'a, W> { } } - try!(write!(self.out, "\r\n")); - try!(self.print_completion_list(&completions[..])); - try!(write!(self.out, "\r\n")); + self.show_completions_hint = Some((completions, None)); try!(self.display()); - self.show_completions_hint = Some((completions, 0)); Ok(()) } } @@ -635,6 +643,7 @@ impl<'a, W: Write> Editor<'a, W> { let w = w as usize; let prompt_width = util::width(&self.prompt); + let buf = cur_buf!(self); let buf_width = buf.width(); @@ -666,7 +675,7 @@ impl<'a, W: Write> Editor<'a, W> { let new_total_width = calc_width(prompt_width, buf_widths, w); let new_total_width_to_cursor = calc_width(prompt_width, buf_widths_to_cursor, w); - let new_num_lines = (new_total_width + w) / w; + let mut new_num_lines = (new_total_width + w) / w; // Move the term cursor to the same line as the prompt. if self.term_cursor_line > 1 { @@ -676,8 +685,18 @@ impl<'a, W: Write> Editor<'a, W> { cursor::Up(self.term_cursor_line as u16 - 1) )); } - // Move the cursor to the start of the line then clear everything after. Write the prompt - try!(write!(self.out, "\r{}{}", clear::AfterCursor, self.prompt)); + // Move the cursor to the start of the line then clear everything after. + try!(write!(self.out, "\r{}", clear::AfterCursor)); + + // If we're cycling through completions, show those + let mut completion_lines = 0; + if let Some((completions, i)) = self.show_completions_hint.as_ref() { + completion_lines = 2 + try!(Self::print_completion_list(&mut self.out, completions, *i)); + try!(write!(self.out, "\r\n")); + } + + // Write the prompt + try!(write!(self.out, "{}", self.prompt)); // If we have an autosuggestion, we make the autosuggestion the buffer we print out. // We get the number of bytes in the buffer (but NOT the autosuggestion). @@ -749,6 +768,7 @@ impl<'a, W: Write> Editor<'a, W> { )); } + self.term_cursor_line = completion_lines; self.out.flush() } From c94ca6610545f5b2010a2ffa9346161023366548 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Fri, 8 Jun 2018 20:22:38 +0200 Subject: [PATCH 3/3] Fix prompt issue with really long inputs --- src/editor.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/editor.rs b/src/editor.rs index 74c41bc..eaed6f9 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -675,7 +675,7 @@ impl<'a, W: Write> Editor<'a, W> { let new_total_width = calc_width(prompt_width, buf_widths, w); let new_total_width_to_cursor = calc_width(prompt_width, buf_widths_to_cursor, w); - let mut new_num_lines = (new_total_width + w) / w; + let new_num_lines = (new_total_width + w) / w; // Move the term cursor to the same line as the prompt. if self.term_cursor_line > 1 { @@ -691,7 +691,7 @@ impl<'a, W: Write> Editor<'a, W> { // If we're cycling through completions, show those let mut completion_lines = 0; if let Some((completions, i)) = self.show_completions_hint.as_ref() { - completion_lines = 2 + try!(Self::print_completion_list(&mut self.out, completions, *i)); + completion_lines = 1 + try!(Self::print_completion_list(&mut self.out, completions, *i)); try!(write!(self.out, "\r\n")); } @@ -768,7 +768,8 @@ impl<'a, W: Write> Editor<'a, W> { )); } - self.term_cursor_line = completion_lines; + self.term_cursor_line += completion_lines; + self.out.flush() }