From 1136a1f5dcea65490197b6b3f69d8a59848e4e53 Mon Sep 17 00:00:00 2001 From: James Campos Date: Fri, 17 Jul 2020 09:54:43 -0700 Subject: fragments --- src/epub.rs | 23 +++++++++++++---------- src/main.rs | 30 +++++++++++++----------------- 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> { @@ -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 => { -- cgit v1.2.3