From 5dc93f28a6e732e2fee75c8899ca9c9d3ac8cbba Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Thu, 13 Jun 2024 16:39:39 -0700 Subject: [PATCH 1/2] feat: add support for rendering mermaid diagrams --- config-file-schema.json | 23 +++++++++---- src/custom.rs | 24 ++++++++++++-- src/demo.rs | 6 ++-- src/export.rs | 14 ++++---- src/lib.rs | 4 +-- src/main.rs | 22 ++++++++++--- src/markdown/elements.rs | 4 ++- src/presenter.rs | 10 +++--- src/processing/builder.rs | 17 +++++----- src/render/highlighting.rs | 1 + src/theme.rs | 16 +++++++++- src/{typst.rs => third_party.rs} | 55 ++++++++++++++++++++++++++------ src/tools.rs | 4 +++ 13 files changed, 150 insertions(+), 50 deletions(-) rename src/{typst.rs => third_party.rs} (68%) diff --git a/config-file-schema.json b/config-file-schema.json index b78ccc4f..a11fe342 100644 --- a/config-file-schema.json +++ b/config-file-schema.json @@ -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, @@ -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": { diff --git a/src/custom.rs b/src/custom.rs index a5779a8c..f44697c2 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -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, @@ -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 { diff --git a/src/demo.rs b/src/demo.rs index 6ee342ca..1b811aaf 100644 --- a/src/demo.rs +++ b/src/demo.rs @@ -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}; @@ -100,14 +100,14 @@ impl ThemesDemo { ) -> Result { 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, diff --git a/src/export.rs b/src/export.rs index 31d2d722..5cc4788f 100644 --- a/src/export.rs +++ b/src/export.rs @@ -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}; @@ -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, themes: Themes, options: PresentationBuilderOptions, @@ -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, 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. @@ -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(), @@ -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") } diff --git a/src/lib.rs b/src/lib.rs index a42fb608..d16d5e56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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}, @@ -33,5 +33,5 @@ pub use crate::{ render::highlighting::{CodeHighlighter, HighlightThemeSet}, resource::Resources, theme::{LoadThemeError, PresentationTheme, PresentationThemeSet}, - typst::TypstRender, + third_party::{ThirdPartyConfigs, ThirdPartyRender}, }; diff --git a/src/main.rs b/src/main.rs index 451ad63e..13906df6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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, @@ -211,10 +211,13 @@ fn run(mut cli: Cli) -> Result<(), Box> { 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]); @@ -239,8 +242,17 @@ fn run(mut cli: Cli) -> Result<(), Box> { 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(()) diff --git a/src/markdown/elements.rs b/src/markdown/elements.rs index 2f3ec3f0..216d4b1f 100644 --- a/src/markdown/elements.rs +++ b/src/markdown/elements.rs @@ -217,6 +217,7 @@ pub enum CodeLanguage { Latex, Lua, Makefile, + Mermaid, Markdown, Nix, OCaml, @@ -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) } } @@ -283,6 +284,7 @@ impl FromStr for CodeLanguage { "lua" => Lua, "make" => Makefile, "markdown" => Markdown, + "mermaid" => Mermaid, "nix" => Nix, "ocaml" => OCaml, "perl" => Perl, diff --git a/src/presenter.rs b/src/presenter.rs index 8eb858ee..572f8186 100644 --- a/src/presenter.rs +++ b/src/presenter.rs @@ -15,7 +15,7 @@ use crate::{ }, resource::Resources, theme::PresentationTheme, - typst::TypstRender, + third_party::ThirdPartyRender, }; use std::{ collections::HashSet, @@ -43,7 +43,7 @@ pub struct Presenter<'a> { commands: CommandSource, parser: MarkdownParser<'a>, resources: Resources, - typst: TypstRender, + third_party: ThirdPartyRender, code_executor: Rc, state: PresenterState, slides_with_pending_widgets: HashSet, @@ -60,7 +60,7 @@ impl<'a> Presenter<'a> { commands: CommandSource, parser: MarkdownParser<'a>, resources: Resources, - typst: TypstRender, + third_party: ThirdPartyRender, code_executor: Rc, themes: Themes, image_printer: Rc, @@ -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(), @@ -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()), diff --git a/src/processing/builder.rs b/src/processing/builder.rs index 7d44a161..94ee4607 100644 --- a/src/processing/builder.rs +++ b/src/processing/builder.rs @@ -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; @@ -98,7 +98,7 @@ pub(crate) struct PresentationBuilder<'a> { code_executor: Rc, theme: Cow<'a, PresentationTheme>, resources: &'a mut Resources, - typst: &'a mut TypstRender, + third_party: &'a mut ThirdPartyRender, slide_state: SlideState, footer_context: Rc>, themes: &'a Themes, @@ -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, themes: &'a Themes, image_registry: ImageRegistry, @@ -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, @@ -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); @@ -1065,14 +1066,14 @@ mod test { ) -> Result { 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(), diff --git a/src/render/highlighting.rs b/src/render/highlighting.rs index d20caee5..9b4f92d8 100644 --- a/src/render/highlighting.rs +++ b/src/render/highlighting.rs @@ -137,6 +137,7 @@ impl CodeHighlighter { Lua => "lua", Makefile => "make", Markdown => "md", + Mermaid => "txt", Nix => "nix", OCaml => "ml", Perl => "pl", diff --git a/src/theme.rs b/src/theme.rs index b5629ab9..11af0f62 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -170,7 +170,11 @@ pub struct PresentationTheme { #[serde(default)] pub(crate) typst: TypstStyle, - /// The style for typst auto-rendered code blocks. + /// The style for mermaid auto-rendered code blocks. + #[serde(default)] + pub(crate) mermaid: MermaidStyle, + + /// The style for modals. #[serde(default)] pub(crate) modals: ModalStyle, } @@ -607,6 +611,16 @@ pub(crate) struct TypstStyle { pub(crate) colors: Colors, } +/// Where to position the author's name in the intro slide. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +pub(crate) struct MermaidStyle { + /// The mermaidjs theme to use. + pub(crate) theme: Option, + + /// The background color to use. + pub(crate) background: Option, +} + /// Modals style. #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub(crate) struct ModalStyle { diff --git a/src/typst.rs b/src/third_party.rs similarity index 68% rename from src/typst.rs rename to src/third_party.rs index b10005e5..f88936a7 100644 --- a/src/typst.rs +++ b/src/third_party.rs @@ -1,31 +1,36 @@ use crate::{ + custom::{default_mermaid_scale, default_typst_ppi}, media::{image::Image, printer::RegisterImageError}, style::Color, - theme::TypstStyle, + theme::{MermaidStyle, TypstStyle}, tools::{ExecutionError, ThirdPartyTools}, ImageRegistry, }; use std::{fs, io, path::Path}; use tempfile::tempdir_in; -const DEFAULT_PPI: u32 = 300; const DEFAULT_HORIZONTAL_MARGIN: u16 = 5; const DEFAULT_VERTICAL_MARGIN: u16 = 7; -pub struct TypstRender { - ppi: String, +pub struct ThirdPartyConfigs { + pub typst_ppi: String, + pub mermaid_scale: String, +} + +pub struct ThirdPartyRender { + config: ThirdPartyConfigs, image_registry: ImageRegistry, root_dir: String, } -impl TypstRender { - pub fn new(ppi: u32, image_registry: ImageRegistry, root_dir: &Path) -> Self { +impl ThirdPartyRender { + pub fn new(config: ThirdPartyConfigs, image_registry: ImageRegistry, root_dir: &Path) -> Self { // typst complains about empty paths so we give it a "." if we don't have one. let root_dir = match root_dir.to_string_lossy().to_string() { path if path.is_empty() => ".".into(), path => path, }; - Self { ppi: ppi.to_string(), image_registry, root_dir } + Self { config, image_registry, root_dir } } pub(crate) fn render_typst(&self, input: &str, style: &TypstStyle) -> Result { @@ -47,6 +52,32 @@ impl TypstRender { self.render_typst(&input, style) } + pub(crate) fn render_mermaid(&self, input: &str, style: &MermaidStyle) -> Result { + let workdir = tempdir_in(&self.root_dir)?; + let output_path = workdir.path().join("output.png"); + let input_path = workdir.path().join("input.mmd"); + fs::write(&input_path, input)?; + + ThirdPartyTools::mermaid(&[ + "-i", + &input_path.to_string_lossy(), + "-o", + &output_path.to_string_lossy(), + "-s", + &self.config.mermaid_scale, + "-t", + style.theme.as_deref().unwrap_or("default"), + "-b", + style.background.as_deref().unwrap_or("white"), + ]) + .run()?; + + let png_contents = fs::read(&output_path)?; + let image = image::load_from_memory(&png_contents)?; + let image = self.image_registry.register_image(image)?; + Ok(image) + } + fn render_to_image(&self, base_path: &Path, path: &Path) -> Result { let output_path = base_path.join("output.png"); ThirdPartyTools::typst(&[ @@ -56,7 +87,7 @@ impl TypstRender { "--root", &self.root_dir, "--ppi", - &self.ppi, + &self.config.typst_ppi, &path.to_string_lossy(), &output_path.to_string_lossy(), ]) @@ -91,9 +122,13 @@ impl TypstRender { } } -impl Default for TypstRender { +impl Default for ThirdPartyRender { fn default() -> Self { - Self::new(DEFAULT_PPI, Default::default(), Path::new(".")) + let config = ThirdPartyConfigs { + typst_ppi: default_typst_ppi().to_string(), + mermaid_scale: default_mermaid_scale().to_string(), + }; + Self::new(config, Default::default(), Path::new(".")) } } diff --git a/src/tools.rs b/src/tools.rs index e0df0230..f00b783e 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -17,6 +17,10 @@ impl ThirdPartyTools { Tool::new("typst", args) } + pub(crate) fn mermaid(args: &[&str]) -> Tool { + Tool::new("mmdc", args) + } + pub(crate) fn presenterm_export(args: &[&str]) -> Tool { Tool::new("presenterm-export", args).inherit_stdout() } From 37d8f61cedad00c3f0e789e46ad65f9cddd76687 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Fri, 14 Jun 2024 06:26:43 -0700 Subject: [PATCH 2/2] chore: add better error message if unknown language is found --- src/execute.rs | 7 +------ src/markdown/code.rs | 2 +- src/markdown/elements.rs | 4 ++-- src/processing/builder.rs | 8 ++++---- src/processing/code.rs | 2 +- src/render/highlighting.rs | 2 +- src/third_party.rs | 16 ++++++++-------- 7 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/execute.rs b/src/execute.rs index ed3f2570..a9ad213e 100644 --- a/src/execute.rs +++ b/src/execute.rs @@ -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, @@ -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(); diff --git a/src/markdown/code.rs b/src/markdown/code.rs index fd2a6564..e2d1adb6 100644 --- a/src/markdown/code.rs +++ b/src/markdown/code.rs @@ -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] diff --git a/src/markdown/elements.rs b/src/markdown/elements.rs index 216d4b1f..0b8f3638 100644 --- a/src/markdown/elements.rs +++ b/src/markdown/elements.rs @@ -237,7 +237,7 @@ pub enum CodeLanguage { Terraform, TypeScript, Typst, - Unknown, + Unknown(String), Xml, Yaml, Vue, @@ -308,7 +308,7 @@ impl FromStr for CodeLanguage { "yaml" => Yaml, "vue" => Vue, "zig" => Zig, - _ => Unknown, + other => Unknown(other.to_string()), }; Ok(language) } diff --git a/src/processing/builder.rs b/src/processing/builder.rs index 94ee4607..fbf3b9f7 100644 --- a/src/processing/builder.rs +++ b/src/processing/builder.rs @@ -26,7 +26,7 @@ use crate::{ theme::{ Alignment, AuthorPositioning, ElementType, LoadThemeError, Margin, PresentationTheme, PresentationThemeSet, }, - third_party::{ThirdPartyRender, TypstRenderError}, + third_party::{ThirdPartyRender, ThirdPartyRenderError}, }; use image::DynamicImage; use serde::Deserialize; @@ -706,7 +706,7 @@ impl<'a> PresentationBuilder<'a> { fn highlight_lines(&self, code: &Code) -> (Vec, Rc>) { let lines = CodePreparer::new(&self.theme).prepare(code); let block_length = lines.iter().map(|line| line.width()).max().unwrap_or(0); - let mut empty_highlighter = self.highlighter.language_highlighter(&CodeLanguage::Unknown); + let mut empty_highlighter = self.highlighter.language_highlighter(&CodeLanguage::Unknown(String::new())); let mut code_highlighter = self.highlighter.language_highlighter(&code.language); let padding_style = { let mut highlighter = self.highlighter.language_highlighter(&CodeLanguage::Rust); @@ -910,8 +910,8 @@ pub enum BuildError { #[error("error parsing command at line {line}: {error}")] CommandParse { line: usize, error: CommandParseError }, - #[error("typst render failed: {0}")] - TypstRender(#[from] TypstRenderError), + #[error("third party render failed: {0}")] + ThirdPartyRender(#[from] ThirdPartyRenderError), #[error("language {0:?} does not support execution")] UnsupportedExecution(CodeLanguage), diff --git a/src/processing/code.rs b/src/processing/code.rs index 14882aa5..c39f43ea 100644 --- a/src/processing/code.rs +++ b/src/processing/code.rs @@ -189,7 +189,7 @@ mod test { let input_lines = "hi\n".repeat(total_lines); let code = Code { contents: input_lines, - language: CodeLanguage::Unknown, + language: CodeLanguage::Unknown("".to_string()), attributes: CodeAttributes { line_numbers: true, ..Default::default() }, }; let lines = CodePreparer { theme: &Default::default() }.prepare(&code); diff --git a/src/render/highlighting.rs b/src/render/highlighting.rs index 9b4f92d8..0f74e045 100644 --- a/src/render/highlighting.rs +++ b/src/render/highlighting.rs @@ -157,7 +157,7 @@ impl CodeHighlighter { TypeScript => "ts", Typst => "txt", // default to plain text so we get the same look&feel - Unknown => "txt", + Unknown(_) => "txt", Vue => "vue", Xml => "xml", Yaml => "yaml", diff --git a/src/third_party.rs b/src/third_party.rs index f88936a7..ec13f1b4 100644 --- a/src/third_party.rs +++ b/src/third_party.rs @@ -33,7 +33,7 @@ impl ThirdPartyRender { Self { config, image_registry, root_dir } } - pub(crate) fn render_typst(&self, input: &str, style: &TypstStyle) -> Result { + pub(crate) fn render_typst(&self, input: &str, style: &TypstStyle) -> Result { let workdir = tempdir_in(&self.root_dir)?; let mut typst_input = Self::generate_page_header(style)?; typst_input.push_str(input); @@ -43,7 +43,7 @@ impl ThirdPartyRender { self.render_to_image(workdir.path(), &input_path) } - pub(crate) fn render_latex(&self, input: &str, style: &TypstStyle) -> Result { + pub(crate) fn render_latex(&self, input: &str, style: &TypstStyle) -> Result { let output = ThirdPartyTools::pandoc(&["--from", "latex", "--to", "typst"]) .stdin(input.as_bytes().into()) .run_and_capture_stdout()?; @@ -52,7 +52,7 @@ impl ThirdPartyRender { self.render_typst(&input, style) } - pub(crate) fn render_mermaid(&self, input: &str, style: &MermaidStyle) -> Result { + pub(crate) fn render_mermaid(&self, input: &str, style: &MermaidStyle) -> Result { let workdir = tempdir_in(&self.root_dir)?; let output_path = workdir.path().join("output.png"); let input_path = workdir.path().join("input.mmd"); @@ -78,7 +78,7 @@ impl ThirdPartyRender { Ok(image) } - fn render_to_image(&self, base_path: &Path, path: &Path) -> Result { + fn render_to_image(&self, base_path: &Path, path: &Path) -> Result { let output_path = base_path.join("output.png"); ThirdPartyTools::typst(&[ "compile", @@ -99,7 +99,7 @@ impl ThirdPartyRender { Ok(image) } - fn generate_page_header(style: &TypstStyle) -> Result { + fn generate_page_header(style: &TypstStyle) -> Result { let x_margin = style.horizontal_margin.unwrap_or(DEFAULT_HORIZONTAL_MARGIN); let y_margin = style.vertical_margin.unwrap_or(DEFAULT_VERTICAL_MARGIN); let background = @@ -114,10 +114,10 @@ impl ThirdPartyRender { Ok(header) } - fn as_typst_color(color: &Color) -> Result { + fn as_typst_color(color: &Color) -> Result { match color.as_rgb() { Some((r, g, b)) => Ok(format!("rgb(\"#{r:02x}{g:02x}{b:02x}\")")), - None => Err(TypstRenderError::UnsupportedColor(color.to_string())), + None => Err(ThirdPartyRenderError::UnsupportedColor(color.to_string())), } } } @@ -133,7 +133,7 @@ impl Default for ThirdPartyRender { } #[derive(Debug, thiserror::Error)] -pub enum TypstRenderError { +pub enum ThirdPartyRenderError { #[error(transparent)] Execution(#[from] ExecutionError),