#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TokenKind {
Keyword,
String,
Comment,
Number,
Function,
Type,
Operator,
Punctuation,
Property,
Builtin,
Attr,
Variable,
Plain,
}
impl TokenKind {
pub fn class(self) -> Option<&'static str> {
match self {
Self::Keyword => Some("tok-keyword"),
Self::String => Some("tok-string"),
Self::Comment => Some("tok-comment"),
Self::Number => Some("tok-number"),
Self::Function => Some("tok-function"),
Self::Type => Some("tok-type"),
Self::Operator => Some("tok-operator"),
Self::Punctuation => Some("tok-punctuation"),
Self::Property => Some("tok-property"),
Self::Builtin => Some("tok-builtin"),
Self::Attr => Some("tok-attr"),
Self::Variable => Some("tok-variable"),
Self::Plain => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Token {
pub kind: TokenKind,
pub start: usize,
pub end: usize,
}
pub fn render(code: &str, tokens: &[Token]) -> String {
use crate::escape::escape_html;
let mut out = String::with_capacity(code.len() * 2);
let mut pos = 0;
for tok in tokens {
if tok.start > pos {
escape_html(&code[pos..tok.start], &mut out);
}
let text = &code[tok.start..tok.end];
if let Some(cls) = tok.kind.class() {
out.push_str("<span class=\"");
out.push_str(cls);
out.push_str("\">");
escape_html(text, &mut out);
out.push_str("</span>");
} else {
escape_html(text, &mut out);
}
pos = tok.end;
}
if pos < code.len() {
escape_html(&code[pos..], &mut out);
}
out
}