Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 56 additions & 25 deletions src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>, Option<usize>)>,

// Show autosuggestions based on history
show_autosuggestions: bool,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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<bool> {
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')?;
Expand All @@ -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)
}
}
Expand Down Expand Up @@ -215,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<usize>) -> io::Result<usize> {
use std::cmp::max;

let (w, _) = try!(termion::terminal_size());
Expand All @@ -226,32 +231,52 @@ 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) {
self.show_completions_hint = false;
self.show_completions_hint = None;
}

pub fn complete(&mut self, handler: &mut EventHandler<W>) -> io::Result<()> {
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));
try!(self.insert_str_after_cursor(&completions[i]));

self.show_completions_hint = Some((completions, Some(i)));
}
if self.show_completions_hint.is_some() {
try!(self.display());
return Ok(());
}

let (word, completions) = {
let word_range = self.get_word_before_cursor(false);
let buf = cur_buf_mut!(self);
Expand All @@ -273,10 +298,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 {
Expand All @@ -296,16 +321,9 @@ 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());
self.show_completions_hint = Some((completions, None));
try!(self.display());

self.show_completions_hint = false;
} else {
self.show_completions_hint = true;
}
Ok(())
}
}
Expand Down Expand Up @@ -625,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();

Expand Down Expand Up @@ -666,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 = 1 + 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).
Expand Down Expand Up @@ -739,6 +768,8 @@ impl<'a, W: Write> Editor<'a, W> {
));
}

self.term_cursor_line += completion_lines;

self.out.flush()
}

Expand Down