aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/epub.rs23
-rw-r--r--src/main.rs30
2 files changed, 26 insertions, 27 deletions
diff --git a/src/epub.rs b/src/epub.rs
index 66c2eb1..73f4e44 100644
--- a/src/epub.rs
+++ b/src/epub.rs
@@ -11,6 +11,7 @@ pub struct Chapter {
// crossterm gives us a bitset but doesn't let us diff it, so store the state transition
pub attrs: Vec<(usize, Attribute, Attributes)>,
pub links: Vec<(usize, usize, String)>,
+ frag: Vec<(String, usize)>,
state: Attributes,
}
@@ -60,13 +61,18 @@ impl Epub {
attrs: vec![(0, Attribute::Reset, state)],
state,
links: Vec::new(),
+ frag: Vec::new(),
};
render(body, &mut c);
- if !c.text.is_empty() {
- let key = path.rsplit('/').next().unwrap().to_string();
- self.links.insert(key, (self.chapters.len(), 0));
- self.chapters.push(c);
+ if c.text.is_empty() {
+ continue;
}
+ for (id, pos) in c.frag.drain(..) {
+ let name = path.rsplit('/').next().unwrap();
+ let url = format!("{}#{}", name, id);
+ self.links.insert(url, (self.chapters.len(), pos));
+ }
+ self.chapters.push(c);
}
}
fn get_spine(&mut self) -> Result<Vec<(String, String)>> {
@@ -167,12 +173,9 @@ fn render(n: Node, c: &mut Chapter) {
if let Some(url) = n.attribute("href") {
let start = c.text.len();
c.render(n, Attribute::Underlined, Attribute::NoUnderline);
- let url = url.split('#').next().unwrap().to_string();
- c.links.push((
- start,
- c.text.len(),
- url,
- ));
+ c.links.push((start, c.text.len(), url.to_string()));
+ } else if let Some(id) = n.attribute("id") {
+ c.frag.push((id.to_string(), c.text.len()));
}
}
"em" => c.render(n, Attribute::Italic, Attribute::NoItalic),
diff --git a/src/main.rs b/src/main.rs
index 09eb5b5..6bee84e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,7 +8,7 @@ use crossterm::{
};
use serde::{Deserialize, Serialize};
use std::{
- cmp::{Ordering, min},
+ cmp::{min, Ordering},
collections::HashMap,
env, fs,
io::{stdout, Write},
@@ -75,6 +75,13 @@ fn wrap(text: &str, max_cols: usize) -> Vec<(usize, usize)> {
lines
}
+fn get_line (lines: &Vec<(usize, usize)>, byte: usize) -> usize {
+ match lines.binary_search_by_key(&byte, |&(a, _)| a) {
+ Ok(n) => n,
+ Err(n) => n - 1,
+ }
+}
+
struct SearchArgs {
dir: Direction,
skip: bool,
@@ -270,9 +277,10 @@ impl View for Page {
}
});
if let Ok(i) = r {
- let path = &c.links[i].2;
- let &pos = bk.links.get(path).unwrap();
- bk.jump(pos);
+ let url = &c.links[i].2;
+ let &(chapter, byte) = bk.links.get(url).unwrap();
+ let line = get_line(&bk.chapters[chapter].lines, byte);
+ bk.jump((chapter, line));
}
}
MouseEvent::ScrollDown(_, _, _) => bk.scroll_down(3),
@@ -522,13 +530,7 @@ impl Bk<'_> {
}
}
- let line = match chapters[args.chapter]
- .lines
- .binary_search_by_key(&args.byte, |&(a, _)| a)
- {
- Ok(n) => n,
- Err(n) => n - 1,
- };
+ let line = get_line(&chapters[args.chapter].lines, args.byte);
let mut mark = HashMap::new();
let view: &dyn View = if args.toc {
@@ -653,12 +655,6 @@ impl Bk<'_> {
self.view = Some(&Search);
}
fn search(&mut self, args: SearchArgs) -> bool {
- let get_line = |lines: &Vec<(usize, usize)>, byte: usize| -> usize {
- match lines.binary_search_by_key(&byte, |&(a, _)| a) {
- Ok(n) => n,
- Err(n) => n - 1,
- }
- };
let (start, end) = self.chap().lines[self.line];
match args.dir {
Direction::Next => {