|
|
|
@ -21,10 +21,7 @@ impl Markdown {
|
|
|
|
|
Self { contents }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
impl Component for Markdown {
|
|
|
|
|
fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) {
|
|
|
|
|
use tui::widgets::{Paragraph, Widget, Wrap};
|
|
|
|
|
|
|
|
|
|
fn parse(contents: &str) -> tui::text::Text {
|
|
|
|
|
use pulldown_cmark::{CodeBlockKind, CowStr, Event, Options, Parser, Tag};
|
|
|
|
|
use tui::text::{Span, Spans, Text};
|
|
|
|
|
|
|
|
|
@ -33,7 +30,7 @@ impl Component for Markdown {
|
|
|
|
|
|
|
|
|
|
let mut options = Options::empty();
|
|
|
|
|
options.insert(Options::ENABLE_STRIKETHROUGH);
|
|
|
|
|
let parser = Parser::new_ext(&self.contents, options);
|
|
|
|
|
let parser = Parser::new_ext(contents, options);
|
|
|
|
|
|
|
|
|
|
// TODO: if possible, render links as terminal hyperlinks: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
|
|
|
|
|
let mut tags = Vec::new();
|
|
|
|
@ -43,7 +40,7 @@ impl Component for Markdown {
|
|
|
|
|
fn to_span(text: pulldown_cmark::CowStr) -> Span {
|
|
|
|
|
use std::ops::Deref;
|
|
|
|
|
Span::raw::<std::borrow::Cow<_>>(match text {
|
|
|
|
|
CowStr::Borrowed(s) => s.into(),
|
|
|
|
|
CowStr::Borrowed(s) => s.to_string().into(), // could retain borrow
|
|
|
|
|
CowStr::Boxed(s) => s.to_string().into(),
|
|
|
|
|
CowStr::Inlined(s) => s.deref().to_owned().into(),
|
|
|
|
|
})
|
|
|
|
@ -59,12 +56,12 @@ impl Component for Markdown {
|
|
|
|
|
Event::End(tag) => {
|
|
|
|
|
tags.pop();
|
|
|
|
|
match tag {
|
|
|
|
|
Tag::Heading(_)
|
|
|
|
|
| Tag::Paragraph
|
|
|
|
|
| Tag::CodeBlock(CodeBlockKind::Fenced(_)) => {
|
|
|
|
|
Tag::Heading(_) | Tag::Paragraph | Tag::CodeBlock(CodeBlockKind::Fenced(_)) => {
|
|
|
|
|
// whenever code block or paragraph closes, new line
|
|
|
|
|
let spans = std::mem::replace(&mut spans, Vec::new());
|
|
|
|
|
if !spans.is_empty() {
|
|
|
|
|
lines.push(Spans::from(spans));
|
|
|
|
|
}
|
|
|
|
|
lines.push(Spans::default());
|
|
|
|
|
}
|
|
|
|
|
_ => (),
|
|
|
|
@ -110,9 +107,15 @@ impl Component for Markdown {
|
|
|
|
|
lines.push(Spans::from(spans));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let contents = Text::from(lines);
|
|
|
|
|
Text::from(lines)
|
|
|
|
|
}
|
|
|
|
|
impl Component for Markdown {
|
|
|
|
|
fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) {
|
|
|
|
|
use tui::widgets::{Paragraph, Widget, Wrap};
|
|
|
|
|
|
|
|
|
|
let text = parse(&self.contents);
|
|
|
|
|
|
|
|
|
|
let par = Paragraph::new(contents)
|
|
|
|
|
let par = Paragraph::new(text)
|
|
|
|
|
.wrap(Wrap { trim: false })
|
|
|
|
|
.scroll((cx.scroll.unwrap_or_default() as u16, 0));
|
|
|
|
|
|
|
|
|
@ -121,7 +124,7 @@ impl Component for Markdown {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
|
|
|
|
|
let contents = tui::text::Text::from(self.contents.clone());
|
|
|
|
|
let contents = parse(&self.contents);
|
|
|
|
|
let padding = 2;
|
|
|
|
|
let width = std::cmp::min(contents.width() as u16 + padding, viewport.0);
|
|
|
|
|
let height = std::cmp::min(contents.height() as u16 + padding, viewport.1);
|
|
|
|
|