oxidoc_highlight/
token.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3pub enum TokenKind {
4 Keyword,
5 String,
6 Comment,
7 Number,
8 Function,
9 Type,
10 Operator,
11 Punctuation,
12 Property,
13 Builtin,
14 Attr,
15 Variable,
16 Plain,
17}
18
19impl TokenKind {
20 pub fn class(self) -> Option<&'static str> {
22 match self {
23 Self::Keyword => Some("tok-keyword"),
24 Self::String => Some("tok-string"),
25 Self::Comment => Some("tok-comment"),
26 Self::Number => Some("tok-number"),
27 Self::Function => Some("tok-function"),
28 Self::Type => Some("tok-type"),
29 Self::Operator => Some("tok-operator"),
30 Self::Punctuation => Some("tok-punctuation"),
31 Self::Property => Some("tok-property"),
32 Self::Builtin => Some("tok-builtin"),
33 Self::Attr => Some("tok-attr"),
34 Self::Variable => Some("tok-variable"),
35 Self::Plain => None,
36 }
37 }
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct Token {
43 pub kind: TokenKind,
44 pub start: usize,
45 pub end: usize,
46}
47
48pub fn render(code: &str, tokens: &[Token]) -> String {
50 use crate::escape::escape_html;
51
52 let mut out = String::with_capacity(code.len() * 2);
53 let mut pos = 0;
54
55 for tok in tokens {
56 if tok.start > pos {
58 escape_html(&code[pos..tok.start], &mut out);
59 }
60 let text = &code[tok.start..tok.end];
61 if let Some(cls) = tok.kind.class() {
62 out.push_str("<span class=\"");
63 out.push_str(cls);
64 out.push_str("\">");
65 escape_html(text, &mut out);
66 out.push_str("</span>");
67 } else {
68 escape_html(text, &mut out);
69 }
70 pos = tok.end;
71 }
72
73 if pos < code.len() {
75 escape_html(&code[pos..], &mut out);
76 }
77
78 out
79}