Skip to content

Commit

Permalink
Merge pull request #268 from mfontanini/feat/mermaid-graphs
Browse files Browse the repository at this point in the history
feat: add support for rendering mermaid diagrams
  • Loading branch information
mfontanini authored Jun 20, 2024
2 parents 98f4402 + 37d8f61 commit 33c9033
Show file tree
Hide file tree
Showing 16 changed files with 166 additions and 71 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
7 changes: 1 addition & 6 deletions src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl CodeExecutor {
return Err(LoadExecutorsError::InvalidExecutor(path, "non .sh extension"));
}
let language: CodeLanguage = match name.parse() {
Ok(CodeLanguage::Unknown) => {
Ok(CodeLanguage::Unknown(_)) => {
return Err(LoadExecutorsError::InvalidExecutor(path, "unknown language"));
}
Ok(language) => language,
Expand Down Expand Up @@ -295,11 +295,6 @@ echo 'hello world'
assert_eq!(state.output, expected_lines);
}

#[test]
fn validate_builtin_executors() {
assert!(EXECUTORS.get(&CodeLanguage::Unknown).is_none(), "unknown language in executors");
}

#[test]
fn custom_executor() {
let dir = tempdir().unwrap();
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
2 changes: 1 addition & 1 deletion src/markdown/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ mod test {

#[test]
fn unknown_language() {
assert_eq!(parse_language("potato"), CodeLanguage::Unknown);
assert_eq!(parse_language("potato"), CodeLanguage::Unknown("potato".to_string()));
}

#[test]
Expand Down
8 changes: 5 additions & 3 deletions 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 All @@ -237,7 +238,7 @@ pub enum CodeLanguage {
Terraform,
TypeScript,
Typst,
Unknown,
Unknown(String),
Xml,
Yaml,
Vue,
Expand All @@ -246,7 +247,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 @@ -284,6 +285,7 @@ impl FromStr for CodeLanguage {
"lua" => Lua,
"make" => Makefile,
"markdown" => Markdown,
"mermaid" => Mermaid,
"nix" => Nix,
"ocaml" => OCaml,
"perl" => Perl,
Expand All @@ -308,7 +310,7 @@ impl FromStr for CodeLanguage {
"yaml" => Yaml,
"vue" => Vue,
"zig" => Zig,
_ => Unknown,
other => Unknown(other.to_string()),
};
Ok(language)
}
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
Loading

0 comments on commit 33c9033

Please sign in to comment.