use crate::content::Snippet;
use crate::date::extract_date;
use crate::git::GitRepo;
use std::path::Path;
use syntect::highlighting::ThemeSet;
use syntect::html::highlighted_html_for_string;
use syntect::parsing::SyntaxSet;
pub fn process_snippet(path: &Path, git_repo: Option<&GitRepo>) -> anyhow::Result<Snippet> {
let code = std::fs::read_to_string(path)?;
let mut snippet = Snippet::new(path.to_path_buf());
snippet.language = path
.extension()
.and_then(|e| e.to_str())
.unwrap_or("text")
.to_string();
let filename = path
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or("untitled");
snippet.title = filename.replace(['_', '-'], " ");
let slug = slug::slugify(filename);
snippet.url = format!("/snippets/{}/", slug);
snippet.code = code.clone();
snippet.html_content = highlight_code(&code, &snippet.language);
snippet.date = extract_date(path, git_repo);
Ok(snippet)
}
pub fn highlight_code(code: &str, language: &str) -> String {
let ss = SyntaxSet::load_defaults_newlines();
let ts = ThemeSet::load_defaults();
let syntax = ss
.find_syntax_by_extension(language)
.or_else(|| ss.find_syntax_by_name(language))
.unwrap_or_else(|| ss.find_syntax_plain_text());
let theme = &ts.themes["base16-ocean.dark"];
match highlighted_html_for_string(code, &ss, syntax, theme) {
Ok(html) => html,
Err(_) => {
format!(
"<pre><code class=\"language-{}\">{}</code></pre>",
html_escape::encode_text(language),
html_escape::encode_text(code)
)
}
}
}
pub fn get_language_name(extension: &str) -> &'static str {
match extension {
"rs" => "Rust",
"py" => "Python",
"js" => "JavaScript",
"ts" => "TypeScript",
"go" => "Go",
"rb" => "Ruby",
"java" => "Java",
"c" => "C",
"cpp" | "cc" | "cxx" => "C++",
"h" | "hpp" => "C/C++ Header",
"sh" | "bash" => "Bash",
"zsh" => "Zsh",
"fish" => "Fish",
"sql" => "SQL",
"html" => "HTML",
"css" => "CSS",
"scss" | "sass" => "SCSS",
"json" => "JSON",
"yaml" | "yml" => "YAML",
"toml" => "TOML",
"xml" => "XML",
"md" => "Markdown",
"php" => "PHP",
"swift" => "Swift",
"kt" | "kts" => "Kotlin",
"lua" => "Lua",
"r" => "R",
"ex" | "exs" => "Elixir",
"erl" => "Erlang",
"hs" => "Haskell",
"ml" | "mli" => "OCaml",
"clj" | "cljs" => "Clojure",
"scala" => "Scala",
"pl" | "pm" => "Perl",
"vim" => "Vim Script",
"dockerfile" => "Dockerfile",
"tf" => "Terraform",
"nix" => "Nix",
_ => "Code",
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_highlight_code() {
let code = "fn main() { println!(\"Hello\"); }";
let html = highlight_code(code, "rs");
assert!(html.contains("pre"));
}
#[test]
fn test_get_language_name() {
assert_eq!(get_language_name("rs"), "Rust");
assert_eq!(get_language_name("py"), "Python");
assert_eq!(get_language_name("unknown"), "Code");
}
}