Skip to content

Commit

Permalink
Merge pull request #299 from gjtorikian/support-plugins-for-nodes
Browse files Browse the repository at this point in the history
Support plugins when processing node tree
  • Loading branch information
gjtorikian committed Jun 3, 2024
2 parents 2fd0c39 + d44a174 commit 1b74829
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 141 deletions.
142 changes: 31 additions & 111 deletions ext/commonmarker/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,15 @@
extern crate core;

use std::path::PathBuf;

use ::syntect::highlighting::ThemeSet;
use comrak::{
adapters::SyntaxHighlighterAdapter,
markdown_to_html, markdown_to_html_with_plugins, parse_document,
plugins::syntect::{SyntectAdapter, SyntectAdapterBuilder},
ComrakOptions, ComrakPlugins,
};
use magnus::{
define_module, exception, function, r_hash::ForEach, scan_args, Error, RHash, Symbol, Value,
};
use comrak::{markdown_to_html_with_plugins, parse_document, ComrakOptions};
use magnus::{define_module, function, r_hash::ForEach, scan_args, Error, RHash, Symbol, Value};
use node::CommonmarkerNode;
use plugins::syntax_highlighting::construct_syntax_highlighter_from_plugin;

mod options;
use options::iterate_options_hash;

mod plugins;
use plugins::{
syntax_highlighting::{fetch_syntax_highlighter_path, fetch_syntax_highlighter_theme},
SYNTAX_HIGHLIGHTER_PLUGIN,
};

use typed_arena::Arena;

mod node;
Expand Down Expand Up @@ -63,6 +51,32 @@ fn commonmark_to_html(args: &[Value]) -> Result<String, magnus::Error> {
)?;
let (rb_options, rb_plugins) = kwargs.optional;

let comrak_options = match format_options(rb_options) {
Ok(options) => options,
Err(err) => return Err(err),
};

let mut comrak_plugins = comrak::Plugins::default();

let syntect_adapter = match construct_syntax_highlighter_from_plugin(rb_plugins) {
Ok(Some(adapter)) => Some(adapter),
Ok(None) => None,
Err(err) => return Err(err),
};

match syntect_adapter {
Some(ref adapter) => comrak_plugins.render.codefence_syntax_highlighter = Some(adapter),
None => comrak_plugins.render.codefence_syntax_highlighter = None,
}

Ok(markdown_to_html_with_plugins(
&rb_commonmark,
&comrak_options,
&comrak_plugins,
))
}

fn format_options(rb_options: Option<RHash>) -> Result<comrak::Options, magnus::Error> {
let mut comrak_options = ComrakOptions::default();

if let Some(rb_options) = rb_options {
Expand All @@ -72,101 +86,7 @@ fn commonmark_to_html(args: &[Value]) -> Result<String, magnus::Error> {
})?;
}

if let Some(rb_plugins) = rb_plugins {
let mut comrak_plugins = ComrakPlugins::default();

let syntax_highlighter: Option<&dyn SyntaxHighlighterAdapter>;
let adapter: SyntectAdapter;

let theme = match rb_plugins.get(Symbol::new(SYNTAX_HIGHLIGHTER_PLUGIN)) {
Some(syntax_highlighter_options) => {
match fetch_syntax_highlighter_theme(syntax_highlighter_options) {
Ok(theme) => theme,
Err(e) => {
return Err(e);
}
}
}
None => None, // no `syntax_highlighter:` defined
};

match theme {
None => syntax_highlighter = None,
Some(theme) => {
if theme.is_empty() {
// no theme? uss css classes
adapter = SyntectAdapter::new(None);
syntax_highlighter = Some(&adapter);
} else {
let path = match rb_plugins.get(Symbol::new(SYNTAX_HIGHLIGHTER_PLUGIN)) {
Some(syntax_highlighter_options) => {
fetch_syntax_highlighter_path(syntax_highlighter_options)?
}
None => PathBuf::from("".to_string()), // no `syntax_highlighter:` defined
};

if path.exists() {
if !path.is_dir() {
return Err(Error::new(
exception::arg_error(),
"`path` needs to be a directory",
));
}

let builder = SyntectAdapterBuilder::new();
let mut ts = ThemeSet::load_defaults();

match ts.add_from_folder(&path) {
Ok(_) => {}
Err(e) => {
return Err(Error::new(
exception::arg_error(),
format!("failed to load theme set from path: {e}"),
));
}
}

// check if the theme exists in the dir
match ts.themes.get(&theme) {
Some(theme) => theme,
None => {
return Err(Error::new(
exception::arg_error(),
format!("theme `{}` does not exist", theme),
));
}
};

adapter = builder.theme_set(ts).theme(&theme).build();

syntax_highlighter = Some(&adapter);
} else {
// no path? default theme lookup
ThemeSet::load_defaults()
.themes
.get(&theme)
.ok_or_else(|| {
Error::new(
exception::arg_error(),
format!("theme `{}` does not exist", theme),
)
})?;
adapter = SyntectAdapter::new(Some(&theme));
syntax_highlighter = Some(&adapter);
}
}
}
}
comrak_plugins.render.codefence_syntax_highlighter = syntax_highlighter;

Ok(markdown_to_html_with_plugins(
&rb_commonmark,
&comrak_options,
&comrak_plugins,
))
} else {
Ok(markdown_to_html(&rb_commonmark, &comrak_options))
}
Ok(comrak_options)
}

