Packages
mdex
0.1.8
0.13.3
0.13.2
0.13.1
0.13.0
0.12.5
retired
0.12.4
0.12.3
0.12.2
0.12.1
0.12.0
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Fast and extensible Markdown for Elixir
Current section
Files
Jump to
Current section
Files
native/comrak_nif/src/inkjet_adapter.rs
use crate::themes;
use crate::themes::Theme;
use comrak::adapters::SyntaxHighlighterAdapter;
use inkjet::Language;
use std::collections::HashMap;
use std::io::{self, Write};
use tree_sitter_highlight::{HighlightEvent, Highlighter};
#[derive(Debug)]
pub struct InkjetAdapter<'a> {
theme: &'a Theme,
}
impl<'a> InkjetAdapter<'a> {
pub fn new(theme: &'a str) -> Self {
let theme = match themes::theme(theme) {
Some(theme) => theme,
None => themes::theme("onedark").unwrap(),
};
Self { theme }
}
fn write_highlighted(
&self,
output: &mut dyn Write,
lang: Language,
code: &str,
) -> io::Result<()> {
let mut highlighter = Highlighter::new();
let config = lang.config();
let highlights = highlighter
.highlight(
config,
code.as_bytes(),
None,
|token| match Language::from_token(token) {
Some(lang) => Some(lang.config()),
None => None,
},
)
.unwrap();
for event in highlights {
match event.unwrap() {
HighlightEvent::Source { start, end } => {
let span = code
.get(start..end)
.expect("Source bounds should be in bounds!");
let span = v_htmlescape::escape(span).to_string();
write!(output, "{}", span)?
}
HighlightEvent::HighlightStart(idx) => {
let scope = inkjet::constants::HIGHLIGHT_NAMES[idx.0];
let (class, style) = self.theme.get_scope(scope);
write!(output, "<span class=\"{}\" style=\"{}\">", class, style)?
}
HighlightEvent::HighlightEnd => write!(output, "</span>")?,
}
}
Ok(())
}
fn write_plain_highlighted(
&self,
output: &mut dyn Write,
lang: Language,
code: &str,
) -> io::Result<()> {
let mut highlighter = Highlighter::new();
let config = lang.config();
let highlights = highlighter
.highlight(config, code.as_bytes(), None, |_| None)
.unwrap();
for event in highlights {
match event.unwrap() {
HighlightEvent::Source { start, end } => {
let span = code
.get(start..end)
.expect("Source bounds should be in bounds!");
let span = v_htmlescape::escape(span).to_string();
write!(output, "{}", span)?
}
HighlightEvent::HighlightStart(_idx) => write!(output, "<span>")?,
HighlightEvent::HighlightEnd => write!(output, "</span>")?,
}
}
Ok(())
}
}
impl<'a> SyntaxHighlighterAdapter for InkjetAdapter<'a> {
fn write_highlighted(
&self,
output: &mut dyn Write,
lang: Option<&str>,
code: &str,
) -> io::Result<()> {
let lang = lang.unwrap_or("plain");
match Language::from_token(lang) {
Some(lang_config) => self.write_highlighted(output, lang_config, code)?,
None => self.write_plain_highlighted(output, Language::Diff, code)?,
};
Ok(())
}
fn write_pre_tag(
&self,
output: &mut dyn Write,
_attributes: HashMap<String, String>,
) -> io::Result<()> {
let (_class, background_style) = self.theme.get_scope("background");
let (_class, text_style) = self.theme.get_scope("text");
writeln!(
output,
"<pre class=\"autumn highlight\" style=\"{} {}\">",
background_style, text_style
)
}
fn write_code_tag(
&self,
output: &mut dyn Write,
attributes: HashMap<String, String>,
) -> io::Result<()> {
if attributes.contains_key("class") {
write!(output, "<code class=\"{}\">", attributes["class"])
} else {
write!(output, "<code>")
}
}
}