Syntax Highlighting With Line Numbering And Classes In Rust
[] Uses classes instead of inline styles
[] Trim leading empty lines, but not white space before
the first character on the first line
[] Trim trailing empty lines
[] Provide HTML that can have line numbers added via
CSS
[] Fall back to plain
-
text if the requested language
isn't found
[] link to
:
2fbld7l3 for generating stylesheets
rust
```cargo
[dependencies]
regex = "1.10.4"
syntect = "5.2.0"
```
use regex::Regex;
use syntect::html::{ClassedHTMLGenerator, ClassStyle};
use syntect::parsing::SyntaxSet;
use syntect::util::LinesWithEndings;
fn main() {
let code = r#"
fn main() {
println!(`Hello, World
alfa
bravo
`)
}
"#;
let lang = "rust";
let output = highlight_code(code, lang);
println!("{}", output)
}
fn highlight_code(code: &str, lang: &str) -> String {
let syntax_set = SyntaxSet::load_defaults_newlines();
let syntax = syntax_set.find_syntax_by_token(&lang).unwrap_or_else(|| syntax_set.find_syntax_plain_text());
let mut html_generator = ClassedHTMLGenerator::new_with_class_style(syntax, &syntax_set, ClassStyle::Spaced);
for line in LinesWithEndings::from(&trim_empty_lines(code)) {
let _ = html_generator.parse_html_for_line_which_includes_newline(line);
}
let initial_html = html_generator.finalize();
let output_html: Vec<_> = initial_html.lines()
.map(|line|
format!(r#"<span class="line-marker"></span>{}"#, line))
.collect();
output_html.join("\n")
}
fn trim_empty_lines(source: &str) -> String {
let re = Regex::new(r"\S").unwrap();
let trimmed_front = source.split("\n")
.fold(
"".to_string(), |acc, l|
{
if !acc.is_empty() {
acc + l + "\n"
} else {
if re.is_match(l) {
l.to_string() + "\n"
} else {
acc
}
}
});
trimmed_front.trim_end().to_string()
}
results start
CSS
.line-numbers {
counter-reset: lineNumber;
}
.line-marker {
counter-increment: lineNumber;
}
.line-marker:before {
display: inline-block;
color: goldenrod;
content: counter(lineNumber);
padding-right: 0.7rem;
text-align: right;
width: 2rem;
}
This is how I'm doing syntax highlighting in Rust.
This is the main way I'm doing it where instead of adding
the styles inline it adds classes.
fn main() {
println!(`Hello, World
alfa
bravo
`)
}