[Web] Highlight code blocks.

master
Araozu 2023-04-05 09:48:15 -05:00
parent 0588e1f2fe
commit 5c60943fab
4 changed files with 116 additions and 110 deletions

View File

@ -1,13 +1,17 @@
use markdown::mdast::Code;
use crate::highlighter::highlight;
use super::Printable;
impl Printable for Code {
fn to_html(&self) -> String {
let code = highlight(&self.value);
if let Some(lang) = &self.lang {
format!("<pre class=\"language-{}\">{}</pre>", lang, self.value)
format!("<pre class=\"language-{}\">{}</pre>", lang, code)
} else {
format!("<pre class=\"language-none\">{}</pre>", self.value)
format!("<pre class=\"language-none\">{}</pre>", code)
}
}

View File

@ -1,7 +1,7 @@
use markdown::mdast::InlineCode;
use super::Printable;
use misti::TokenType;
use crate::highlighter::highlight;
impl Printable for InlineCode {
fn to_html(&self) -> String {
@ -21,110 +21,3 @@ impl Printable for InlineCode {
self.value.clone()
}
}
fn highlight(input: &String) -> String {
// The tokens come in order
let tokens = misti::tokenize(&input);
if tokens.is_err() {
eprintln!(
"Found a lexical error processing an inline-code with input {}",
input
);
return input.clone();
}
let mut output = input.clone();
// Offset to the position of the tokens in the string, to allow
// several tokens to be highlighted
let mut offset = 0;
for token in tokens.unwrap() {
match &token.token_type {
TokenType::Datatype => {
let start_pos = token.position;
let end_pos = token.get_end_position();
let range = (start_pos + offset)..(end_pos + offset);
let html = format!("<span class=\"token class-name\">{}</span>", token.value);
// 38 is the number of extra characters added to the token
offset += 38;
output.replace_range(range, html.as_str());
}
TokenType::Number => {
let start_pos = token.position;
let end_pos = token.get_end_position();
let range = (start_pos + offset)..(end_pos + offset);
let html = format!("<span class=\"token number\">{}</span>", token.value);
offset += 34;
output.replace_range(range, html.as_str());
}
TokenType::String => {
let start_pos = token.position;
let end_pos = token.get_end_position();
let range = (start_pos + offset)..(end_pos + offset);
let html = format!("<span class=\"token string\">\"{}\"</span>", token.value);
offset += 34;
output.replace_range(range, html.as_str());
}
_ => {}
}
}
output
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_return_simple_string() {
assert_eq!("sample", highlight(&String::from("sample")))
}
#[test]
fn should_highlight_datatype() {
assert_eq!(
"<span class=\"token class-name\">Num</span>",
highlight(&String::from("Num"))
)
}
#[test]
fn should_highlight_number() {
assert_eq!(
"<span class=\"token number\">322</span>",
highlight(&String::from("322"))
)
}
#[test]
fn should_highlight_string() {
assert_eq!(
"<span class=\"token string\">\"Hello\"</span>",
highlight(&String::from("\"Hello\""))
)
}
#[test]
fn should_highlight_multiple_tokens() {
assert_eq!(
"<span class=\"token class-name\">Str</span> x = <span class=\"token number\">322</span>",
highlight(&String::from("Str x = 322"))
);
assert_eq!(
"<span class=\"token class-name\">Str</span> x = <span class=\"token string\">\"hello\"</span> <span class=\"token number\">322</span>",
highlight(&String::from("Str x = \"hello\" 322"))
);
}
}

View File

@ -0,0 +1,108 @@
use misti::TokenType;
pub fn highlight(input: &String) -> String {
// The tokens come in order
let tokens = misti::tokenize(&input);
if tokens.is_err() {
eprintln!(
"Found a lexical error processing code.\n{:?}",
tokens
);
return input.clone();
}
let mut output = input.clone();
// Offset to the position of the tokens in the string, to allow
// several tokens to be highlighted
let mut offset = 0;
for token in tokens.unwrap() {
match &token.token_type {
TokenType::Datatype => {
let start_pos = token.position;
let end_pos = token.get_end_position();
let range = (start_pos + offset)..(end_pos + offset);
let html = format!("<span class=\"token class-name\">{}</span>", token.value);
// 38 is the number of extra characters added to the token
offset += 38;
output.replace_range(range, html.as_str());
}
TokenType::Number => {
let start_pos = token.position;
let end_pos = token.get_end_position();
let range = (start_pos + offset)..(end_pos + offset);
let html = format!("<span class=\"token number\">{}</span>", token.value);
offset += 34;
output.replace_range(range, html.as_str());
}
TokenType::String => {
let start_pos = token.position;
let end_pos = token.get_end_position();
let range = (start_pos + offset)..(end_pos + offset);
let html = format!("<span class=\"token string\">\"{}\"</span>", token.value);
offset += 34;
output.replace_range(range, html.as_str());
}
_ => {}
}
}
output
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_return_simple_string() {
assert_eq!("sample", highlight(&String::from("sample")))
}
#[test]
fn should_highlight_datatype() {
assert_eq!(
"<span class=\"token class-name\">Num</span>",
highlight(&String::from("Num"))
)
}
#[test]
fn should_highlight_number() {
assert_eq!(
"<span class=\"token number\">322</span>",
highlight(&String::from("322"))
)
}
#[test]
fn should_highlight_string() {
assert_eq!(
"<span class=\"token string\">\"Hello\"</span>",
highlight(&String::from("\"Hello\""))
)
}
#[test]
fn should_highlight_multiple_tokens() {
assert_eq!(
"<span class=\"token class-name\">Str</span> x = <span class=\"token number\">322</span>",
highlight(&String::from("Str x = 322"))
);
assert_eq!(
"<span class=\"token class-name\">Str</span> x = <span class=\"token string\">\"hello\"</span> <span class=\"token number\">322</span>",
highlight(&String::from("Str x = \"hello\" 322"))
);
}
}

View File

@ -6,6 +6,7 @@ use std::{fs, path::Path};
mod generator;
mod utils;
mod highlighter;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]