diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 101 |
1 files changed, 73 insertions, 28 deletions
diff --git a/src/main.rs b/src/main.rs index bf2be55..09eb5b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,14 @@ use anyhow::Result; use crossterm::{ cursor, - event::{self, Event, KeyCode}, + event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, MouseEvent}, queue, style::{Attribute, Print}, terminal, }; use serde::{Deserialize, Serialize}; use std::{ - cmp::min, + cmp::{Ordering, min}, collections::HashMap, env, fs, io::{stdout, Write}, @@ -87,14 +87,15 @@ enum Direction { } trait View { - fn run(&self, bk: &mut Bk, kc: KeyCode); fn render(&self, bk: &Bk) -> Vec<String>; + fn on_key(&self, bk: &mut Bk, kc: KeyCode); + fn on_mouse(&self, _: &mut Bk, _: MouseEvent) {} } // TODO render something useful? struct Mark; impl View for Mark { - fn run(&self, bk: &mut Bk, kc: KeyCode) { + fn on_key(&self, bk: &mut Bk, kc: KeyCode) { if let KeyCode::Char(c) = kc { bk.mark(c) } @@ -107,9 +108,11 @@ impl View for Mark { struct Jump; impl View for Jump { - fn run(&self, bk: &mut Bk, kc: KeyCode) { + fn on_key(&self, bk: &mut Bk, kc: KeyCode) { if let KeyCode::Char(c) = kc { - bk.jump(c) + if let Some(&pos) = bk.mark.get(&c) { + bk.jump(pos); + } } bk.view = Some(&Page); } @@ -120,7 +123,7 @@ impl View for Jump { struct Metadata; impl View for Metadata { - fn run(&self, bk: &mut Bk, _: KeyCode) { + fn on_key(&self, bk: &mut Bk, _: KeyCode) { bk.view = Some(&Page); } fn render(&self, bk: &Bk) -> Vec<String> { @@ -144,7 +147,7 @@ impl View for Metadata { struct Help; impl View for Help { - fn run(&self, bk: &mut Bk, _: KeyCode) { + fn on_key(&self, bk: &mut Bk, _: KeyCode) { bk.view = Some(&Page); } fn render(&self, _: &Bk) -> Vec<String> { @@ -179,7 +182,7 @@ PageDown Right Space f l Page Down struct Nav; impl View for Nav { - fn run(&self, bk: &mut Bk, kc: KeyCode) { + fn on_key(&self, bk: &mut Bk, kc: KeyCode) { match kc { KeyCode::Esc | KeyCode::Tab @@ -244,7 +247,40 @@ impl View for Nav { struct Page; impl View for Page { - fn run(&self, bk: &mut Bk, kc: KeyCode) { + fn on_mouse(&self, bk: &mut Bk, e: MouseEvent) { + match e { + MouseEvent::Down(_, col, row, _) => { + if col < bk.pad() { + return; + } + let c = bk.chap(); + let (start, end) = c.lines[bk.line + row as usize]; + // FIXME unicode width + let byte = start + (col - bk.pad()) as usize; + if byte > end { + return; + } + let r = c.links.binary_search_by(|&(start, end, _)| { + if start > byte { + Ordering::Greater + } else if end < byte { + Ordering::Less + } else { + Ordering::Equal + } + }); + if let Ok(i) = r { + let path = &c.links[i].2; + let &pos = bk.links.get(path).unwrap(); + bk.jump(pos); + } + } + MouseEvent::ScrollDown(_, _, _) => bk.scroll_down(3), + MouseEvent::ScrollUp(_, _, _) => bk.scroll_up(3), + _ => (), + } + } + fn on_key(&self, bk: &mut Bk, kc: KeyCode) { match kc { KeyCode::Esc | KeyCode::Char('q') => bk.view = None, KeyCode::Tab => { @@ -285,13 +321,13 @@ impl View for Page { bk.scroll_up(bk.rows / 2); } KeyCode::Up | KeyCode::Char('k') => { - bk.scroll_up(2); + bk.scroll_up(3); } KeyCode::Left | KeyCode::PageUp | KeyCode::Char('b') | KeyCode::Char('h') => { bk.scroll_up(bk.rows); } KeyCode::Down | KeyCode::Char('j') => { - bk.scroll_down(2); + bk.scroll_down(3); } KeyCode::Right | KeyCode::PageDown @@ -396,7 +432,7 @@ impl View for Page { struct Search; impl View for Search { - fn run(&self, bk: &mut Bk, kc: KeyCode) { + fn on_key(&self, bk: &mut Bk, kc: KeyCode) { match kc { KeyCode::Esc => { bk.jump_reset(); @@ -450,6 +486,7 @@ struct Bk<'a> { chapter: usize, line: usize, mark: HashMap<char, (usize, usize)>, + links: HashMap<String, (usize, usize)>, // terminal cols: u16, rows: usize, @@ -507,6 +544,7 @@ impl Bk<'_> { chapter: args.chapter, line, mark, + links: epub.links, cols, rows: rows as usize, max_width: args.width, @@ -517,26 +555,32 @@ impl Bk<'_> { query: String::new(), } } + fn pad(&self) -> u16 { + self.cols.saturating_sub(self.max_width) / 2 + } fn run(&mut self) -> crossterm::Result<()> { let mut stdout = stdout(); - queue!(stdout, terminal::EnterAlternateScreen, cursor::Hide)?; + queue!( + stdout, + terminal::EnterAlternateScreen, + cursor::Hide, + EnableMouseCapture + )?; terminal::enable_raw_mode()?; while let Some(view) = self.view { - let pad = self.cols.saturating_sub(self.max_width) / 2; - queue!( stdout, terminal::Clear(terminal::ClearType::All), Print(Attribute::Reset) )?; for (i, line) in view.render(self).iter().enumerate() { - queue!(stdout, cursor::MoveTo(pad, i as u16), Print(line))?; + queue!(stdout, cursor::MoveTo(self.pad(), i as u16), Print(line))?; } stdout.flush().unwrap(); match event::read()? { - Event::Key(e) => view.run(self, e.code), + Event::Key(e) => view.on_key(self, e.code), Event::Resize(cols, rows) => { self.rows = rows as usize; if cols != self.cols { @@ -547,24 +591,25 @@ impl Bk<'_> { } } } - // TODO - Event::Mouse(_) => (), + Event::Mouse(e) => view.on_mouse(self, e), } } - queue!(stdout, terminal::LeaveAlternateScreen, cursor::Show)?; + queue!( + stdout, + terminal::LeaveAlternateScreen, + cursor::Show, + DisableMouseCapture + )?; terminal::disable_raw_mode() } fn mark(&mut self, c: char) { self.mark.insert(c, (self.chapter, self.line)); } - fn jump(&mut self, c: char) { - if let Some(&(c, l)) = self.mark.get(&c) { - let jump = (self.chapter, self.line); - self.chapter = c; - self.line = l; - self.mark.insert('\'', jump); - } + fn jump(&mut self, (c, l): (usize, usize)) { + self.mark('\''); + self.chapter = c; + self.line = l; } fn jump_reset(&mut self) { let &(c, l) = self.mark.get(&'\'').unwrap(); |