diff options
-rw-r--r-- | src/epub.rs | 4 | ||||
-rw-r--r-- | src/view.rs | 129 |
2 files changed, 68 insertions, 65 deletions
diff --git a/src/epub.rs b/src/epub.rs index 7357cda..66d1077 100644 --- a/src/epub.rs +++ b/src/epub.rs @@ -205,10 +205,10 @@ fn render(n: Node, c: &mut Chapter) { } } "em" => c.render(n, Attribute::Italic, Attribute::NoItalic), - "strong" => c.render(n, Attribute::Bold, Attribute::NoBold), + "strong" => c.render(n, Attribute::Bold, Attribute::NormalIntensity), "h1" | "h2" | "h3" | "h4" | "h5" | "h6" => { c.text.push('\n'); - c.render(n, Attribute::Bold, Attribute::NoBold); + c.render(n, Attribute::Bold, Attribute::NormalIntensity); c.text.push('\n'); } "blockquote" | "div" | "p" | "tr" => { diff --git a/src/view.rs b/src/view.rs index 2028fda..e06c1ff 100644 --- a/src/view.rs +++ b/src/view.rs @@ -5,7 +5,10 @@ use crossterm::{ }, style::Attribute, }; -use std::cmp::{min, Ordering}; +use std::{ + cmp::{min, Ordering}, + iter, +}; use unicode_width::UnicodeWidthChar; use crate::{Bk, Direction, SearchArgs}; @@ -330,89 +333,89 @@ impl View for Page { } fn render(&self, bk: &Bk) -> Vec<String> { let c = bk.chap(); - let line_end = min(bk.line + bk.rows, c.lines.len()); - - let attrs = { - let text_start = c.lines[bk.line].0; - let text_end = c.lines[line_end - 1].1; - - let qlen = bk.query.len(); - let mut search = Vec::new(); - if qlen > 0 { - for (pos, _) in c.text[text_start..text_end].match_indices(&bk.query) { - search.push((text_start + pos, Attribute::Reverse)); - search.push((text_start + pos + qlen, Attribute::NoReverse)); - } - } - let mut search_iter = search.into_iter().peekable(); + let last_line = min(bk.line + bk.rows, c.lines.len()); + let text_start = c.lines[bk.line].0; + let text_end = c.lines[last_line - 1].1; - let mut merged = Vec::new(); - let attr_start = match c + let mut base = { + let start = match c .attrs - .binary_search_by_key(&text_start, |&(pos, _, _)| pos) + .binary_search_by_key(&text_start, |&x| x.0) { Ok(n) => n, Err(n) => n - 1, }; - let mut attrs_iter = c.attrs[attr_start..].iter(); - let (_, _, attr) = attrs_iter.next().unwrap(); + + let attr = c.attrs[start].2; + let mut head = Vec::new(); if attr.has(Attribute::Bold) { - merged.push((text_start, Attribute::Bold)); + head.push((text_start, Attribute::Bold)); } if attr.has(Attribute::Italic) { - merged.push((text_start, Attribute::Italic)); + head.push((text_start, Attribute::Italic)); } if attr.has(Attribute::Underlined) { - merged.push((text_start, Attribute::Underlined)); + head.push((text_start, Attribute::Underlined)); } - let mut attrs_iter = attrs_iter - .map(|&(pos, a, _)| (pos, a)) - .take_while(|(pos, _)| pos <= &text_end) - .peekable(); + let tail = c.attrs[start + 1..] + .iter() + .take_while(|x| x.0 < text_end) + .map(|x| (x.0, x.1)); + head.into_iter().chain(tail).peekable() + }; - // use itertools? - loop { - match (search_iter.peek(), attrs_iter.peek()) { - (None, None) => break, - (Some(_), None) => { - merged.extend(search_iter); - break; - } - (None, Some(_)) => { - merged.extend(attrs_iter); - break; - } - (Some(&s), Some(&a)) => { - if s.0 < a.0 { - merged.push(s); - search_iter.next(); - } else { - merged.push(a); - attrs_iter.next(); - } + let mut search = Vec::new(); + if !bk.query.is_empty() { + let len = bk.query.len(); + for (pos, _) in c.text[text_start..text_end].match_indices(&bk.query) { + search.push((text_start + pos, Attribute::Reverse)); + search.push((text_start + pos + len, Attribute::NoReverse)); + } + } + let mut search = search.into_iter().peekable(); + + let mut attrs = Vec::new(); + loop { + match (search.peek(), base.peek()) { + (None, None) => break, + (Some(_), None) => { + attrs.extend(search); + break; + } + (None, Some(_)) => { + attrs.extend(base); + break; + } + (Some(&s), Some(&b)) => { + if s.0 < b.0 { + attrs.push(s); + search.next(); + } else { + attrs.push(b); + base.next(); } } } + } + let mut attrs = attrs.into_iter().peekable(); - merged - }; - - let mut buf = Vec::new(); - let mut iter = attrs.into_iter().peekable(); - for &(mut start, end) in &c.lines[bk.line..line_end] { + // itertools: peeking take while + let mut buf = Vec::with_capacity(last_line - bk.line); + for &(mut pos, line_end) in &c.lines[bk.line..last_line] { let mut s = String::new(); - while let Some(&(pos, attr)) = iter.peek() { - if pos > end { + while let Some(&(attr_pos, attr)) = attrs.peek() { + if attr_pos > line_end { break; } - s.push_str(&c.text[start..pos]); + s.push_str(&c.text[pos..attr_pos]); s.push_str(&attr.to_string()); - start = pos; - iter.next(); + pos = attr_pos; + attrs.next(); } - s.push_str(&c.text[start..end]); + s.push_str(&c.text[pos..line_end]); buf.push(s); } + buf } } @@ -426,7 +429,7 @@ impl Search { let byte = if args.skip { end } else { start }; let head = (bk.chapter, byte); let tail = (bk.chapter + 1..bk.chapters.len() - 1).map(|n| (n, 0)); - for (c, byte) in std::iter::once(head).chain(tail) { + for (c, byte) in iter::once(head).chain(tail) { if let Some(index) = bk.chapters[c].text[byte..].find(&bk.query) { bk.line = super::get_line(&bk.chapters[c].lines, index + byte); bk.chapter = c; @@ -441,7 +444,7 @@ impl Search { let tail = (0..bk.chapter) .rev() .map(|c| (c, bk.chapters[c].text.len())); - for (c, byte) in std::iter::once(head).chain(tail) { + for (c, byte) in iter::once(head).chain(tail) { if let Some(index) = bk.chapters[c].text[..byte].rfind(&bk.query) { bk.line = super::get_line(&bk.chapters[c].lines, index); bk.chapter = c; @@ -481,7 +484,7 @@ impl View for Search { dir: bk.dir.clone(), skip: false, }; - if self.search(bk, args) { + if !self.search(bk, args) { bk.jump_reset(); } } |