From f955e22c196b95cca46bac71da72477ef96670b1 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Thu, 12 Sep 2019 16:49:49 -0400 Subject: [PATCH] Implement missing function, fix some math issues between cursor_x and render_x --- src/editor.rs | 91 ++++++++++++++++++++++++++++++++--------- src/main.rs | 13 +++--- src/terminal_helpers.rs | 5 +++ 3 files changed, 83 insertions(+), 26 deletions(-) diff --git a/src/editor.rs b/src/editor.rs index c63028b..0390ae6 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -407,14 +407,68 @@ impl Editor { return Some(input[0]); } + fn get_cursor_position(&mut self) -> TermSize { + let mut query = String::new(); + // Move the cursor as far to the bottom right as is practical + query.push_str("\x1b[999C\x1b[999B"); + + // Ask the shell where the cursor is + query.push_str("\x1b[6n"); + + let stdout = io::stdout(); + let mut handle = stdout.lock(); + + // If you can't write to stdout, you might as well just panic + handle.write_all(query.as_bytes()).unwrap(); + + + let stdin = io::stdin(); + let stdin = stdin.lock(); + let mut handle = stdin.take(32); + let mut input = String::new(); + let read_res = handle.read_to_string(&mut input); + clean_unwrap(read_res); + + if input.len() < 6 { + panic!("Invalid or missing response to cursor location query: {:?}", input); + } + + let mut row_str = String::new(); + let mut col_str = String::new(); + + let mut index = 0; + + for ch in input.chars() { + if ch == ';' { + index += 1; + } else if ch == 'R' { + break; + } else { + if index == 0 { + row_str.push(ch) + } else { + col_str.push(ch) + } + } + } + + let rows = clean_unwrap(row_str.parse()); + let cols = clean_unwrap(row_str.parse()); + + return TermSize { + cols, + rows, + } + } + fn get_window_size(&mut self) -> TermSize { match get_term_size() { Some(size) => size, - // I could have implemented this, but I felt that parsing - // an escape code from stdin was of minimal value, - // when the ioctrl method works on any computer I've tried - None => unimplemented!("The easy way usually works"), + None => { + print!("\x1b[999C\x1b[999B"); + return self.get_cursor_position(); + } } } @@ -1062,10 +1116,10 @@ impl Editor { self.draw_message_bar(); // Move cursor to state position - let y = self.cursor_y - self.row_offset + 1; - let x = self.render_x - self.col_offset + 1; - let cursor_code = format!("\x1b[{y};{x}f", y = y, x = x); - self.append_out(&cursor_code); + let y = (self.cursor_y - self.row_offset) + 1; + let x = (self.render_x - self.col_offset) + 1; + let cursor_code = format!("\x1b[{};{}H", y, x); + self.append_out(&cursor_code.as_str()); // Show cursor self.append_out("\x1b[?25h"); @@ -1102,20 +1156,17 @@ impl Editor { fn row_cx_to_rx(&mut self, index: usize, cx: usize) -> usize { let mut rx: usize = 0; - let mut i: usize = 0; - for ch in self.rows[index].chars.chars() { - if ch == '\t' { - rx += (KILO_TAB_STOP - 1) - (rx % KILO_TAB_STOP); - } else { - rx += 1; - } - - if i > cx { + for (i, ch) in self.rows[index].chars.char_indices() { + if i == cx { return rx; } - i += 1; + if ch == '\t' { + rx += (KILO_TAB_STOP - 1) - (rx % KILO_TAB_STOP); + } + + rx += 1; } rx @@ -1128,10 +1179,10 @@ impl Editor { for ch in self.rows[index].chars.chars() { if ch == '\t' { current_rx += (KILO_TAB_STOP - 1) - (current_rx % KILO_TAB_STOP); - } else { - current_rx += 1; } + current_rx += 1; + if current_rx > rx { return cx; } diff --git a/src/main.rs b/src/main.rs index acce25a..0c6ad06 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,12 +45,13 @@ fn main() -> Result<(), Error> { editor.refresh_screen(); match editor.process_keypress() { - Some(_key) => { - /* match key { - editor::EditorKey::OtherKey('\0') => (), - _ => println!("{:?}\r\n", key) - }*/ - () + Some(key) => { + match key { + editor::KeyCode::OtherKey('\0') => (), + + // Just for debugging + _ => () //println!("{:?}\r\n", key) + } } None => break, } diff --git a/src/terminal_helpers.rs b/src/terminal_helpers.rs index 0c0be98..a6eb794 100644 --- a/src/terminal_helpers.rs +++ b/src/terminal_helpers.rs @@ -36,6 +36,11 @@ pub fn get_termios(fd: RawFd) -> Termios { /// Put terminal into raw mode so there is full control of terminal output pub fn enable_raw_mode() { + // 'Access' the saved termios instance, to make sure it is set + // before you enable raw mode. + let mutex = Arc::clone(&super::ORIGINAL_TERMIOS); + mutex.lock().unwrap(); + let mut raw = get_termios(STDIN_FILENO); raw.input_flags.remove(