diff --git a/components/rendering/src/markdown.rs b/components/rendering/src/markdown.rs
index 56f229ec..4181c2dc 100644
--- a/components/rendering/src/markdown.rs
+++ b/components/rendering/src/markdown.rs
@@ -242,7 +242,32 @@ pub fn markdown_to_html(
match event {
Event::Text(text) => {
if let Some(ref mut code_block) = code_block {
- let html = code_block.highlight(&text);
+ let html;
+ if contains_shortcode(text.as_ref()) {
+ let mut accumulated_block = String::new();
+ // mark the start of the code block events
+ let stack_start = events.len();
+ render_shortcodes!(true, text, range);
+ // after rendering the shortcodes we will collect all the text events
+ // and re-render them as code blocks
+ for event in events[stack_start..].iter() {
+ match event {
+ Event::Html(t) | Event::Text(t) => accumulated_block += t,
+ _ => {
+ error = Some(Error::msg(format!(
+ "Unexpected event while expanding the code block: {:?}",
+ event
+ )));
+ break;
+ }
+ }
+ }
+ html = code_block.highlight(&accumulated_block);
+ // remove all the original events from shortcode rendering
+ events.truncate(stack_start);
+ } else {
+ html = code_block.highlight(&text);
+ }
events.push(Event::Html(html.into()));
} else {
let text = if context.config.markdown.render_emoji {
diff --git a/components/rendering/tests/codeblock_shortcode_mix.rs b/components/rendering/tests/codeblock_shortcode_mix.rs
new file mode 100644
index 00000000..e1781913
--- /dev/null
+++ b/components/rendering/tests/codeblock_shortcode_mix.rs
@@ -0,0 +1,271 @@
+use std::collections::HashMap;
+
+use config::Config;
+use front_matter::InsertAnchor;
+use templates::ZOLA_TERA;
+use rendering::{render_content, RenderContext};
+
+#[test]
+fn can_render_shortcode_in_codeblock() {
+ let permalinks_ctx = HashMap::new();
+ let config = Config::default_for_test();
+ let mut context = RenderContext::new(
+ &ZOLA_TERA,
+ &config,
+ &config.default_language,
+ "",
+ &permalinks_ctx,
+ InsertAnchor::None,
+ );
+ let shortcode_def = utils::templates::get_shortcodes(&ZOLA_TERA);
+ context.set_shortcode_definitions(&shortcode_def);
+ // simple case
+ let res = render_content(
+ r#"
+```
+{{ youtube(id="dQw4w9WgXcQ") }}
+```
+ "#,
+ &context,
+ )
+ .unwrap();
+ assert_eq!(
+ res.body,
+ "
<div >\n <iframe src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>\n</div>\n\n
\n"
+ );
+ // mixed with other contents
+ let res = render_content(
+ r#"
+```
+
+{{ youtube(id="dQw4w9WgXcQ") }}
+
+```
+ "#,
+ &context,
+ )
+ .unwrap();
+ assert_eq!(
+ res.body,
+ "<div id="custom-attr">\n<div >\n <iframe src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>\n</div>\n\n</div>\n
\n"
+ );
+ // mixed content with syntax and line numbers
+ let res = render_content(
+ r#"
+```html,linenos
+
+{{ youtube(id="dQw4w9WgXcQ") }}
+
+```
+ "#,
+ &context,
+ )
+ .unwrap();
+ assert_eq!(
+ res.body,
+ "1 | <div id="custom-attr">\n |
2 | <div >\n |
3 | <iframe src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>\n |
4 | </div>\n |
5 | \n |
6 | </div>\n |
\n"
+ );
+}
+
+#[test]
+fn can_render_multiple_shortcodes_in_codeblock() {
+ let permalinks_ctx = HashMap::new();
+ let config = Config::default_for_test();
+ let mut context = RenderContext::new(
+ &ZOLA_TERA,
+ &config,
+ &config.default_language,
+ "",
+ &permalinks_ctx,
+ InsertAnchor::None,
+ );
+ let shortcode_def = utils::templates::get_shortcodes(&ZOLA_TERA);
+ context.set_shortcode_definitions(&shortcode_def);
+ // simple case
+ let res = render_content(
+ r#"
+```
+{{ youtube(id="dQw4w9WgXcQ") }}
+{{ gist(url="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57", class="gist") }}
+```
+ "#,
+ &context,
+ )
+ .unwrap();
+ assert_eq!(
+ res.body,
+ "<div >\n <iframe src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>\n</div>\n\n<div class="gist">\n <script src="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57.js"></script>\n</div>\n\n
\n"
+ );
+ // mixed with other contents
+ let res = render_content(
+ r#"
+```
+text 1
+{{ youtube(id="dQw4w9WgXcQ") }}
+text 2
+{{ gist(url="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57", class="gist") }}
+text 3
+```
+ "#,
+ &context,
+ )
+ .unwrap();
+ assert_eq!(
+ res.body,
+ "text 1\n<div >\n <iframe src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>\n</div>\n\ntext 2\n<div class="gist">\n <script src="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57.js"></script>\n</div>\n\ntext 3\n
\n"
+ );
+ // mixed content with syntax and line numbers
+ let res = render_content(
+ r#"
+```html,linenos
+text 1
+{{ youtube(id="dQw4w9WgXcQ") }}
+text 2
+{{ gist(url="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57", class="gist") }}
+text 3
+```
+ "#,
+ &context,
+ )
+ .unwrap();
+ assert_eq!(
+ res.body,
+r#"1 | <span>text 1</span>
+ |
2 | <div >
+ |
3 | <iframe src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
+ |
4 | </div>
+ |
5 |
+ |
6 | <span>text 2</span>
+ |
7 | <div class="gist">
+ |
8 | <script src="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57.js"></script>
+ |
9 | </div>
+ |
10 |
+ |
11 | <span>text 3</span>
+ |
+"#
+ );
+}
+
+#[test]
+fn is_highlighting_linenos_still_working() {
+ let permalinks_ctx = HashMap::new();
+ let mut config = Config::default_for_test();
+ config.markdown.highlight_code = true;
+ let mut context = RenderContext::new(
+ &ZOLA_TERA,
+ &config,
+ &config.default_language,
+ "",
+ &permalinks_ctx,
+ InsertAnchor::None,
+ );
+ let shortcode_def = utils::templates::get_shortcodes(&ZOLA_TERA);
+ context.set_shortcode_definitions(&shortcode_def);
+ // single shortcode mixed with syntax and line numbers
+ let res = render_content(
+ r#"
+```html,linenos
+
+{{ youtube(id="dQw4w9WgXcQ") }}
+
+```
+ "#,
+ &context,
+ )
+ .unwrap();
+ assert_eq!(
+ res.body,
+ "1 | <div id="custom-attr">\n |
2 | <div >\n |
3 | <iframe src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>\n |
4 | </div>\n |
5 | \n |
6 | </div>\n |
\n"
+ );
+ // multiple shortcode mixed with syntax and line numbers
+ let res = render_content(
+ r#"
+```html,linenos
+text 1
+{{ youtube(id="dQw4w9WgXcQ") }}
+text 2
+{{ gist(url="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57", class="gist") }}
+text 3
+```
+ "#,
+ &context,
+ )
+ .unwrap();
+ assert_eq!(
+ res.body,
+r#"1 | <span>text 1</span>
+ |
2 | <div >
+ |
3 | <iframe src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
+ |
4 | </div>
+ |
5 |
+ |
6 | <span>text 2</span>
+ |
7 | <div class="gist">
+ |
8 | <script src="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57.js"></script>
+ |
9 | </div>
+ |
10 |
+ |
11 | <span>text 3</span>
+ |
+"#
+ );
+}
+
+#[test]
+fn codeblock_shortcode_mix_all_stars() {
+ let permalinks_ctx = HashMap::new();
+ let mut config = Config::default_for_test();
+ config.markdown.highlight_code = true;
+ let mut context = RenderContext::new(
+ &ZOLA_TERA,
+ &config,
+ &config.default_language,
+ "",
+ &permalinks_ctx,
+ InsertAnchor::None,
+ );
+ let shortcode_def = utils::templates::get_shortcodes(&ZOLA_TERA);
+ context.set_shortcode_definitions(&shortcode_def);
+ // single shortcode mixed with syntax and line numbers
+ let res = render_content(
+ r#"
+```html,linenos
+{{/* before(texts="1") */}}
+Normally people would not write something & like <> this:
+
+An inline {{ youtube(id="dQw4w9WgXcQ", autoplay=true, class="youtube") }} shortcode
+
+Plain text in-between
+{%/* quote(author="Vincent") */%}
+A quote
+{%/* end */%}
+{{ gist(url="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57", class="gist") }}
+{# A Tera comment, you should see it #}
+
+```
+ "#,
+ &context,
+ )
+ .unwrap();
+ assert_eq!(
+ res.body,
+r#"1 | <a href="javascript:void(0);">{{ before(texts="1") }}</a>
+ |
2 | Normally people would not write something & like <> this:
+ |
3 | <div id="custom-attr">
+ |
4 | An inline <div class="youtube">
+ |
5 | <iframe src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ?autoplay=1" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
+ |
6 | </div>
+ |
7 | shortcode
+ |
8 | </div>
+ |
9 | Plain text in-between
+ |
10 | {% quote(author="Vincent") %}
+ |
11 | A quote
+ |
12 | {% end %}
+ |
13 | <div class="gist">
+ |
14 | <script src="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57.js"></script>
+ |
15 | </div>
+ |
16 |
+ |
17 | {# A Tera comment, you should see it #}
+ |
18 | <!-- end text goes here -->
+ |
+"#
+ );
+}
\ No newline at end of file