Skip to content

Commit

Permalink
feat: allow auto rendering code snippets (#418)
Browse files Browse the repository at this point in the history
This adds a new `auto_render_languages`
[option](https://mfontanini.github.io/presenterm/guides/configuration.html#options)
(meaning it can be configured in the config file or in the presentation
itself) that specifies a list of languages for which the `+render`
attribute is implied and are therefore automatically rendered. This
means for example this presentation would have its mermaid diagram
automatically rendered as an image:

~~~markdown
---
options:
    auto_render_languages:
        - mermaid
---

```mermaid
sequenceDiagram
    bob ->> mike: oh hi
```
~~~

Fixes #416
  • Loading branch information
mfontanini authored Jan 20, 2025
2 parents fd9a128 + 1f5acd8 commit 954f112
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 10 deletions.
95 changes: 95 additions & 0 deletions config-file-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down Expand Up @@ -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": {
Expand Down
19 changes: 10 additions & 9 deletions src/code/snippet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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))
Expand All @@ -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,
Expand All @@ -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:") => {
Expand Down Expand Up @@ -372,7 +373,7 @@ enum SnippetAttribute {
LineNumbers,
Exec,
ExecReplace,
AutoRender,
Render,
HighlightedLines(Vec<HighlightGroup>),
Width(Percent),
NoBackground,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)));
}

Expand Down
3 changes: 3 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ pub struct OptionsConfig {

/// Whether to be strict about parsing the presentation's front matter.
pub strict_front_matter_parsing: Option<bool>,

/// Assume snippets for these languages contain `+render` and render them automatically.
pub auto_render_languages: Vec<SnippetLanguage>,
}

#[derive(Clone, Debug, Default, Deserialize, JsonSchema)]
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/presentation/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<SnippetLanguage>,
}

impl PresentationBuilderOptions {
Expand All @@ -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;
}
}
}

Expand All @@ -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(),
}
}
}
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 954f112

Please sign in to comment.