use std::borrow::Cow;
use once_cell::sync::OnceCell;
use syntastica::{
language_set::{
EitherLang, FileType, HighlightConfiguration, LanguageSet, SupportedLanguage, Union,
},
renderer::TerminalRenderer,
theme::THEME_KEYS,
Processor,
};
use syntastica_parsers::{Lang, LanguageSetImpl};
use tree_sitter_language::LanguageFn;
enum CustomLang {
Xml,
Dtd,
}
impl AsRef<str> for CustomLang {
fn as_ref(&self) -> &str {
match self {
Self::Xml => "xml",
Self::Dtd => "dtd",
}
}
}
impl<'set, T> SupportedLanguage<'set, T> for CustomLang {
fn name(&self) -> Cow<'_, str> {
self.as_ref().into()
}
fn for_name(name: impl AsRef<str>, _set: &'set T) -> syntastica::Result<Self> {
match name.as_ref() {
"xml" => Ok(CustomLang::Xml),
"dtd" => Ok(CustomLang::Dtd),
name => Err(syntastica::Error::UnsupportedLanguage(name.to_string())),
}
}
fn for_file_type(file_type: FileType, _set: &'set T) -> Option<Self> {
match file_type {
FileType::Xml => Some(CustomLang::Xml),
FileType::Dtd => Some(CustomLang::Dtd),
_ => None,
}
}
}
#[derive(Default)]
struct CustomLanguageSet {
xml_lang: OnceCell<HighlightConfiguration>,
dtd_lang: OnceCell<HighlightConfiguration>,
}
impl CustomLanguageSet {
pub fn new() -> Self {
Self::default()
}
}
impl LanguageSet<'_> for CustomLanguageSet {
type Language = CustomLang;
fn get_language(
&self,
language: Self::Language,
) -> syntastica::Result<&HighlightConfiguration> {
match language {
CustomLang::Xml => init_lang(
language.as_ref(),
&self.xml_lang,
tree_sitter_xml::LANGUAGE_XML,
tree_sitter_xml::XML_HIGHLIGHT_QUERY,
),
CustomLang::Dtd => init_lang(
language.as_ref(),
&self.dtd_lang,
tree_sitter_xml::LANGUAGE_DTD,
tree_sitter_xml::DTD_HIGHLIGHT_QUERY,
),
}
}
}
fn init_lang<'a>(
name: &str,
cell: &'a OnceCell<HighlightConfiguration>,
get_lang: LanguageFn,
queries: &str,
) -> syntastica::Result<&'a HighlightConfiguration> {
cell.get_or_try_init(|| {
let mut conf = HighlightConfiguration::new(
get_lang.into(),
name,
&syntastica_query_preprocessor::process_highlights("", true, queries),
"",
"",
)?;
conf.configure(THEME_KEYS);
Ok(conf)
})
}
fn main() -> syntastica::Result<()> {
let code_xml = r#"
<?xml version="1.1" encoding="UTF-8" ?>
<!DOCTYPE greeting [
<!ELEMENT greeting (#PCDATA)>
]>
<greeting>Hello, world!</greeting>
"#;
let code_dtd = r#"
<!ATTLIST termdef
id ID #REQUIRED
name CDATA #IMPLIED>
<!ATTLIST list
type (bullets|ordered|glossary) "ordered">
<!ATTLIST form method CDATA #FIXED "POST">
"#;
let code_rust = r#"
fn main() {
Regex::new(r"[a-fA-F0-9_]\s(.*)$");
}
"#;
let set = Union::new(CustomLanguageSet::new(), LanguageSetImpl::new());
let mut processor = Processor::new(&set);
let mut renderer = TerminalRenderer::new(None);
let theme = syntastica_themes::one::dark();
println!(
"{}",
syntastica::render(
&processor.process(code_xml, EitherLang::Left(CustomLang::Xml))?,
&mut renderer,
&theme,
)
);
println!(
"{}",
syntastica::render(
&processor.process(code_dtd, CustomLang::Dtd)?,
&mut renderer,
&theme,
)
);
println!(
"{}",
syntastica::render(
&processor.process(code_rust, EitherLang::Right(Lang::Rust))?,
&mut renderer,
&theme,
)
);
Ok(())
}