Commit 98981ecd authored by Liam Naddell's avatar Liam Naddell

Add upstream fork commits except 1

parent bb84002c
......@@ -20,6 +20,6 @@ name = "liner_test"
path = "src/main.rs"
[dependencies]
bytecount = "0.1"
bytecount = "0.3.1"
termion = "1.4.0"
unicode-width = "0.1.*"
......@@ -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,
......@@ -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<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')?;
......@@ -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)
}
}
......@@ -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());
......@@ -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);
......@@ -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 {
......@@ -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(())
}
}
......@@ -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();
......@@ -656,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 {
......@@ -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 = 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).
......@@ -739,6 +768,7 @@ impl<'a, W: Write> Editor<'a, W> {
));
}
self.term_cursor_line = completion_lines;
self.out.flush()
}
......
......@@ -277,7 +277,7 @@ fn write_to_disk(max_file_size: usize, new_item: &Buffer, file_name: &str) -> io
// Move it all back
move_file_contents_backward(&mut file, move_dist);
move_file_contents_backward(&mut file, move_dist)?;
}
};
......@@ -294,7 +294,7 @@ fn write_to_disk(max_file_size: usize, new_item: &Buffer, file_name: &str) -> io
fn move_file_contents_backward(file: &mut File, distance: u64) -> io::Result<()> {
let mut total_read = 0;
let mut buffer = [0u8, 4096];
let mut buffer = [0u8; 4096];
file.seek(SeekFrom::Start(distance))?;
......@@ -307,15 +307,15 @@ fn move_file_contents_backward(file: &mut File, distance: u64) -> io::Result<()>
break;
}
file.seek(SeekFrom::Current(-(read as i64 + distance as i64)));
file.seek(SeekFrom::Current(-(read as i64 + distance as i64)))?;
file.write_all(&buffer[..read])?;
file.seek(SeekFrom::Current(distance as i64));
file.seek(SeekFrom::Current(distance as i64))?;
}
file.set_len(total_read)?;
file.flush()?;
Ok(())
}
\ No newline at end of file
}
......@@ -908,6 +908,11 @@ impl<'a, W: Write> Vi<'a, W> {
(_, ReverseRepeat, Some((c, RightUntil))) => (Key::Char(c), LeftUntil),
(_, ReverseRepeat, Some((c, LeftAt))) => (Key::Char(c), RightAt),
(_, ReverseRepeat, Some((c, RightAt))) => (Key::Char(c), LeftAt),
// repeat with no last_char_movement, invalid
(_, Repeat, None) | (_, ReverseRepeat, None) => {
self.normal_mode_abort();
return Ok(());
}
// pass valid keys through as is
(Key::Char(c), _, _) => {
// store last command info
......@@ -915,8 +920,7 @@ impl<'a, W: Write> Vi<'a, W> {
self.current_command.push(key);
(key, movement)
}
// all other combinations are invalid, abort. This includes repeats with no
// last_char_movement stored, and non char key presses.
// all other combinations are invalid, abort
_ => {
self.normal_mode_abort();
return Ok(());
......@@ -3716,4 +3720,21 @@ mod tests {
assert_eq!(res.is_ok(), true);
assert_eq!(map.ed.current_buffer().to_string(), "not empt".to_string());
}
#[test]
/// repeat char move with no last char
fn repeat_char_move_no_char() {
let mut context = Context::new();
let out = Vec::new();
let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
let mut map = Vi::new(ed);
map.ed.insert_str_after_cursor("abc defg").unwrap();
simulate_keys!(map, [
Esc,
Char('$'),
Char(';'),
]);
assert_eq!(map.ed.cursor(), 7);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment