1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use syntect::html::{ClassStyle, ClassedHTMLGenerator};
use syntect::parsing::SyntaxSet;
use syntect::util::LinesWithEndings;
use std::sync::OnceLock;
fn syntaxes() -> &'static SyntaxSet {
static SS: OnceLock<SyntaxSet> = OnceLock::new();
SS.get_or_init(SyntaxSet::load_defaults_newlines)
}
pub fn highlight(path: &str, content: &str) -> String {
let ss = syntaxes();
let syntax = ss
.find_syntax_by_extension(
std::path::Path::new(path)
.extension()
.and_then(|e| e.to_str())
.unwrap_or(""),
)
.or_else(|| {
std::path::Path::new(path)
.file_name()
.and_then(|n| n.to_str())
.and_then(|n| ss.find_syntax_by_name(n))
})
.or_else(|| ss.find_syntax_by_first_line(content.lines().next().unwrap_or("")))
.unwrap_or_else(|| ss.find_syntax_plain_text());
let mut generator =
ClassedHTMLGenerator::new_with_class_style(syntax, ss, ClassStyle::Spaced);
for line in LinesWithEndings::from(content) {
let _ = generator.parse_html_for_line_which_includes_newline(line);
}
let mut html = generator.finalize();
while html.ends_with('\n') {
html.pop();
}
let line_count = html.lines().count().max(1);
let mut nums = String::with_capacity(line_count * 4);
for n in 1..=line_count {
if n > 1 {
nums.push('\n');
}
nums.push_str(&n.to_string());
}
format!(
"<div class=\"kg-codeview kg-blob\">\
<div class=\"kg-blob__nums\" aria-hidden=\"true\">{nums}</div>\
<pre class=\"kg-blob__code\"><code class=\"kg-highlight\">{html}</code></pre>\
</div>"
)
}