diff --git a/config-file-schema.json b/config-file-schema.json index 75a4174d..30764191 100644 --- a/config-file-schema.json +++ b/config-file-schema.json @@ -279,7 +279,17 @@ }, "OptionsConfig": { "type": "object", + "required": [ + "auto_render_languages" + ], "properties": { + "auto_render_languages": { + "description": "Assume snippets for these languages contain `+render` and render them automatically.", + "type": "array", + "items": { + "$ref": "#/definitions/SnippetLanguage" + } + }, "command_prefix": { "description": "The prefix to use for commands.", "type": [ @@ -388,6 +398,91 @@ }, "additionalProperties": false }, + "SnippetLanguage": { + "description": "The language of a code snippet.", + "oneOf": [ + { + "type": "string", + "enum": [ + "Ada", + "Asp", + "Awk", + "Bash", + "BatchFile", + "C", + "CMake", + "Crontab", + "CSharp", + "Clojure", + "Cpp", + "Css", + "DLang", + "Diff", + "Docker", + "Dotenv", + "Elixir", + "Elm", + "Erlang", + "File", + "Fish", + "Go", + "GraphQL", + "Haskell", + "Html", + "Java", + "JavaScript", + "Json", + "Kotlin", + "Latex", + "Lua", + "Makefile", + "Mermaid", + "Markdown", + "Nix", + "Nushell", + "OCaml", + "Perl", + "Php", + "Protobuf", + "Puppet", + "Python", + "R", + "Racket", + "Ruby", + "Rust", + "RustScript", + "Scala", + "Shell", + "Sql", + "Swift", + "Svelte", + "Tcl", + "Terraform", + "Toml", + "TypeScript", + "Typst", + "Xml", + "Yaml", + "Verilog", + "Vue", + "Zig", + "Zsh" + ] + }, + { + "type": "object", + "required": [ + "Unknown" + ], + "properties": { + "Unknown": { + "type": "string" + } + }, + "additionalProperties": false + } + ] + }, "SnippetRenderConfig": { "type": "object", "properties": { diff --git a/src/code/snippet.rs b/src/code/snippet.rs index 589652ea..6c3e51cf 100644 --- a/src/code/snippet.rs +++ b/src/code/snippet.rs @@ -16,6 +16,7 @@ use crate::{ }, theme::{Alignment, CodeBlockStyle}, }; +use schemars::JsonSchema; use serde::Deserialize; use serde_with::DeserializeFromStr; use std::{cell::RefCell, convert::Infallible, fmt::Write, ops::Range, path::PathBuf, rc::Rc, str::FromStr}; @@ -208,7 +209,7 @@ impl SnippetParser { fn parse_block_info(input: &str) -> ParseResult<(SnippetLanguage, SnippetAttributes)> { let (language, input) = Self::parse_language(input); let attributes = Self::parse_attributes(input)?; - if attributes.width.is_some() && !attributes.auto_render { + if attributes.width.is_some() && !attributes.render { return Err(SnippetBlockParseError::NotRenderSnippet("width")); } Ok((language, attributes)) @@ -234,7 +235,7 @@ impl SnippetParser { SnippetAttribute::LineNumbers => attributes.line_numbers = true, SnippetAttribute::Exec => attributes.execute = true, SnippetAttribute::ExecReplace => attributes.execute_replace = true, - SnippetAttribute::AutoRender => attributes.auto_render = true, + SnippetAttribute::Render => attributes.render = true, SnippetAttribute::NoBackground => attributes.no_background = true, SnippetAttribute::AcquireTerminal => attributes.acquire_terminal = true, SnippetAttribute::HighlightedLines(lines) => attributes.highlight_groups = lines, @@ -258,7 +259,7 @@ impl SnippetParser { "line_numbers" => SnippetAttribute::LineNumbers, "exec" => SnippetAttribute::Exec, "exec_replace" => SnippetAttribute::ExecReplace, - "render" => SnippetAttribute::AutoRender, + "render" => SnippetAttribute::Render, "no_background" => SnippetAttribute::NoBackground, "acquire_terminal" => SnippetAttribute::AcquireTerminal, token if token.starts_with("width:") => { @@ -372,7 +373,7 @@ enum SnippetAttribute { LineNumbers, Exec, ExecReplace, - AutoRender, + Render, HighlightedLines(Vec), Width(Percent), NoBackground, @@ -417,7 +418,7 @@ impl Snippet { } /// The language of a code snippet. -#[derive(Clone, Debug, PartialEq, Eq, EnumIter, PartialOrd, Ord, DeserializeFromStr)] +#[derive(Clone, Debug, PartialEq, Eq, EnumIter, PartialOrd, Ord, DeserializeFromStr, JsonSchema)] pub enum SnippetLanguage { Ada, Asp, @@ -569,11 +570,11 @@ pub(crate) struct SnippetAttributes { /// of its execution. pub(crate) execute_replace: bool, - /// Whether a snippet is marked to be auto rendered. + /// Whether a snippet is marked to be rendered. /// - /// An auto rendered snippet is transformed during parsing, leading to some visual + /// A rendered snippet is transformed during parsing, leading to some visual /// representation of it being shown rather than the original code. - pub(crate) auto_render: bool, + pub(crate) render: bool, /// Whether the snippet should show line numbers. pub(crate) line_numbers: bool, @@ -754,7 +755,7 @@ mod test { #[test] fn parse_width() { let attributes = parse_attributes("mermaid +width:50% +render"); - assert!(attributes.auto_render); + assert!(attributes.render); assert_eq!(attributes.width, Some(Percent(50))); } diff --git a/src/config.rs b/src/config.rs index d13db379..67df8fb9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -129,6 +129,9 @@ pub struct OptionsConfig { /// Whether to be strict about parsing the presentation's front matter. pub strict_front_matter_parsing: Option, + + /// Assume snippets for these languages contain `+render` and render them automatically. + pub auto_render_languages: Vec, } #[derive(Clone, Debug, Default, Deserialize, JsonSchema)] diff --git a/src/main.rs b/src/main.rs index 76b54c3c..f271f752 100644 --- a/src/main.rs +++ b/src/main.rs @@ -231,6 +231,7 @@ fn make_builder_options( enable_snippet_execution: config.snippet.exec.enable, enable_snippet_execution_replace: config.snippet.exec_replace.enable, render_speaker_notes_only: speaker_notes_mode.is_some_and(|mode| matches!(mode, SpeakerNotesMode::Receiver)), + auto_render_languages: config.options.auto_render_languages.clone(), } } diff --git a/src/presentation/builder.rs b/src/presentation/builder.rs index c8ab9285..f0dc5952 100644 --- a/src/presentation/builder.rs +++ b/src/presentation/builder.rs @@ -72,6 +72,7 @@ pub struct PresentationBuilderOptions { pub enable_snippet_execution: bool, pub enable_snippet_execution_replace: bool, pub render_speaker_notes_only: bool, + pub auto_render_languages: Vec, } impl PresentationBuilderOptions { @@ -87,6 +88,9 @@ impl PresentationBuilderOptions { if let Some(prefix) = options.image_attributes_prefix { self.image_attribute_prefix = prefix; } + if !options.auto_render_languages.is_empty() { + self.auto_render_languages = options.auto_render_languages; + } } } @@ -105,6 +109,7 @@ impl Default for PresentationBuilderOptions { enable_snippet_execution: false, enable_snippet_execution_replace: false, render_speaker_notes_only: false, + auto_render_languages: Default::default(), } } } @@ -784,7 +789,7 @@ impl<'a> PresentationBuilder<'a> { } self.push_differ(snippet.contents.clone()); - if snippet.attributes.auto_render { + if snippet.attributes.render || self.options.auto_render_languages.contains(&snippet.language) { return self.push_rendered_code(snippet, source_position); } else if snippet.attributes.execute_replace && self.options.enable_snippet_execution_replace { return self.push_code_execution(snippet, 0, ExecutionMode::ReplaceSnippet);