diff options
author | Sam Tay <sam.chong.tay@gmail.com> | 2020-06-18 18:19:37 -0700 |
---|---|---|
committer | Sam Tay <sam.chong.tay@gmail.com> | 2020-06-18 18:19:37 -0700 |
commit | 2fea044264da4a35e112110164eb98f6b19295ce (patch) | |
tree | e7bad01268f1d0ea3cdf381f48b0f4dbe870c3eb /src/tui | |
parent | 99bc14e8adb80d96ba1896b79a6c2ddec32c2513 (diff) |
Parallelize markdown parsing, and do it upfront
Diffstat (limited to 'src/tui')
-rw-r--r-- | src/tui/app.rs | 24 | ||||
-rw-r--r-- | src/tui/markdown.rs | 68 | ||||
-rw-r--r-- | src/tui/mod.rs | 2 | ||||
-rw-r--r-- | src/tui/views.rs | 10 |
4 files changed, 49 insertions, 55 deletions
diff --git a/src/tui/app.rs b/src/tui/app.rs index bb0a923..ad1a1ea 100644 --- a/src/tui/app.rs +++ b/src/tui/app.rs @@ -4,11 +4,11 @@ use cursive::utils::markup::StyledString; use cursive::utils::span::SpannedString; use cursive::Cursive; use cursive::XY; -use std::cmp; use std::collections::HashMap; use std::sync::Arc; use super::markdown; +use super::markdown::Markdown; use super::views::{ LayoutView, ListView, MdView, Name, Vimable, NAME_ANSWER_LIST, NAME_ANSWER_VIEW, NAME_QUESTION_LIST, NAME_QUESTION_VIEW, @@ -17,16 +17,14 @@ use crate::config; use crate::error::Result; use crate::stackexchange::{Answer, Question}; -// TODO maybe a struct like Tui::new(stackexchange) creates App::new and impls tui.run()? -// TODO take async questions -// TODO take the entire SE struct for future questions -pub fn run(qs: Vec<Question>) -> Result<()> { +pub fn run(qs: Vec<Question<Markdown>>) -> Result<()> { let mut siv = cursive::default(); siv.load_theme_file(config::theme_file_name()?).unwrap(); // TODO dont unwrap - let question_map: HashMap<u32, Question> = qs.clone().into_iter().map(|q| (q.id, q)).collect(); + let question_map: HashMap<u32, Question<Markdown>> = + qs.clone().into_iter().map(|q| (q.id, q)).collect(); let question_map = Arc::new(question_map); - let answer_map: HashMap<u32, Answer> = qs + let answer_map: HashMap<u32, Answer<Markdown>> = qs .clone() .into_iter() .map(|q| q.answers.into_iter().map(|a| (a.id, a))) @@ -74,15 +72,16 @@ pub fn run(qs: Vec<Question>) -> Result<()> { } fn question_selected_callback( - question_map: Arc<HashMap<u32, Question>>, + question_map: Arc<HashMap<u32, Question<Markdown>>>, mut s: &mut Cursive, qid: u32, ) { let q = question_map.get(&qid).unwrap(); + let body = &q.body; let XY { x, y: _y } = s.screen_size(); // Update question view s.call_on_name(NAME_QUESTION_VIEW, |v: &mut MdView| { - v.set_content(&q.body); + v.set_content(body); }) .expect("Panic: setting question view content failed"); // Update answer list view @@ -94,15 +93,14 @@ fn question_selected_callback( cb(&mut s) } -fn preview_question(q: &Question) -> StyledString { +fn preview_question(q: &Question<Markdown>) -> StyledString { let mut preview = pretty_score(q.score); preview.append_plain(&q.title); preview } -fn preview_answer(screen_width: usize, a: &Answer) -> StyledString { - let width = cmp::min(a.body.len(), screen_width); - let md = markdown::preview(width, a.body.to_owned()); +fn preview_answer(screen_width: usize, a: &Answer<Markdown>) -> StyledString { + let md = markdown::preview(screen_width, &a.body); let mut preview = pretty_score(a.score); if a.is_accepted { preview.append_styled( diff --git a/src/tui/markdown.rs b/src/tui/markdown.rs index 6c44684..0330696 100644 --- a/src/tui/markdown.rs +++ b/src/tui/markdown.rs @@ -17,50 +17,23 @@ use unicode_width::UnicodeWidthStr; use super::entities::is_entity; +pub type Markdown = StyledString; + /// Parses the given string as markdown text. +/// **Note**: Assumes preprocessing has taken place pub fn parse<S>(input: S) -> StyledString where S: Into<String>, { - let input = preprocess(input.into()); + let input = input.into(); let spans = parse_spans(&input); //let output = build_output(&spans); StyledString::with_spans(input, spans) } -/// Preview markdown. Largely heuristic. -pub fn preview<S>(size: usize, input: S) -> StyledString -where - S: Into<String>, -{ - // DO the initial parsing here too, not just in `parse` - let generous_size = (size as f32) * 1.2; - let generous_size = generous_size.ceil(); - let generous_size = generous_size as usize; - let mut input = input.into(); - input.truncate(generous_size); - let input = preprocess(input); - let spans = parse_spans(&input) - .into_iter() - // Filter out newlines - .map(|ix_span| match ix_span { - IndexedSpan { width: 0, .. } => IndexedSpan { - content: IndexedCow::Owned(" ".to_owned()), - width: 1, - ..ix_span - }, - is => is, - }) - .collect(); - - let mut prev = StyledString::with_spans(input, spans); - prev.append_plain("..."); - prev -} - -fn preprocess(input: String) -> String { - // TODO handle other stackexchange oddities here ENTITIES - // TODO then benchmark +// TODO handle other stackexchange oddities here ENTITIES +// TODO then benchmark +pub fn preprocess(input: String) -> String { input .as_str() .trim() @@ -68,8 +41,33 @@ fn preprocess(input: String) -> String { .replace("</kbd>", "]**") } +/// Preview markdown of the given length +pub fn preview(width: usize, input: &StyledString) -> StyledString { + let mut w = 0; + let mut new_spans = Vec::new(); + for span in input.spans_raw() { + // Filter newlines + if span.width == 0 { + w += 1; + new_spans.push(IndexedSpan { + content: IndexedCow::Owned(" ".to_owned()), + width: 1, + ..*span + }); + } else { + w += span.width; + new_spans.push(span.clone()); + } + if w > width { + break; + } + } + let mut prev = StyledString::with_spans(input.source(), new_spans); + prev.append_plain("..."); + prev +} + /// Parse the given markdown text into a list of spans. -/// Assumes preprocessing has taken place /// This is a shortcut for `Parser::new(preprocessed_input).collect()`. fn parse_spans(input: &str) -> Vec<StyledIndexedSpan> { Parser::new(input).collect() diff --git a/src/tui/mod.rs b/src/tui/mod.rs index 634cb29..be3764f 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -1,7 +1,7 @@ mod app; mod entities; mod enumerable; -mod markdown; +pub mod markdown; mod ui; mod views; diff --git a/src/tui/views.rs b/src/tui/views.rs index 2fc2136..e4c8649 100644 --- a/src/tui/views.rs +++ b/src/tui/views.rs @@ -11,7 +11,7 @@ use std::fmt; use std::fmt::Display; use std::rc::Rc; -use super::markdown; +use super::markdown::Markdown; use crate::error::Result; pub const NAME_QUESTION_LIST: &str = "question_list"; @@ -243,13 +243,10 @@ impl MdView { } /// Panics for now, to explore when result is None - pub fn set_content<S>(&mut self, content: S) - where - S: Into<String>, - { + pub fn set_content(&mut self, content: &Markdown) { self.view .call_on_name(&self.inner_name, |tv: &mut TextView| { - tv.set_content(markdown::parse(content)) + tv.set_content(content.clone()) }) .expect("unwrap failed in MdView.set_content") } @@ -310,6 +307,7 @@ impl ViewWrapper for LayoutView { fn wrap_on_event(&mut self, event: Event) -> EventResult { match event { Event::WindowResize => { + println!("window resized"); self.size_invalidated = true; } Event::Char(' ') => { |