aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/epub.rs14
-rw-r--r--src/main.rs87
2 files changed, 51 insertions, 50 deletions
diff --git a/src/epub.rs b/src/epub.rs
index 48263c2..795f4d1 100644
--- a/src/epub.rs
+++ b/src/epub.rs
@@ -6,8 +6,7 @@ use roxmltree::{Document, Node};
pub struct Epub {
container: zip::ZipArchive<File>,
- pub nav: Vec<String>,
- pub chapters: Vec<String>,
+ pub chapters: Vec<(String, String)>,
}
impl Epub {
@@ -15,13 +14,12 @@ impl Epub {
let file = File::open(path)?;
let mut epub = Epub {
container: zip::ZipArchive::new(file)?,
- nav: Vec::new(),
chapters: Vec::new(),
};
- let (nav, chapters) = epub
+ epub.chapters = epub
.get_nav()
.into_iter()
- .filter_map(|(path, label)| {
+ .filter_map(|(path, title)| {
let xml = epub.get_text(&path);
// https://github.com/RazrFalcon/roxmltree/issues/12
// UnknownEntityReference for HTML entities
@@ -32,12 +30,10 @@ impl Epub {
if chapter.is_empty() {
None
} else {
- Some((label, chapter))
+ Some((title, chapter))
}
})
- .unzip();
- epub.nav = nav;
- epub.chapters = chapters;
+ .collect();
Ok(epub)
}
fn render(buf: &mut String, n: Node) {
diff --git a/src/main.rs b/src/main.rs
index b1586c3..0d1889e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -61,8 +61,6 @@ fn wrap(text: &str, width: usize) -> Vec<(usize, String)> {
lines
}
-struct Position(String, usize, usize);
-
trait View {
fn run(&self, bk: &mut Bk, kc: KeyCode);
fn render(&self, bk: &Bk) -> Vec<String>;
@@ -112,7 +110,7 @@ impl View for Nav {
bk.view = Some(&Page);
}
KeyCode::Down | KeyCode::Char('j') => {
- if bk.chapter < bk.toc.len() - 1 {
+ if bk.chapter < bk.chapters.len() - 1 {
bk.chapter += 1;
if bk.chapter == bk.nav_top + bk.rows {
bk.nav_top += 1;
@@ -132,23 +130,28 @@ impl View for Nav {
bk.nav_top = 0;
}
KeyCode::End | KeyCode::Char('G') => {
- bk.chapter = bk.toc.len() - 1;
- bk.nav_top = bk.toc.len().saturating_sub(bk.rows);
+ bk.chapter = bk.chapters.len() - 1;
+ bk.nav_top = bk.chapters.len().saturating_sub(bk.rows);
}
_ => (),
}
}
fn render(&self, bk: &Bk) -> Vec<String> {
- let end = std::cmp::min(bk.nav_top + bk.rows, bk.toc.len());
+ let end = std::cmp::min(bk.nav_top + bk.rows, bk.chapters.len());
- bk.toc[bk.nav_top..end]
+ bk.chapters[bk.nav_top..end]
.iter()
.enumerate()
- .map(|(i, label)| {
+ .map(|(i, chapter)| {
if bk.chapter == bk.nav_top + i {
- format!("{}{}{}", Attribute::Reverse, label, Attribute::Reset)
+ format!(
+ "{}{}{}",
+ Attribute::Reverse,
+ chapter.title,
+ Attribute::Reset
+ )
} else {
- label.to_string()
+ chapter.title.to_string()
}
})
.collect()
@@ -278,6 +281,8 @@ impl View for Search {
// ideally we could use string slices as pointers, but self referential structs are hard
struct Chapter {
+ // for toc
+ title: String,
// chapter text as a single string, used for search
text: String,
// line wrapped text
@@ -287,14 +292,12 @@ struct Chapter {
}
struct Bk<'a> {
- // the book
chapters: Vec<Chapter>,
- toc: Vec<String>,
// position in the book
chapter: usize,
line: usize,
jump: (usize, usize),
- // the terminal
+ // terminal
cols: u16,
rows: usize,
// user config
@@ -307,12 +310,12 @@ struct Bk<'a> {
}
impl Bk<'_> {
- fn new(epub: epub::Epub, line: &Position, max_width: u16) -> Self {
+ fn new(epub: epub::Epub, chapter: usize, line: usize, max_width: u16) -> Self {
let (cols, rows) = terminal::size().unwrap();
let width = std::cmp::min(cols, max_width) as usize;
let mut chapters = Vec::with_capacity(epub.chapters.len());
- for text in epub.chapters {
+ for (title, text) in epub.chapters {
let wrap = wrap(&text, width);
let mut lines = Vec::with_capacity(wrap.len());
let mut bytes = Vec::with_capacity(wrap.len());
@@ -321,20 +324,24 @@ impl Bk<'_> {
lines.push(line);
bytes.push(byte);
}
- chapters.push(Chapter { text, lines, bytes });
+ chapters.push(Chapter {
+ title,
+ text,
+ lines,
+ bytes,
+ });
}
Bk {
- jump: (0, 0),
- view: Some(&Page),
- chapter: line.1,
- nav_top: 0,
- toc: epub.nav,
chapters,
- line: line.2,
- max_width,
+ chapter,
+ line,
+ jump: (0, 0),
cols,
rows: rows as usize,
+ max_width,
+ view: Some(&Page),
+ nav_top: 0,
search: String::new(),
}
}
@@ -372,7 +379,7 @@ impl Bk<'_> {
terminal::disable_raw_mode()
}
fn next_chapter(&mut self) {
- if self.chapter < self.toc.len() - 1 {
+ if self.chapter < self.chapters.len() - 1 {
self.chapter += 1;
self.line = 0;
}
@@ -438,14 +445,13 @@ impl Bk<'_> {
}
}
-fn restore() -> Option<Position> {
+fn restore(save_path: &str) -> Option<(String, usize, usize)> {
let path = std::env::args().nth(1);
- let save_path = format!("{}/.local/share/bk", std::env::var("HOME").unwrap());
let save = std::fs::read_to_string(save_path);
let get_save = |s: String| {
let mut lines = s.lines();
- Position(
+ (
lines.next().unwrap().to_string(),
lines.next().unwrap().parse::<usize>().unwrap(),
lines.next().unwrap().parse::<usize>().unwrap(),
@@ -454,40 +460,39 @@ fn restore() -> Option<Position> {
match (save, path) {
(Err(_), None) => None,
- (Err(_), Some(path)) => Some(Position(path, 0, 0)),
+ (Err(_), Some(path)) => Some((path, 0, 0)),
(Ok(save), None) => Some(get_save(save)),
(Ok(save), Some(path)) => {
let save = get_save(save);
- if save.0 == path {
+ if path == save.0 {
Some(save)
} else {
- Some(Position(path, 0, 0))
+ Some((path, 0, 0))
}
}
}
}
fn main() {
- let line = restore().unwrap_or_else(|| {
+ let save_path = format!("{}/.local/share/bk", std::env::var("HOME").unwrap());
+ let (path, chapter, line) = restore(&save_path).unwrap_or_else(|| {
println!("usage: bk path");
std::process::exit(1);
});
- let epub = epub::Epub::new(&line.0).unwrap_or_else(|e| {
+ let epub = epub::Epub::new(&path).unwrap_or_else(|e| {
println!("error reading epub: {}", e);
std::process::exit(1);
});
- let mut bk = Bk::new(epub, &line, 75);
+ let mut bk = Bk::new(epub, chapter, line, 75);
// crossterm really shouldn't error
bk.run().unwrap();
- std::fs::write(
- format!("{}/.local/share/bk", std::env::var("HOME").unwrap()),
- format!("{}\n{}\n{}", line.0, bk.chapter, bk.line),
- )
- .unwrap_or_else(|e| {
- println!("error saving position: {}", e);
- std::process::exit(1);
- });
+ std::fs::write(save_path, format!("{}\n{}\n{}", path, bk.chapter, bk.line)).unwrap_or_else(
+ |e| {
+ println!("error saving position: {}", e);
+ std::process::exit(1);
+ },
+ );
}