diff options
| author | Rose Hogenson <rosehogenson@posteo.net> | 2024-01-06 11:14:24 -0800 |
|---|---|---|
| committer | Rose Hogenson <rosehogenson@posteo.net> | 2024-01-06 11:14:24 -0800 |
| commit | b5f471c6a5c517605aa0c53738d4e916579ede78 (patch) | |
| tree | e227878c26fb2423aebe89ee7653e7aa859e9f93 /src/main.rs | |
| parent | dbb1ba202bb5803af1b580b588e7aeef0c6f7e31 (diff) | |
| download | editor-b5f471c6a5c517605aa0c53738d4e916579ede78.tar.zst | |
Use more idiomatic error handling.
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 141 |
1 files changed, 50 insertions, 91 deletions
diff --git a/src/main.rs b/src/main.rs index 599ed36..a427d27 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ mod term; use rope::Rope; use std::ffi::{OsStr, OsString}; use std::io::{stdout, stdin, Write, Read}; +use std::error::Error; use std::path::Path; use term::Key; @@ -15,77 +16,56 @@ struct State { line_cols: usize, } -impl State { - fn cursor_pos(&mut self) -> Result<(usize, usize), String> { - if let Err(err) = write!(stdout(), "\x1b[6n") { - return Err(format!("cursor position: status report: {}", err)); - } - if let Err(err) = stdout().flush() { - return Err(format!("cursor position: status report: {}", err)); +fn parse_status_report(buf: &[u8]) -> Result<(usize, usize), Box<dyn Error>> { + let mut semicolon = 0; + for (i, &c) in buf.iter().enumerate() { + if c == b';' { + semicolon = i; + break; } + } + if semicolon < 2 || semicolon == buf.len()-1 { + return Err(Box::from("invalid response")); + } + let row_str = std::str::from_utf8(&buf[2..semicolon])?; + let col_str = std::str::from_utf8(&buf[semicolon+1..buf.len()-1])?; + let row = row_str.parse::<usize>()?; + let col = col_str.parse::<usize>()?; + // Yuck... 1 indexing + return Ok((row-1, col-1)); +} + +impl State { + fn cursor_pos(&mut self) -> Result<(usize, usize), Box<dyn Error>> { + write!(stdout(), "\x1b[6n").map_err(|err| format!("cursor position: status report: {}", err))?; + stdout().flush().map_err(|err| format!("cursor position: status report: {}", err))?; let mut buf = vec![0; 20]; - let n = match stdin().read(&mut buf) { - Ok(n) => n, - Err(err) => { - return Err(format!("cursor position: read status report: {}", err)); - } - }; + let n = stdin().read(&mut buf).map_err(|err| format!("cursor position: read status report: {}", err))?; buf.truncate(n); - let mut semicolon = 0; - for (i, &c) in buf.iter().enumerate() { - if c == b';' { - semicolon = i; - break; - } - } - let row_str = match std::str::from_utf8(&buf[2..semicolon]) { - Ok(row_str) => row_str, - Err(_) => { - return Err(format!("cursor position: invalid response {}", String::from_utf8_lossy(&buf))); - } - }; - let col_str = match std::str::from_utf8(&buf[semicolon+1..buf.len()-1]) { - Ok(col_str) => col_str, - Err(_) => { - return Err(format!("cursor position: invalid response {}", String::from_utf8_lossy(&buf))); - } - }; - let row = match row_str.parse::<usize>() { - Ok(row) => row, - Err(_) => { - return Err(format!("cursor position: invalid response {}", String::from_utf8_lossy(&buf))); - } - }; - let col = match col_str.parse::<usize>() { - Ok(col) => col, - Err(_) => { - return Err(format!("cursor position: invalid response {}", String::from_utf8_lossy(&buf))); - } - }; - // Yuck... 1 indexing - return Ok((row-1, col-1)); + let pos = parse_status_report(&buf).map_err(|_| format!("cursor position: invalid response: {}", String::from_utf8_lossy(&buf)))?; + return Ok(pos); } - fn repaint_line_full(&mut self) { - let _ = write!(stdout(), "\x1b[{}H", self.cursor_row+1); + fn repaint_line_full(&mut self) -> Result<(), Box<dyn Error>> { + write!(stdout(), "\x1b[{}H", self.cursor_row+1)?; let line = self.buf.line(self.cursor_row); - let _ = line.print(&mut stdout()); - let (_, col) = self.cursor_pos().expect("asdf"); + line.print(&mut stdout())?; + let (_, col) = self.cursor_pos()?; self.line_cols = col; if self.cursor_col >= self.line_cols { self.line_offset = line.len(); - return; + return Ok(()); } - let mut lo = line.char(self.cursor_col).expect("at this point, cursor_col should have some valid offset"); + let mut lo = line.ceil_char_boundary(self.cursor_col); let mut hi = line.len(); // Binary search :D while hi > lo { let x = line.floor_char_boundary(lo + (hi - lo) / 2); - let _ = write!(stdout(), "\x1b[G"); - let _ = line.slice(0, x).print(&mut stdout()); - let (_, col) = self.cursor_pos().expect("ouchie, I should really handle this I guess"); + write!(stdout(), "\x1b[G")?; + line.slice(0, x).print(&mut stdout())?; + let (_, col) = self.cursor_pos()?; if col <= self.cursor_col { lo = line.ceil_char_boundary(x+1); } else { @@ -93,32 +73,18 @@ impl State { } } self.line_offset = line.floor_char_boundary(lo-1); - let _ = write!(stdout(), "\x1b[G\x1b[K"); - let _ = line.print(&mut stdout()); - let _ = write!(stdout(), "\x1b[{}G", self.cursor_col+1); + write!(stdout(), "\x1b[G\x1b[K")?; + line.print(&mut stdout())?; + write!(stdout(), "\x1b[{}G", self.cursor_col+1)?; + return Ok(()); } } -fn edit(file: &OsStr) -> Result<(), String> { - let _raw_handle = match term::raw() { - Some(h) => h, - None => { - return Err(String::from("cannot put terminal in raw mode")); - } - }; +fn edit(file: &OsStr) -> Result<(), Box<dyn Error>> { + let _raw_handle = term::raw().map_err(|err| format!("cannot put terminal in raw mode: {}", err))?; - let r = match Rope::open(Path::new(file)) { - Ok(r) => r, - Err(err) => { - return Err(format!("open file {}: {}", file.to_string_lossy(), err)); - } - }; - let size = match term::size() { - Some(size) => size, - None => { - return Err(String::from("cannot get terminal size")); - } - }; + let r = Rope::open(Path::new(file))?; + let size = term::size()?; let mut state = State{ buf: r, cursor_row: 0, @@ -146,20 +112,13 @@ fn edit(file: &OsStr) -> Result<(), String> { let _ = stdout().flush(); loop { - let c = match term::read_key(&mut stdin()) { - Ok(c) => c, - Err(err) => { - return Err(err); - } - }; + let c = term::read_key(&mut stdin()).map_err(|err| format!("read key: {}", err))?; match c { Key::CtrlQ => { break; } Key::CtrlS => { - if let Err(err) = state.buf.save(Path::new(file)) { - return Err(format!("write file {}: {}", file.to_string_lossy(), err)); - } + let _ = state.buf.save(Path::new(file)); } Key::Up => { if state.cursor_row == 0 { @@ -167,7 +126,7 @@ fn edit(file: &OsStr) -> Result<(), String> { } state.cursor_row -= 1; - state.repaint_line_full(); + let _ = state.repaint_line_full(); let _ = stdout().flush(); } Key::Down => { @@ -176,7 +135,7 @@ fn edit(file: &OsStr) -> Result<(), String> { } state.cursor_row += 1; - state.repaint_line_full(); + let _ = state.repaint_line_full(); let _ = stdout().flush(); } Key::Left => { @@ -185,7 +144,7 @@ fn edit(file: &OsStr) -> Result<(), String> { continue; } state.cursor_col -= 1; - state.repaint_line_full(); + let _ = state.repaint_line_full(); let _ = stdout().flush(); } Key::Right => { @@ -193,14 +152,14 @@ fn edit(file: &OsStr) -> Result<(), String> { continue; } state.cursor_col += 1; - state.repaint_line_full(); + let _ = state.repaint_line_full(); let _ = stdout().flush(); } Key::Char(c) => { state.cursor_col = std::cmp::min(state.cursor_col, state.line_cols); state.buf = state.buf.insert(state.buf.line_idx(state.cursor_row)+state.line_offset, c); state.cursor_col += 1; - state.repaint_line_full(); + let _ = state.repaint_line_full(); let _ = stdout().flush(); } } |
