Skip to content

Instantly share code, notes, and snippets.

@dustinknopoff
Created May 3, 2020 14:29
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save dustinknopoff/b67a1082eae29c0c63f88dcdf64175d5 to your computer and use it in GitHub Desktop.
A bare minimum pulldown_cmark highlighting using syntect based off of conversation in: https://github.com/raphlinus/pulldown-cmark/issues/167
use syntect::highlighting::ThemeSet;
use syntect::html::highlighted_html_for_string;
use syntect::parsing::SyntaxSet;
use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag};
fn main() {
// Setup for pulldown_cmark to read (only) from stdin
let opts = Options::all();
let input = String::from(
r#"Test
```bash
sh install.sh && echo "true"
```
Test"#,
);
let mut s = String::with_capacity(&input.len() * 3 / 2);
let p = Parser::new_ext(&input, opts);
// Setup for syntect to highlight (specifically) Rust code
let ss = SyntaxSet::load_defaults_newlines();
let ts = ThemeSet::load_defaults();
let theme = &ts.themes["Solarized (light)"];
// We'll build a new vector of events since we can only consume the parser once
let mut new_p = Vec::new();
// As we go along, we'll want to highlight code in bundles, not lines
let mut to_highlight = String::new();
// And track a little bit of state
let mut in_code_block = false;
p.for_each(|event| match event {
Event::Start(Tag::CodeBlock(_)) => {
in_code_block = true;
}
Event::End(Tag::CodeBlock(ref token)) => {
if in_code_block {
let syntax = if let CodeBlockKind::Fenced(val) = token {
ss.find_syntax_by_extension(&val.clone().into_string())
.unwrap_or_else(|| ss.find_syntax_plain_text())
} else {
ss.find_syntax_plain_text()
};
// Format the whole multi-line code block as HTML all at once
let html = highlighted_html_for_string(&to_highlight, &ss, &syntax, &theme);
// And put it into the vector
new_p.push(Event::Html(CowStr::Boxed(html.into_boxed_str())));
to_highlight = String::new();
in_code_block = false;
}
}
Event::Text(t) => {
if in_code_block {
// If we're in a code block, build up the string of text
to_highlight.push_str(&t);
} else {
new_p.push(Event::Text(t))
}
}
e => {
new_p.push(e);
}
});
// Now we send this new vector of events off to be transformed into HTML
html::push_html(&mut s, new_p.into_iter());
print!("{}", s);
}
@dustinknopoff
Copy link
Author

Rendered from JSFiddle

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment