Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for rendering mermaid diagrams #268

Merged
merged 2 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -236,7 +237,7 @@ pub enum CodeLanguage {
Terraform,
TypeScript,
Typst,
Unknown,
Unknown(String),
Xml,
Yaml,
Vue,
Expand All @@ -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 All @@ -306,7 +308,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
Loading