aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2024-01-06 11:14:24 -0800
committerRose Hogenson <rosehogenson@posteo.net>2024-01-06 11:14:24 -0800
commitb5f471c6a5c517605aa0c53738d4e916579ede78 (patch)
treee227878c26fb2423aebe89ee7653e7aa859e9f93 /src/main.rs
parentdbb1ba202bb5803af1b580b588e7aeef0c6f7e31 (diff)
downloadeditor-b5f471c6a5c517605aa0c53738d4e916579ede78.tar.zst
Use more idiomatic error handling.
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs141
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();
}
}