pub mod syntax_themes;
use std::collections::BTreeMap;
use std::time::Instant;
use crate::errors::*;
use crate::site::markdown::syntax_highlight::syntax_themes::SyntaxTheme;
use syntect::highlighting::{Theme, ThemeSet};
use syntect::html::highlighted_html_for_string;
use syntect::parsing::{SyntaxDefinition, SyntaxReference, SyntaxSet};
fn find_syntax<'a>(ps: &'a SyntaxSet, language: &'a str) -> Result<&'a SyntaxReference> {
let syntax_extension = ps.find_syntax_by_extension(language);
let syntax_name = ps.find_syntax_by_token(language);
if let Some(syntax_extension) = syntax_extension {
Ok(syntax_extension)
} else if let Some(syntax_name) = syntax_name {
Ok(syntax_name)
} else {
if !language.is_empty() {
let msg = format!("Found syntax highlight language annotation `{language}` which is not currently supported. The annotated block will be shown as plaintext. Please file an issue https://github.com/axodotdev/oranda/issues/new to let us know you'd like to see it supported.");
tracing::warn!("{}", &msg);
}
let plain_text = ps
.syntaxes()
.iter()
.find(|syntax| syntax.name == "Plain Text")
.expect("syntax was missing the Plain Text builtin???");
Ok(plain_text)
}
}
const THEMES: &[(&str, &str)] = &[("MaterialTheme", include_str!("MaterialTheme.tmTheme"))];
#[allow(dead_code)]
pub fn dump_syntax_themes() -> Result<()> {
println!("DUMPING ORANDA SYNTAX THEMES...");
let toml_syntax_file =
std::fs::read_to_string("./src/site/markdown/syntax_highlight/TOML.sublime-syntax")?;
let ts_syntax_file =
std::fs::read_to_string("./src/site/markdown/syntax_highlight/TypeScript.sublime-syntax")?;
let timer = Instant::now();
let toml_syntax =
SyntaxDefinition::load_from_str(&toml_syntax_file, true, Some("toml")).unwrap();
let ts_syntax =
SyntaxDefinition::load_from_str(&ts_syntax_file, true, Some("typescript")).unwrap();
let mut ps_builder = SyntaxSet::load_defaults_newlines().into_builder();
ps_builder.add(toml_syntax);
ps_builder.add(ts_syntax);
let ps = ps_builder.build();
syntect::dumps::dump_to_uncompressed_file(
&ps,
"./src/site/markdown/syntax_highlight/syntax_themes.themedump",
)
.unwrap();
println!("DUMPED SYNTAX THEMES IN {}MS", timer.elapsed().as_millis());
println!("PLEASE DELETE THIS CODE PATH");
Ok(())
}
pub fn syntax_highlight(
lang: Option<&str>,
code: &str,
syntax_theme: &SyntaxTheme,
) -> Result<String> {
let ps = syntect::dumps::from_uncompressed_data(include_bytes!("./syntax_themes.themedump"))
.expect("failed to load syntax_themes.themedump from the binary");
let themes = THEMES
.iter()
.map(|(name, body)| {
use std::io::Cursor;
let mut buff = Cursor::new(body);
let theme = ThemeSet::load_from_reader(&mut buff)
.expect("failed to parse syntax theme from the binary");
Ok((name.to_string(), theme))
})
.collect::<Result<BTreeMap<String, Theme>>>()?;
let theme_set = ThemeSet { themes };
let language = match lang {
None => "",
Some("text") => "txt",
Some("shell") => "sh",
Some(l) => l,
};
let syntax = find_syntax(&ps, language)?;
Ok(highlighted_html_for_string(
code,
&ps,
syntax,
&theme_set.themes[&syntax_theme.as_str()],
)?)
}