1 object TextColor = 2 val regular = FontColor.black 3 val highlighted = FontColor.blue 4 val quoted = FontColor.green 5 val attribute = FontColor.gray 6 val modifier = FontColor.gray 7 val macro = FontColor.yellow 8 val commented = FontColor.light_gray 9 val failure = FontColor.red 10 11 let word_end_chars : Set<Char> = 12 [' ', '\n', '(', ')', '[', ']', '<', '>', '.', ',', ':', ';', '/'] 13 14 type Lang = 15 | Kedr 16 | Julia 17 18 let get_kedr_word_color (t : String) (c : Char) (index : u32) = case t of 19 "let" | "local" | "val" | "var" | "def" | "fun" | "mut" | "mem" 20 | "if" | "then" | "else" | "do" | "case" | "of" | "when" 21 | "while" | "repeat" | "until" | "for" | "downto" 22 | "u8" | "u16" | "u32" | "i32" | "f32" | "u64" | "i64" 23 | "f64" | "bool" 24 | "where" | "assert" | "return" | "break" | "continue" 25 | "is" | "f@" | "t@" -> 26 TextColor.highlighted 27 28 "as" if c == ' ' -> TextColor.highlighted 29 30 "type" | "object" | "class" | "mixin" | "typealias" 31 | "import" | "module" 32 | "endmodule" if index - t.length == 0 -> 33 TextColor.highlighted 34 35 "@mut" | "@c" | "@cpp" | "@abstract" 36 | "@byval" | "@move" | "@data" | "@open" | "@literal" 37 | "@decl" | "@impl" | "@secondary" | "@optional" 38 | "@param" | "@owner" | "@auto" | "@publish" | "@dst" 39 | "@late" | "@vararg" | "@restrict" | "@nonnull" -> 40 TextColor.attribute 41 42 _ if t.starts_with "@[" && t.ends_with ']' -> TextColor.attribute 43 44 else -> TextColor.regular 45 46 let get_julia_word_color (t : String) = case t of 47 "struct" | "function" | "module" | "end" | "if" | "else" | "elseif" 48 | "try" | "catch" | "finally" | "for" | "while" | "local" | "global" 49 | "import" | "using" | "where" | "const" | "return" -> 50 TextColor.highlighted 51 52 "@kwdef" | "@assert" | "@debug" | "@info" | "@warn" | "@error" 53 | "@show" -> 54 TextColor.macro 55 56 else -> TextColor.regular 57 58 let update_line_colors (line : TextLine) (lang : Lang) = 59 let word = StringBuilder.new 60 let prev_word = StringBuilder.new 61 let mut prev_start = 0 62 let mut is_double_quoted = false 63 let mut is_single_quoted = false 64 let mut is_commented_single_line = false 65 let mut commented_multiline = line.commented_in 66 let mut is_attribute_brackets = false 67 let (comment_first_c, comment_second_c) = case lang of 68 Lang/Kedr -> ('/', '*') 69 Lang/Julia -> ('#', '=') 70 71 for index = 0 until line.length do 72 let c = line[index].char 73 let maybe_prev_c = if index == 0 then None else Some line[index - 1].char 74 let maybe_prev_prev_c = if index < 2 then None else Some line[index - 2].char 75 let maybe_next_c = if index == line.length - 1 76 then None 77 else Some line[index + 1].char 78 79 if is_commented_single_line then 80 line.set_color index TextColor.commented 81 82 else if commented_multiline > 0 then 83 line.set_color index TextColor.commented 84 if c == comment_first_c && maybe_prev_c == Some comment_second_c then 85 commented_multiline -= 1 86 87 else if c == comment_first_c && maybe_next_c == Some comment_second_c then 88 commented_multiline += 1 89 90 else if c == comment_first_c && maybe_next_c == Some comment_second_c then 91 commented_multiline += 1 92 line.set_color index TextColor.commented 93 94 else if (lang == Lang/Kedr && c == '/' && maybe_next_c == Some '/' || c == '#') 95 && not is_double_quoted && not is_single_quoted 96 then 97 is_commented_single_line = true 98 line.set_color index TextColor.commented 99 100 else if c == '"' && not is_single_quoted then 101 is_double_quoted = not is_double_quoted 102 if is_double_quoted then 103 for i = 0 until word.length do 104 line.set_color (index - i - 1) TextColor.regular 105 106 word.clear 107 108 word.append c 109 if not is_double_quoted then 110 for i = 0 until word.length do 111 line.set_color (index - i) TextColor.quoted 112 113 word.clear 114 115 else if c == '\'' && not is_double_quoted 116 && (maybe_prev_c <> Some '\\' || maybe_prev_prev_c == Some '\\') 117 then 118 is_single_quoted = not is_single_quoted 119 if is_single_quoted then 120 for i = 0 until word.length do 121 line.set_color (index - i - 1) TextColor.regular 122 123 word.clear 124 125 word.append c 126 if not is_single_quoted then 127 for i = 0 until word.length do 128 line.set_color (index - i) TextColor.quoted 129 130 word.clear 131 132 else if c == '@' && maybe_next_c == Some '[' then 133 word.append c 134 is_attribute_brackets = true 135 136 else if is_attribute_brackets then 137 word.append c 138 if c == ']' then 139 is_attribute_brackets = false 140 141 else if word_end_chars.contains c && not is_double_quoted 142 && not is_single_quoted 143 then 144 if word.is_not_empty then 145 let t = word.as_string 146 let start = index - word.length 147 let prev_t = prev_word.as_string 148 let is_composite = case lang of 149 Lang/Julia -> 150 t == "struct" && prev_t == "mutable" 151 || t == "type" && prev_t == "abstract" 152 153 Lang/Kedr -> 154 t == "obs" && (prev_t == "let" || prev_t == "var") 155 156 if is_composite then 157 for i = prev_start until index do 158 line.set_color i TextColor.highlighted 159 else 160 let color = case lang of 161 Lang/Kedr -> get_kedr_word_color t c index 162 Lang/Julia -> get_julia_word_color t 163 164 for i = 0 until word.length do 165 line.set_color (start + i) color 166 167 if lang == Lang/Kedr 168 && word[i] == '@' 169 && (i <> 0 170 || index > word.length 171 && line[index - word.length - 1].char == ']') 172 then 173 val u = t.drop (i + 1) 174 let colorize = case u of 175 "ptr" | "mut_ptr" | "ref" | "mut_ref" | "zero" 176 | "atom" | "fn" | "value" | "to_ref" | "obs" 177 | "null" | "all" | "type" | "is_set" | "is_unset" 178 | "copy" -> true 179 180 else -> false 181 182 if colorize then 183 for j = start + i until start + word.length do 184 line.set_color j TextColor.modifier 185 186 break 187 188 prev_start = start 189 prev_word.clear 190 append word.as_string 191 word.clear 192 193 line.set_color index TextColor.regular 194 195 else if c == '\n' && is_double_quoted then 196 for i = 0 until word.length do 197 line.set_color (index - i - 1) TextColor.quoted 198 else 199 word.append c 200 201 if is_attribute_brackets then 202 for i = line.length - word.length until line.length do 203 line.set_color i TextColor.regular 204 205 line.commented_out = commented_multiline 206 207 def update_colors_for_line (text : Text 208 line_index : u32 209 lang : Lang) : Unit = 210 if text.lines.size > line_index then 211 let line = text.lines[line_index] 212 let prev_is_commented_out = line.commented_out 213 update_line_colors line lang 214 if prev_is_commented_out <> line.commented_out 215 && text.lines.size > line_index + 1 216 then 217 text.lines[line_index + 1].commented_in = line.commented_out 218 update_colors_for_line text (line_index + 1) lang 219 220 def update_colors (text : Text 221 from_index : u32 222 to_index : u32 223 lang : Lang) = 224 if from_index == to_index then 225 update_colors_for_line text from_index lang 226 else 227 for line_index = from_index until to_index do 228 let line = text.lines[line_index] 229 update_line_colors line lang 230 if text.lines.size > line_index + 1 then 231 let next_line = text.lines[line_index + 1] 232 let prev_is_commented_in = next_line.commented_in 233 next_line.commented_in = line.commented_out 234 if line_index == to_index - 1 235 && prev_is_commented_in <> next_line.commented_in 236 then 237 update_colors_for_line text (line_index + 1) lang 238