#[magnus::init]
Expand Down
71 changes: 50 additions & 21 deletions ext/commonmarker/src/node.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
use comrak::arena_tree::Node as ComrakNode;
use comrak::nodes::{
Ast as ComrakAst, AstNode as ComrakAstNode, ListDelimType, ListType, NodeCode, NodeCodeBlock,
NodeDescriptionItem, NodeFootnoteDefinition, NodeFootnoteReference, NodeHeading, NodeHtmlBlock,
NodeLink, NodeList, NodeMath, NodeMultilineBlockQuote, NodeShortCode, NodeTable,
NodeValue as ComrakNodeValue, NodeWikiLink, TableAlignment,
};
use comrak::{arena_tree::Node as ComrakNode, ComrakOptions};
use magnus::RArray;
use magnus::{
function, method, r_hash::ForEach, scan_args, Module, Object, RHash, RModule, Symbol, Value,
};
use magnus::{function, method, scan_args, Module, Object, RHash, RModule, Symbol, Value};
use rctree::Node;
use typed_arena::Arena;

use std::cell::RefCell;

use crate::options::iterate_options_hash;
use crate::format_options;

use crate::plugins::syntax_highlighting::construct_syntax_highlighter_from_plugin;

#[derive(Debug, Clone)]
#[magnus::wrap(class = "Commonmarker::Node::Ast", size, mark)]
Expand Down Expand Up @@ -905,15 +905,24 @@ impl CommonmarkerNode {
&[],
&["options", "plugins"],
)?;
let (rb_options, _rb_plugins) = kwargs.optional;
let (rb_options, rb_plugins) = kwargs.optional;

let comrak_options = match format_options(rb_options) {
Ok(options) => options,
Err(err) => return Err(err),
};

let mut comrak_plugins = comrak::Plugins::default();

let mut comrak_options = ComrakOptions::default();
let syntect_adapter = match construct_syntax_highlighter_from_plugin(rb_plugins) {
Ok(Some(adapter)) => Some(adapter),
Ok(None) => None,
Err(err) => return Err(err),
};

if let Some(rb_options) = rb_options {
rb_options.foreach(|key: Symbol, value: RHash| {
iterate_options_hash(&mut comrak_options, key, value)?;
Ok(ForEach::Continue)
})?;
match syntect_adapter {
Some(ref adapter) => comrak_plugins.render.codefence_syntax_highlighter = Some(adapter),
None => comrak_plugins.render.codefence_syntax_highlighter = None,
}

let arena: Arena<ComrakAstNode> = Arena::new();
Expand Down Expand Up @@ -946,7 +955,12 @@ impl CommonmarkerNode {
}

let mut output = vec![];
match comrak::format_html(&comrak_root_node, &comrak_options, &mut output) {
match comrak::format_html_with_plugins(
&comrak_root_node,
&comrak_options,
&mut output,
&comrak_plugins,
) {
Ok(_) => {}
Err(e) => {
return Err(magnus::Error::new(
Expand All @@ -973,15 +987,25 @@ impl CommonmarkerNode {
&[],
&["options", "plugins"],
)?;
let (rb_options, _rb_plugins) = kwargs.optional;
let (rb_options, rb_plugins) = kwargs.optional;

let _comrak_options = format_options(rb_options);
let comrak_options = match format_options(rb_options) {
Ok(options) => options,
Err(err) => return Err(err),
};

let mut comrak_options = ComrakOptions::default();
let mut comrak_plugins = comrak::Plugins::default();

let syntect_adapter = match construct_syntax_highlighter_from_plugin(rb_plugins) {
Ok(Some(adapter)) => Some(adapter),
Ok(None) => None,
Err(err) => return Err(err),
};

if let Some(rb_options) = rb_options {
rb_options.foreach(|key: Symbol, value: RHash| {
iterate_options_hash(&mut comrak_options, key, value)?;
Ok(ForEach::Continue)
})?;
match syntect_adapter {
Some(ref adapter) => comrak_plugins.render.codefence_syntax_highlighter = Some(adapter),
None => comrak_plugins.render.codefence_syntax_highlighter = None,
}

let arena: Arena<ComrakAstNode> = Arena::new();
Expand Down Expand Up @@ -1014,7 +1038,12 @@ impl CommonmarkerNode {
}

let mut output = vec![];
match comrak::format_commonmark(&comrak_root_node, &comrak_options, &mut output) {
match comrak::format_commonmark_with_plugins(
&comrak_root_node,
&comrak_options,
&mut output,
&comrak_plugins,
) {
Ok(_) => {}
Err(e) => {
return Err(magnus::Error::new(
Expand Down
3 changes: 3 additions & 0 deletions ext/commonmarker/src/plugins.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
pub mod syntax_highlighting;

pub const SYNTAX_HIGHLIGHTER_PLUGIN: &str = "syntax_highlighter";

pub const SYNTAX_HIGHLIGHTER_PLUGIN_THEME_KEY: &str = "theme";
pub const SYNTAX_HIGHLIGHTER_PLUGIN_PATH_KEY: &str = "path";
Loading

0 comments on commit 1b74829

Please sign in to comment.