aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
authorJames Campos <james.r.campos@gmail.com>2020-04-28 10:41:08 -0700
committerJames Campos <james.r.campos@gmail.com>2020-04-28 10:41:08 -0700
commit5c6dd582c3f527005680b48c4a7b336e2fd362ba (patch)
tree39f47930ceae349791aa08c67e4090fdad2e15d9 /src/main.rs
parentc29013c6593b72a27d683e0c7b01b634a3a229fa (diff)
downloadbk-5c6dd582c3f527005680b48c4a7b336e2fd362ba.tar.gz
search
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs105
1 files changed, 79 insertions, 26 deletions
diff --git a/src/main.rs b/src/main.rs
index 31c92e7..d4c9642 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,7 +7,7 @@ use crossterm::{
event::{self, Event, KeyCode, MouseEvent},
queue,
style::{Attribute, Print},
- terminal,
+ terminal::{self, ClearType},
};
use roxmltree::Document;
@@ -16,25 +16,13 @@ enum Mode {
Help,
Nav,
Read,
+ Search,
}
struct Epub {
container: zip::ZipArchive<File>,
}
-struct Bk {
- mode: Mode,
- epub: Epub,
- cols: u16,
- chapter: Vec<String>,
- chapter_idx: usize,
- nav_idx: usize,
- pos: usize,
- rows: usize,
- toc: Vec<(String, String)>,
- pad: u16,
-}
-
impl Epub {
fn new(path: &str) -> Result<Self, Error> {
let file = File::open(path)?;
@@ -168,6 +156,7 @@ impl Epub {
fn wrap(text: Vec<String>, width: u16) -> Vec<String> {
// XXX assumes a char is 1 unit wide
+ // TODO break at dash/hyphen
let mut wrapped = Vec::with_capacity(text.len() * 2);
for chunk in text {
@@ -196,6 +185,20 @@ fn wrap(text: Vec<String>, width: u16) -> Vec<String> {
wrapped
}
+struct Bk {
+ mode: Mode,
+ epub: Epub,
+ cols: u16,
+ chapter: Vec<String>,
+ chapter_idx: usize,
+ nav_idx: usize,
+ pos: usize,
+ rows: usize,
+ toc: Vec<(String, String)>,
+ pad: u16,
+ search: String,
+}
+
impl Bk {
fn new(
path: &str,
@@ -216,6 +219,7 @@ impl Bk {
pad,
cols,
rows: rows as usize,
+ search: String::new(),
};
bk.get_chapter(chapter_idx);
bk.pos = pos;
@@ -288,9 +292,44 @@ impl Bk {
Mode::Read => return self.run_read(e),
Mode::Nav => self.run_nav(e),
Mode::Help => self.mode = Mode::Read,
+ Mode::Search => self.run_search(e),
}
true
}
+ fn really_search(&mut self, forwards: bool) {
+ if forwards {
+ if let Some(pos) = self.chapter[self.pos + 1..]
+ .iter()
+ .position(|s| s.contains(&self.search))
+ {
+ self.pos += pos + 1;
+ }
+ } else if let Some(pos) = self.chapter[0..self.pos - 1]
+ .iter()
+ .rposition(|s| s.contains(&self.search))
+ {
+ self.pos = pos;
+ }
+ }
+ fn run_search(&mut self, e: Event) {
+ match e {
+ Event::Key(e) => match e.code {
+ KeyCode::Esc => {
+ self.search = String::new();
+ self.mode = Mode::Read;
+ }
+ KeyCode::Enter => {
+ self.mode = Mode::Read;
+ self.really_search(true);
+ }
+ KeyCode::Char(c) => {
+ self.search.push(c);
+ }
+ _ => (),
+ },
+ _ => (),
+ }
+ }
fn run_nav(&mut self, e: Event) {
match e {
Event::Key(e) => match e.code {
@@ -343,15 +382,15 @@ impl Bk {
KeyCode::Esc | KeyCode::Char('q') => return false,
KeyCode::Tab => self.start_nav(),
KeyCode::F(1) | KeyCode::Char('?') => self.mode = Mode::Help,
- KeyCode::Char('p') => {
- if self.chapter_idx > 0 {
- self.get_chapter(self.chapter_idx - 1);
- }
+ KeyCode::Char('/') => {
+ self.search = String::new();
+ self.mode = Mode::Search;
+ }
+ KeyCode::Char('N') => {
+ self.really_search(false);
}
KeyCode::Char('n') => {
- if self.chapter_idx < self.toc.len() - 1 {
- self.get_chapter(self.chapter_idx + 1);
- }
+ self.really_search(true);
}
KeyCode::End | KeyCode::Char('G') => {
self.pos = (self.chapter.len() / self.rows) * self.rows;
@@ -402,15 +441,27 @@ impl Bk {
Mode::Read => self.render_read(),
Mode::Help => self.render_help(),
Mode::Nav => self.render_nav(),
+ Mode::Search => self.render_search(),
}
}
+ fn render_search(&self) {
+ let mut stdout = stdout();
+ queue!(
+ stdout,
+ cursor::MoveTo(0, self.rows as u16),
+ terminal::Clear(ClearType::CurrentLine),
+ Print(&self.search)
+ )
+ .unwrap();
+ stdout.flush().unwrap();
+ }
fn start_nav(&mut self) {
self.nav_idx = self.chapter_idx;
self.mode = Mode::Nav;
}
fn render_nav(&self) {
let mut stdout = stdout();
- queue!(stdout, terminal::Clear(terminal::ClearType::All),).unwrap();
+ queue!(stdout, terminal::Clear(ClearType::All),).unwrap();
let end = std::cmp::min(self.rows, self.toc.len());
for i in 0..end {
if i == self.nav_idx {
@@ -441,21 +492,23 @@ impl Bk {
let text = r#"
Esc q Quit
F1 ? Help
+ / Search
Tab Table of Contents
+
PageDown Right Space f l Page Down
PageUp Left b h Page Up
d Half Page Down
u Half Page Up
Down j Line Down
Up k Line Up
- n Next Chapter
- p Previous Chapter
Home g Chapter Start
End G Chapter End
+ n Search Forwards
+ N Search Backwards
"#;
let mut stdout = stdout();
- queue!(stdout, terminal::Clear(terminal::ClearType::All),).unwrap();
+ queue!(stdout, terminal::Clear(ClearType::All),).unwrap();
for (i, line) in text.lines().enumerate() {
queue!(stdout, cursor::MoveTo(0, i as u16), Print(line)).unwrap();
}
@@ -465,7 +518,7 @@ PageDown Right Space f l Page Down
let mut stdout = stdout();
queue!(
stdout,
- terminal::Clear(terminal::ClearType::All),
+ terminal::Clear(ClearType::All),
cursor::MoveTo(self.pad, 0),
)
.unwrap();