summaryrefslogtreecommitdiffstats
path: root/src/tui
diff options
context:
space:
mode:
authorSam Tay <sam.chong.tay@gmail.com>2020-06-18 18:19:37 -0700
committerSam Tay <sam.chong.tay@gmail.com>2020-06-18 18:19:37 -0700
commit2fea044264da4a35e112110164eb98f6b19295ce (patch)
treee7bad01268f1d0ea3cdf381f48b0f4dbe870c3eb /src/tui
parent99bc14e8adb80d96ba1896b79a6c2ddec32c2513 (diff)
Parallelize markdown parsing, and do it upfront
Diffstat (limited to 'src/tui')
-rw-r--r--src/tui/app.rs24
-rw-r--r--src/tui/markdown.rs68
-rw-r--r--src/tui/mod.rs2
-rw-r--r--src/tui/views.rs10
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(' ') => {