use tree_sitter_highlight::{HighlightConfiguration, HighlightEvent, Highlighter};
use v_htmlescape::escape;
pub mod c;
pub mod c_sharp;
pub mod cpp;
pub mod go;
pub mod haskell;
pub mod java;
pub mod javascript;
pub mod json;
pub mod julia;
pub mod php;
pub mod python;
pub mod ruby;
pub mod rust;
pub mod scala;
pub mod typescript;
pub mod bash;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Language {
Rust,
Javascript,
JavascriptJsx,
Typescript,
TypescriptTsx,
Python,
Cpp,
Java,
Php,
Go,
Scala,
Haskell,
Ruby,
Julia,
Json,
CSharp,
C,
Bash,
}
pub static HIGHLIGHT_NAMES: &[&str] = &[
"attribute",
"label",
"constant",
"function.builtin",
"function.macro",
"function",
"keyword",
"operator",
"property",
"punctuation",
"punctuation.bracket",
"punctuation.delimiter",
"string",
"string.special",
"tag",
"escape",
"type",
"type.builtin",
"constructor",
"variable",
"variable.builtin",
"variable.parameter",
"comment",
];
pub fn highlight_to_html(lang: Language, code: &str) -> String {
let recognized_names: Vec<String> = HIGHLIGHT_NAMES.iter().cloned().map(String::from).collect();
let mut highlighter = Highlighter::new();
let mut config = {
match lang {
Language::Rust => {
HighlightConfiguration::new(rust::language(), rust::HIGHLIGHT_QUERY, "", "")
.unwrap()
}
Language::Bash => {
HighlightConfiguration::new(bash::language(), bash::HIGHLIGHT_QUERY, "", "")
.unwrap()
}
Language::Haskell => HighlightConfiguration::new(
haskell::language(),
haskell::HIGHLIGHT_QUERY,
"",
haskell::LOCALS_QUERY,
)
.unwrap(),
Language::Go => {
HighlightConfiguration::new(go::language(), go::HIGHLIGHT_QUERY, "", "").unwrap()
}
Language::Ruby => HighlightConfiguration::new(
ruby::language(),
ruby::HIGHLIGHT_QUERY,
"",
ruby::LOCALS_QUERY,
)
.unwrap(),
Language::Scala => HighlightConfiguration::new(scala::language(), "", "", "").unwrap(),
Language::Php => HighlightConfiguration::new(
php::language(),
php::HIGHLIGHTS_QUERY,
php::INJECTIONS_QUERY,
"",
)
.unwrap(),
Language::Typescript => HighlightConfiguration::new(
typescript::language_typescript(),
typescript::HIGHLIGHT_QUERY,
"",
typescript::LOCALS_QUERY,
)
.unwrap(),
Language::TypescriptTsx => HighlightConfiguration::new(
typescript::language_tsx(),
typescript::HIGHLIGHT_QUERY,
"",
typescript::LOCALS_QUERY,
)
.unwrap(),
Language::Javascript => HighlightConfiguration::new(
javascript::language(),
javascript::HIGHLIGHT_QUERY,
javascript::INJECTION_QUERY,
"",
)
.unwrap(),
Language::JavascriptJsx => HighlightConfiguration::new(
javascript::language(),
javascript::JSX_HIGHLIGHT_QUERY,
javascript::INJECTION_QUERY,
"",
)
.unwrap(),
Language::Python => {
HighlightConfiguration::new(python::language(), python::HIGHLIGHT_QUERY, "", "")
.unwrap()
}
Language::Cpp => {
HighlightConfiguration::new(cpp::language(), cpp::HIGHLIGHT_QUERY, "", "").unwrap()
}
Language::Julia => HighlightConfiguration::new(julia::language(), "", "", "").unwrap(),
Language::Json => {
HighlightConfiguration::new(json::language(), json::HIGHLIGHT_QUERY, "", "")
.unwrap()
}
Language::Java => {
HighlightConfiguration::new(java::language(), java::HIGHLIGHT_QUERY, "", "")
.unwrap()
}
Language::CSharp => {
HighlightConfiguration::new(c_sharp::language(), c_sharp::HIGHLIGHT_QUERY, "", "")
.unwrap()
}
Language::C => {
HighlightConfiguration::new(c::language(), c::HIGHLIGHT_QUERY, "", "").unwrap()
}
}
};
config.configure(&recognized_names);
let mut result = String::new();
let highlights = highlighter
.highlight(&config, code.as_bytes(), None, |_| None)
.unwrap();
for event in highlights {
match event.unwrap() {
HighlightEvent::Source { start, end } => {
let code_span = escape(code.get(start..end).unwrap()).to_string();
result.push_str(&code_span);
}
HighlightEvent::HighlightStart(s) => {
let name = HIGHLIGHT_NAMES.get(s.0).unwrap().replace(".", "-");
result.push_str(&format!("<span class='{}'>", name));
}
HighlightEvent::HighlightEnd => {
result.push_str("</span>");
}
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let code = r#"
use tree_sitter::Parser;
use tree_sitter_highlight::{HighlightConfiguration, HighlightEvent, Highlighter};
use thiserror::Error;
pub fn hello<T>(c: T) -> T {
c
}
#[derive(Error, Debug)]
pub enum ResponseError {
/// A paypal api error.
#[error("api error {0}")]
ApiError(#[from] PaypalError),
/// A http error.
#[error("http error {0}")]
HttpError(#[from] reqwest::Error)
}
"#;
let result = highlight_to_html(Language::Rust, code);
println!("{}", result);
}
}