Skip to content

Commit

Permalink
Move plugins.
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanpallant committed Nov 21, 2024
1 parent 06bdf2c commit 21b943c
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 79 deletions.
82 changes: 3 additions & 79 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
use std::io::prelude::*;
use std::path::Path;
use std::sync::atomic::{AtomicBool, Ordering::Relaxed};

mod plugins;

/// Describes the ways in which this library can fail.
#[derive(thiserror::Error, Debug)]
Expand Down Expand Up @@ -211,83 +212,6 @@ pub fn load_book(summary_src: &str) -> Result<Vec<IndexEntry>, Error> {
Ok(index_entries)
}

/// Adds `<section>` around <h1> and <h2> slides.
struct SlideAdapter {
first: AtomicBool,
no_heading_slide: AtomicBool,
in_speaker_notes: AtomicBool,
}

impl SlideAdapter {
fn new() -> SlideAdapter {
SlideAdapter {
first: AtomicBool::new(true),
no_heading_slide: AtomicBool::new(false),
in_speaker_notes: AtomicBool::new(false),
}
}
}

impl comrak::adapters::HeadingAdapter for SlideAdapter {
fn enter(
&self,
output: &mut dyn Write,
heading: &comrak::adapters::HeadingMeta,
_sourcepos: Option<comrak::nodes::Sourcepos>,
) -> std::io::Result<()> {
if heading.level == 3 && heading.content == "Notes" {
// the start of speaker notes.
writeln!(output, r#"<aside class="notes">"#)?;
self.in_speaker_notes.store(true, Relaxed);
} else if heading.level <= 2 {
// We break slides on # and ##
if !self.first.load(Relaxed) {
// we have a previous slide open. Close it

// but first close any speaker notes
if self.in_speaker_notes.load(Relaxed) {
self.in_speaker_notes.store(false, Relaxed);
writeln!(output, "</aside>")?;
}
// now close the slide
writeln!(output, "</section>")?;
} else {
self.first.store(false, Relaxed);
}
// open a new slide
writeln!(output, "<section>")?;
}

if heading.content == "NO_HEADING" {
// this is a slide with no heading - comment out the fake heading
self.no_heading_slide.store(true, Relaxed);
writeln!(output, "<!-- ")?;
} else {
// write out the heading
self.no_heading_slide.store(false, Relaxed);
writeln!(output, "<h{}>", heading.level)?;
}

Ok(())
}

fn exit(
&self,
output: &mut dyn Write,
heading: &comrak::adapters::HeadingMeta,
) -> std::io::Result<()> {
if self.no_heading_slide.load(Relaxed) {
// stop hiding the fake heading
writeln!(output, " -->")?;
self.no_heading_slide.store(false, Relaxed);
} else {
// close the heading
writeln!(output, "</h{}>", heading.level)?;
}
Ok(())
}
}

/// Processes a markdown file into an HTML document, using the given template.
///
/// The template should contain the string `$TITLE`, which is the title of the
Expand All @@ -312,7 +236,7 @@ pub fn generate_deck(
let md_content = std::fs::read_to_string(in_path)?;

let md_content = md_content.replace("---", "## NO_HEADING");
let slide_adapter = SlideAdapter::new();
let slide_adapter = plugins::SlideAdapter::new();
let options = comrak::Options::default();
let mut plugins = comrak::Plugins::default();
plugins.render.heading_adapter = Some(&slide_adapter);
Expand Down
4 changes: 4 additions & 0 deletions src/plugins/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//! comrak plugins we need
mod slides;
pub use slides::SlideAdapter;
84 changes: 84 additions & 0 deletions src/plugins/slides.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//! Our Slide Adapter
//!
//! A comrak plugin for splitting up plain markdown text into reveal.js slides
//! by adding `<section>` tags around each slide (as delimited by `h1` or `h3`
//! heading).
use std::sync::atomic::{AtomicBool, Ordering::Relaxed};

/// Adds `<section>` around <h1> and <h2> slides.
pub struct SlideAdapter {
first: AtomicBool,
no_heading_slide: AtomicBool,
in_speaker_notes: AtomicBool,
}

impl SlideAdapter {
pub fn new() -> SlideAdapter {
SlideAdapter {
first: AtomicBool::new(true),
no_heading_slide: AtomicBool::new(false),
in_speaker_notes: AtomicBool::new(false),
}
}
}

impl comrak::adapters::HeadingAdapter for SlideAdapter {
fn enter(
&self,
output: &mut dyn std::io::Write,
heading: &comrak::adapters::HeadingMeta,
_sourcepos: Option<comrak::nodes::Sourcepos>,
) -> std::io::Result<()> {
if heading.level == 3 && heading.content == "Notes" {
// the start of speaker notes.
writeln!(output, r#"<aside class="notes">"#)?;
self.in_speaker_notes.store(true, Relaxed);
} else if heading.level <= 2 {
// We break slides on # and ##
if !self.first.load(Relaxed) {
// we have a previous slide open. Close it

// but first close any speaker notes
if self.in_speaker_notes.load(Relaxed) {
self.in_speaker_notes.store(false, Relaxed);
writeln!(output, "</aside>")?;
}
// now close the slide
writeln!(output, "</section>")?;
} else {
self.first.store(false, Relaxed);
}
// open a new slide
writeln!(output, "<section>")?;
}

if heading.content == "NO_HEADING" {
// this is a slide with no heading - comment out the fake heading
self.no_heading_slide.store(true, Relaxed);
writeln!(output, "<!-- ")?;
} else {
// write out the heading
self.no_heading_slide.store(false, Relaxed);
writeln!(output, "<h{}>", heading.level)?;
}

Ok(())
}

fn exit(
&self,
output: &mut dyn std::io::Write,
heading: &comrak::adapters::HeadingMeta,
) -> std::io::Result<()> {
if self.no_heading_slide.load(Relaxed) {
// stop hiding the fake heading
writeln!(output, " -->")?;
self.no_heading_slide.store(false, Relaxed);
} else {
// close the heading
writeln!(output, "</h{}>", heading.level)?;
}
Ok(())
}
}

0 comments on commit 21b943c

Please sign in to comment.