| 1 | module main |
| 2 | |
| 3 | import term |
| 4 | import strings |
| 5 | import v.scanner |
| 6 | import v.ast |
| 7 | import v.token |
| 8 | import v.pref |
| 9 | |
| 10 | const highlight_builtin_types = ['bool', 'string', 'i8', 'i16', 'int', 'i64', 'i128', 'isize', |
| 11 | 'byte', 'u8', 'u16', 'u32', 'u64', 'usize', 'u128', 'rune', 'f32', 'f64', 'byteptr', 'voidptr', |
| 12 | 'any'] |
| 13 | |
| 14 | fn color_highlight(code string, tb &ast.Table) string { |
| 15 | highlight_code := fn (tok token.Token, typ HighlightTokenTyp) string { |
| 16 | mut lit := '' |
| 17 | match typ { |
| 18 | .unone, .operator, .punctuation { |
| 19 | lit = tok.kind.str() |
| 20 | } |
| 21 | .string { |
| 22 | use_double_quote := tok.lit.contains("'") && !tok.lit.contains('"') |
| 23 | unescaped_val := tok.lit.replace('\\\\', '\x01').replace_each(["\\'", "'", '\\"', |
| 24 | '"']) |
| 25 | if use_double_quote { |
| 26 | s := unescaped_val.replace_each(['\x01', '\\\\', '"', '\\"']) |
| 27 | lit = term.yellow('"${s}"') |
| 28 | } else { |
| 29 | s := unescaped_val.replace_each(['\x01', '\\\\', "'", "\\'"]) |
| 30 | lit = term.yellow("'${s}'") |
| 31 | } |
| 32 | } |
| 33 | .char { |
| 34 | lit = term.yellow('`${tok.lit}`') |
| 35 | } |
| 36 | .comment { |
| 37 | lit = if tok.lit != '' && tok.lit[0] == 1 { |
| 38 | term.gray('//${tok.lit[1..]}') |
| 39 | } else { |
| 40 | term.gray('//${tok.lit}') |
| 41 | } |
| 42 | } |
| 43 | .keyword { |
| 44 | lit = term.bright_blue(tok.lit) |
| 45 | } |
| 46 | .builtin, .symbol { |
| 47 | lit = term.green(tok.lit) |
| 48 | } |
| 49 | .function { |
| 50 | lit = term.cyan(tok.lit) |
| 51 | } |
| 52 | .number, .module_ { |
| 53 | lit = term.bright_blue(tok.lit) |
| 54 | } |
| 55 | .boolean { |
| 56 | lit = term.bright_magenta(tok.lit) |
| 57 | } |
| 58 | .none { |
| 59 | lit = term.red(tok.lit) |
| 60 | } |
| 61 | .prefix { |
| 62 | lit = term.magenta(tok.lit) |
| 63 | } |
| 64 | else { |
| 65 | lit = tok.lit |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | return lit |
| 70 | } |
| 71 | mut s := scanner.new_scanner(code, .parse_comments, &pref.Preferences{ |
| 72 | is_fmt: true |
| 73 | }) |
| 74 | mut prev_prev := token.Token{} |
| 75 | mut prev := token.Token{} |
| 76 | mut tok := s.scan() |
| 77 | mut next_tok := s.scan() |
| 78 | mut buf := strings.new_builder(200) |
| 79 | mut i := 0 |
| 80 | for i < code.len { |
| 81 | if i == tok.pos { |
| 82 | mut tok_typ := HighlightTokenTyp.unone |
| 83 | match tok.kind { |
| 84 | .name { |
| 85 | if (tok.lit in highlight_builtin_types || tb.known_type(tok.lit)) |
| 86 | && (next_tok.kind != .lpar || prev.kind !in [.key_fn, .rpar]) { |
| 87 | tok_typ = .builtin |
| 88 | } else if |
| 89 | (next_tok.kind in [.lcbr, .rpar, .eof, .name, .rcbr, .assign, .key_pub, .key_mut, .pipe, .comma, .comment, .lt, .lsbr] |
| 90 | && next_tok.lit !in highlight_builtin_types) |
| 91 | && (prev.kind in [.name, .amp, .lcbr, .rsbr, .key_type, .assign, .dot, .not, .question, .rpar, .key_struct, .key_enum, .pipe, .key_interface, .comment, .ellipsis, .comma] |
| 92 | && prev.lit !in highlight_builtin_types) |
| 93 | && ((tok.lit != '' && tok.lit[0].is_capital()) |
| 94 | || prev_prev.lit in ['C', 'JS']) { |
| 95 | tok_typ = .symbol |
| 96 | } else if tok.lit[0].is_capital() && prev.kind == .lpar |
| 97 | && next_tok.kind == .comma { |
| 98 | tok_typ = .symbol |
| 99 | } else if next_tok.kind == .lpar |
| 100 | || (!(tok.lit != '' && tok.lit[0].is_capital()) |
| 101 | && next_tok.kind in [.lt, .lsbr] && next_tok.pos == tok.pos + tok.lit.len) { |
| 102 | tok_typ = .function |
| 103 | } else if next_tok.kind == .dot { |
| 104 | if tok.lit in ['C', 'JS'] { |
| 105 | tok_typ = .prefix |
| 106 | } else { |
| 107 | if tok.lit != '' && tok.lit[0].is_capital() { |
| 108 | tok_typ = .symbol |
| 109 | } else { |
| 110 | tok_typ = .module_ |
| 111 | } |
| 112 | } |
| 113 | } else if tok.lit in ['r', 'c'] && next_tok.kind == .string { |
| 114 | tok_typ = .prefix |
| 115 | } else { |
| 116 | tok_typ = .name |
| 117 | } |
| 118 | } |
| 119 | .comment { |
| 120 | tok_typ = .comment |
| 121 | } |
| 122 | .chartoken { |
| 123 | tok_typ = .char |
| 124 | } |
| 125 | .string { |
| 126 | tok_typ = .string |
| 127 | } |
| 128 | .number { |
| 129 | tok_typ = .number |
| 130 | } |
| 131 | .key_true, .key_false { |
| 132 | tok_typ = .boolean |
| 133 | } |
| 134 | .lpar, .lcbr, .rpar, .rcbr, .lsbr, .rsbr, .semicolon, .colon, .comma, .dot, |
| 135 | .dotdot, .ellipsis { |
| 136 | tok_typ = .punctuation |
| 137 | } |
| 138 | .key_none { |
| 139 | tok_typ = .none |
| 140 | } |
| 141 | else { |
| 142 | if token.is_key(tok.lit) || token.is_decl(tok.kind) { |
| 143 | tok_typ = .keyword |
| 144 | } else if tok.kind.is_assign() || tok.is_unary() || tok.kind.is_relational() |
| 145 | || tok.kind.is_infix() || tok.kind.is_postfix() { |
| 146 | tok_typ = .operator |
| 147 | } |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | buf.write_string(highlight_code(tok, tok_typ)) |
| 152 | if prev_prev.kind == .eof || prev.kind == .eof || next_tok.kind == .eof { |
| 153 | break |
| 154 | } |
| 155 | prev_prev = prev |
| 156 | prev = tok |
| 157 | i = tok.pos + tok.len |
| 158 | tok = next_tok |
| 159 | next_tok = s.scan() |
| 160 | } else { |
| 161 | buf.write_u8(code[i]) |
| 162 | i++ |
| 163 | } |
| 164 | } |
| 165 | return buf.str() |
| 166 | } |
| 167 | |