Skip to content

Commit

Permalink
feat: add support for rendering mermaid diagrams
Browse files Browse the repository at this point in the history
  • Loading branch information
mfontanini committed Jun 14, 2024
1 parent 252a892 commit 5dc93f2
Show file tree
Hide file tree
Showing 13 changed files with 150 additions and 50 deletions.
23 changes: 17 additions & 6 deletions config-file-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@
}
]
},
"mermaid": {
"$ref": "#/definitions/MermaidConfig"
},
"options": {
"$ref": "#/definitions/OptionsConfig"
},
"typst": {
"allOf": [
{
"$ref": "#/definitions/TypstConfig"
}
],
"minimum": 1.0
"$ref": "#/definitions/TypstConfig"
}
},
"additionalProperties": false,
Expand Down Expand Up @@ -210,6 +208,19 @@
},
"additionalProperties": false
},
"MermaidConfig": {
"type": "object",
"properties": {
"scale": {
"description": "The scaling parameter to be used in the mermaid CLI.",
"default": 2,
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
},
"OptionsConfig": {
"type": "object",
"properties": {
Expand Down
24 changes: 22 additions & 2 deletions src/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ pub struct Config {
pub defaults: DefaultsConfig,

#[serde(default)]
#[validate(range(min = 1))]
pub typst: TypstConfig,

#[serde(default)]
pub mermaid: MermaidConfig,

#[serde(default)]
pub options: OptionsConfig,

Expand Down Expand Up @@ -126,10 +128,28 @@ impl Default for TypstConfig {
}
}

fn default_typst_ppi() -> u32 {
pub(crate) fn default_typst_ppi() -> u32 {
300
}

#[derive(Clone, Debug, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct MermaidConfig {
/// The scaling parameter to be used in the mermaid CLI.
#[serde(default = "default_mermaid_scale")]
pub scale: u32,
}

impl Default for MermaidConfig {
fn default() -> Self {
Self { scale: default_mermaid_scale() }
}
}

pub(crate) fn default_mermaid_scale() -> u32 {
2
}

#[derive(Clone, Debug, Default, Deserialize, ValueEnum, JsonSchema)]
#[serde(rename_all = "kebab-case")]
pub enum ImageProtocol {
Expand Down
6 changes: 3 additions & 3 deletions src/demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
presentation::Presentation,
processing::builder::{BuildError, PresentationBuilder},
render::{draw::TerminalDrawer, terminal::TerminalWrite},
ImageRegistry, MarkdownParser, PresentationBuilderOptions, PresentationTheme, Resources, Themes, TypstRender,
ImageRegistry, MarkdownParser, PresentationBuilderOptions, PresentationTheme, Resources, Themes, ThirdPartyRender,
};
use std::{io, rc::Rc};

Expand Down Expand Up @@ -100,14 +100,14 @@ impl<W: TerminalWrite> ThemesDemo<W> {
) -> Result<Presentation, BuildError> {
let image_registry = ImageRegistry::default();
let mut resources = Resources::new("non_existent", image_registry.clone());
let mut typst = TypstRender::default();
let mut third_party = ThirdPartyRender::default();
let options = PresentationBuilderOptions::default();
let executer = Rc::new(CodeExecutor::default());
let bindings_config = Default::default();
let builder = PresentationBuilder::new(
theme,
&mut resources,
&mut typst,
&mut third_party,
executer,
&self.themes,
image_registry,
Expand Down
14 changes: 7 additions & 7 deletions src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::{
},
presentation::{Presentation, RenderOperation},
processing::builder::{BuildError, PresentationBuilder, PresentationBuilderOptions, Themes},
third_party::ThirdPartyRender,
tools::{ExecutionError, ThirdPartyTools},
typst::TypstRender,
MarkdownParser, PresentationTheme, Resources,
};
use base64::{engine::general_purpose::STANDARD, Engine};
Expand All @@ -29,7 +29,7 @@ pub struct Exporter<'a> {
parser: MarkdownParser<'a>,
default_theme: &'a PresentationTheme,
resources: Resources,
typst: TypstRender,
third_party: ThirdPartyRender,
code_executor: Rc<CodeExecutor>,
themes: Themes,
options: PresentationBuilderOptions,
Expand All @@ -41,12 +41,12 @@ impl<'a> Exporter<'a> {
parser: MarkdownParser<'a>,
default_theme: &'a PresentationTheme,
resources: Resources,
typst: TypstRender,
third_party: ThirdPartyRender,
code_executor: Rc<CodeExecutor>,
themes: Themes,
options: PresentationBuilderOptions,
) -> Self {
Self { parser, default_theme, resources, typst, code_executor, themes, options }
Self { parser, default_theme, resources, third_party, code_executor, themes, options }
}

/// Export the given presentation into PDF.
Expand Down Expand Up @@ -85,7 +85,7 @@ impl<'a> Exporter<'a> {
let mut presentation = PresentationBuilder::new(
self.default_theme,
&mut self.resources,
&mut self.typst,
&mut self.third_party,
self.code_executor.clone(),
&self.themes,
Default::default(),
Expand Down Expand Up @@ -302,11 +302,11 @@ mod test {
let parser = MarkdownParser::new(&arena);
let theme = PresentationThemeSet::default().load_by_name("dark").unwrap();
let resources = Resources::new("examples", Default::default());
let typst = TypstRender::default();
let third_party = ThirdPartyRender::default();
let code_executor = Default::default();
let themes = Themes::default();
let options = PresentationBuilderOptions { allow_mutations: false, ..Default::default() };
let mut exporter = Exporter::new(parser, &theme, resources, typst, code_executor, themes, options);
let mut exporter = Exporter::new(parser, &theme, resources, third_party, code_executor, themes, options);
exporter.extract_metadata(content, Path::new(path)).expect("metadata extraction failed")
}

Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ pub(crate) mod render;
pub(crate) mod resource;
pub(crate) mod style;
pub(crate) mod theme;
pub(crate) mod third_party;
pub(crate) mod tools;
pub(crate) mod typst;

pub use crate::{
custom::{Config, ImageProtocol, ValidateOverflows},
Expand All @@ -33,5 +33,5 @@ pub use crate::{
render::highlighting::{CodeHighlighter, HighlightThemeSet},
resource::Resources,
theme::{LoadThemeError, PresentationTheme, PresentationThemeSet},
typst::TypstRender,
third_party::{ThirdPartyConfigs, ThirdPartyRender},
};
22 changes: 17 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use directories::ProjectDirs;
use presenterm::{
CodeExecutor, CommandSource, Config, Exporter, GraphicsMode, HighlightThemeSet, ImagePrinter, ImageProtocol,
ImageRegistry, MarkdownParser, PresentMode, PresentationBuilderOptions, PresentationTheme, PresentationThemeSet,
Presenter, PresenterOptions, Resources, Themes, ThemesDemo, TypstRender, ValidateOverflows,
Presenter, PresenterOptions, Resources, Themes, ThemesDemo, ThirdPartyConfigs, ThirdPartyRender, ValidateOverflows,
};
use std::{
env, io,
Expand Down Expand Up @@ -211,10 +211,13 @@ fn run(mut cli: Cli) -> Result<(), Box<dyn std::error::Error>> {
let printer = Rc::new(ImagePrinter::new(graphics_mode.clone())?);
let registry = ImageRegistry(printer.clone());
let resources = Resources::new(resources_path, registry.clone());
let typst = TypstRender::new(config.typst.ppi, registry, resources_path);
let third_party_config =
ThirdPartyConfigs { typst_ppi: config.typst.ppi.to_string(), mermaid_scale: config.mermaid.scale.to_string() };
let third_party = ThirdPartyRender::new(third_party_config, registry, resources_path);
let code_executor = Rc::new(code_executor);
if cli.export_pdf || cli.generate_pdf_metadata {
let mut exporter = Exporter::new(parser, &default_theme, resources, typst, code_executor, themes, options);
let mut exporter =
Exporter::new(parser, &default_theme, resources, third_party, code_executor, themes, options);
let mut args = Vec::new();
if let Some(theme) = cli.theme.as_ref() {
args.extend(["--theme", theme]);
Expand All @@ -239,8 +242,17 @@ fn run(mut cli: Cli) -> Result<(), Box<dyn std::error::Error>> {
bindings: config.bindings,
validate_overflows,
};
let presenter =
Presenter::new(&default_theme, commands, parser, resources, typst, code_executor, themes, printer, options);
let presenter = Presenter::new(
&default_theme,
commands,
parser,
resources,
third_party,
code_executor,
themes,
printer,
options,
);
presenter.present(&path)?;
}
Ok(())
Expand Down
4 changes: 3 additions & 1 deletion src/markdown/elements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ pub enum CodeLanguage {
Latex,
Lua,
Makefile,
Mermaid,
Markdown,
Nix,
OCaml,
Expand Down Expand Up @@ -245,7 +246,7 @@ pub enum CodeLanguage {

impl CodeLanguage {
pub(crate) fn supports_auto_render(&self) -> bool {
matches!(self, Self::Latex | Self::Typst)
matches!(self, Self::Latex | Self::Typst | Self::Mermaid)
}
}

Expand Down Expand Up @@ -283,6 +284,7 @@ impl FromStr for CodeLanguage {
"lua" => Lua,
"make" => Makefile,
"markdown" => Markdown,
"mermaid" => Mermaid,
"nix" => Nix,
"ocaml" => OCaml,
"perl" => Perl,
Expand Down
10 changes: 5 additions & 5 deletions src/presenter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
},
resource::Resources,
theme::PresentationTheme,
typst::TypstRender,
third_party::ThirdPartyRender,
};
use std::{
collections::HashSet,
Expand Down Expand Up @@ -43,7 +43,7 @@ pub struct Presenter<'a> {
commands: CommandSource,
parser: MarkdownParser<'a>,
resources: Resources,
typst: TypstRender,
third_party: ThirdPartyRender,
code_executor: Rc<CodeExecutor>,
state: PresenterState,
slides_with_pending_widgets: HashSet<usize>,
Expand All @@ -60,7 +60,7 @@ impl<'a> Presenter<'a> {
commands: CommandSource,
parser: MarkdownParser<'a>,
resources: Resources,
typst: TypstRender,
third_party: ThirdPartyRender,
code_executor: Rc<CodeExecutor>,
themes: Themes,
image_printer: Rc<ImagePrinter>,
Expand All @@ -71,7 +71,7 @@ impl<'a> Presenter<'a> {
commands,
parser,
resources,
typst,
third_party,
code_executor,
state: PresenterState::Empty,
slides_with_pending_widgets: HashSet::new(),
Expand Down Expand Up @@ -260,7 +260,7 @@ impl<'a> Presenter<'a> {
let mut presentation = PresentationBuilder::new(
self.default_theme,
&mut self.resources,
&mut self.typst,
&mut self.third_party,
self.code_executor.clone(),
&self.themes,
ImageRegistry(self.image_printer.clone()),
Expand Down
17 changes: 9 additions & 8 deletions src/processing/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{
theme::{
Alignment, AuthorPositioning, ElementType, LoadThemeError, Margin, PresentationTheme, PresentationThemeSet,
},
typst::{TypstRender, TypstRenderError},
third_party::{ThirdPartyRender, TypstRenderError},
};
use image::DynamicImage;
use serde::Deserialize;
Expand Down Expand Up @@ -98,7 +98,7 @@ pub(crate) struct PresentationBuilder<'a> {
code_executor: Rc<CodeExecutor>,
theme: Cow<'a, PresentationTheme>,
resources: &'a mut Resources,
typst: &'a mut TypstRender,
third_party: &'a mut ThirdPartyRender,
slide_state: SlideState,
footer_context: Rc<RefCell<FooterContext>>,
themes: &'a Themes,
Expand All @@ -114,7 +114,7 @@ impl<'a> PresentationBuilder<'a> {
pub(crate) fn new(
default_theme: &'a PresentationTheme,
resources: &'a mut Resources,
typst: &'a mut TypstRender,
third_party: &'a mut ThirdPartyRender,
code_executor: Rc<CodeExecutor>,
themes: &'a Themes,
image_registry: ImageRegistry,
Expand All @@ -130,7 +130,7 @@ impl<'a> PresentationBuilder<'a> {
code_executor,
theme: Cow::Borrowed(default_theme),
resources,
typst,
third_party,
slide_state: Default::default(),
footer_context: Default::default(),
themes,
Expand Down Expand Up @@ -694,8 +694,9 @@ impl<'a> PresentationBuilder<'a> {

fn push_rendered_code(&mut self, code: Code) -> Result<(), BuildError> {
let image = match code.language {
CodeLanguage::Typst => self.typst.render_typst(&code.contents, &self.theme.typst)?,
CodeLanguage::Latex => self.typst.render_latex(&code.contents, &self.theme.typst)?,
CodeLanguage::Typst => self.third_party.render_typst(&code.contents, &self.theme.typst)?,
CodeLanguage::Latex => self.third_party.render_latex(&code.contents, &self.theme.typst)?,
CodeLanguage::Mermaid => self.third_party.render_mermaid(&code.contents, &self.theme.mermaid)?,
_ => panic!("language {:?} should not be renderable", code.language),
};
self.push_image(image);
Expand Down Expand Up @@ -1065,14 +1066,14 @@ mod test {
) -> Result<Presentation, BuildError> {
let theme = PresentationTheme::default();
let mut resources = Resources::new("/tmp", Default::default());
let mut typst = TypstRender::default();
let mut third_party = ThirdPartyRender::default();
let code_executor = Rc::new(CodeExecutor::default());
let themes = Themes::default();
let bindings = KeyBindingsConfig::default();
let builder = PresentationBuilder::new(
&theme,
&mut resources,
&mut typst,
&mut third_party,
code_executor,
&themes,
Default::default(),
Expand Down
1 change: 1 addition & 0 deletions src/render/highlighting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ impl CodeHighlighter {
Lua => "lua",
Makefile => "make",
Markdown => "md",
Mermaid => "txt",
Nix => "nix",
OCaml => "ml",
Perl => "pl",
Expand Down
Loading

0 comments on commit 5dc93f2

Please sign in to comment.