Struct concisemark::Page

source ·
pub struct Page {
    pub meta: Option<Meta>,
    pub ast: Node,
    pub content: String,
    pub options: Option<PageOptions>,
}
Expand description

A markdown page

Fields§

§meta: Option<Meta>

Meta information for the page, such as author, tags …

§ast: Node

Page AST (abstract syntax tree), see Page::transform to learn how to modify it

§content: String

The markdown file content (with meta stripped). ast does not store any text but only node range, and content is necessary to retrive node text with ast information.

§options: Option<PageOptions>

Page options, a placehodler for future usage

Implementations§

source§

impl Page

source

pub fn new<S: AsRef<str>>(content: S) -> Self

Create a new markdown page from content

source

pub fn with_options(self, options: PageOptions) -> Self

source

pub fn render(&self) -> String

Render markdown into HTML page

use concisemark::Page;

let content = "# Title";
let page = Page::new(content);
let html = page.render();

The output html will be

<div><h1>Title</h1></div>
source

pub fn render_latex(&self) -> String

Render markdown into XeLaTex source

Note that latex can not embed image from url, you must download the image and fix the image path to generate a working tex file, the following is a dirty and quick example.

use concisemark::Page;
use concisemark::node::Node;
use concisemark::node::NodeTagName;
use concisemark::utils;

use std::fs::OpenOptions;
use std::process::Command;
use std::io::Write;

use indoc::indoc;

let content = indoc! {r#"
    ![animal-online](https://cn.bing.com/th?id=OHR.NorwayMuskox_EN-CN7806818932_1920x1080.jpg&w=720)

    ![animal-offlie](assets/th.jpg)
"#
};
let manifest_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let draft_dir = manifest_dir.join("draft");
std::fs::create_dir_all(draft_dir.as_path()).unwrap();

let page = Page::new(content);
let hook = |node: &Node| -> Result<(), ()> {
    let mut nodedata = node.data.borrow_mut();
    if nodedata.tag.name == NodeTagName::Image {
        let src = nodedata.tag.attrs.get("src").unwrap().to_owned();
        let name = nodedata.tag.attrs.get("name").unwrap().to_owned();
        let output_path;
        if src.starts_with("https://") || src.starts_with("http://") {
            output_path = utils::download_image_fs(src, draft_dir.as_path(), name).unwrap();
        } else {
            output_path = manifest_dir.join(src);
        }
        nodedata.tag.attrs.insert("src".to_owned(), format!("{}", output_path.display()));
    }
    Ok(())
};
page.transform(hook);

let setup = include_str!("../assets/setup.tex");
let wanted = indoc! {r#"
    \begin{document}

    \begin{figure}[H]
    \centerline{\includegraphics[width=0.7\textwidth]{PLACEHOLDER_ONLINE}}
    \caption{animal-online}
    \end{figure}


    \begin{figure}[H]
    \centerline{\includegraphics[width=0.7\textwidth]{PLACEHOLDER_OFFLINE}}
    \caption{animal-offlie}
    \end{figure}

    \end{document}
"#};
let wanted = wanted.replace(
    "PLACEHOLDER_ONLINE",
    &format!("{}", manifest_dir.join("draft").join("animal-online.jpg").display())
).replace(
    "PLACEHOLDER_OFFLINE",
    &format!("{}", manifest_dir.join("assets").join("th.jpg").display())
);
let pagesrc = &page.render_latex()[setup.len()..];
assert_eq!(wanted.trim(), pagesrc.trim());

let latex = page.render_latex();
let texfile = draft_dir.join("output.tex");
let mut f = OpenOptions::new().truncate(true).write(true).create(true).open(&texfile).unwrap();
f.write(latex.as_bytes()).unwrap();
let mut cmd = Command::new("xelatex");
cmd.current_dir(&draft_dir);
cmd.arg(&texfile);
_ = cmd.output();
source

pub fn render_with_hook<F>(&self, hook: &F) -> String
where F: Fn(&Node) -> Option<String>,

Render markdown into HTML page with hook

If the hook returns None, then the default rendering function will be used or else use the returned value as render result.

source

pub fn transform<F, E>(&self, hook: F)
where F: Fn(&Node) -> Result<(), E>,

Modify markdown AST node with hook.

The error status of the hook function (when returns an Err) will not stop the transform process, instead it will print the error as a log message.

The following is an exmaple to change image url

use concisemark::node::{Node, NodeTagName};
use concisemark::Page;

let content = "![imgs](/path/to/image.jpg)";
let page = Page::new(content);
let hook = |node: &Node| -> Result<(), ()> {
    let mut nodedata = node.data.borrow_mut();
    if nodedata.tag.name == NodeTagName::Image {
        let src = nodedata.tag.attrs.get("src").unwrap().to_owned();
        let src = if src.starts_with("/") {
            format!("https://example.com{src}")
        } else {
            format!("https://example.com/{src}")
        };
        nodedata.tag.attrs.insert("src".to_owned(), src);
    }
    Ok(())
};
let img = &page.ast.children()[0].children()[0];
assert_eq!(img.data.borrow().tag.attrs.get("src").map(|s| s.as_str()), Some("/path/to/image.jpg"));
page.transform(hook);
assert_eq!(img.data.borrow().tag.attrs.get("src").map(|s| s.as_str()), Some("https://example.com/path/to/image.jpg"));

Auto Trait Implementations§

§

impl Freeze for Page

§

impl !RefUnwindSafe for Page

§

impl !Send for Page

§

impl !Sync for Page

§

impl Unpin for Page

§

impl !UnwindSafe for Page

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.