1 #include <assert.h> 2 #include <stdbool.h> 3 #include <stdio.h> 4 #include <errno.h> 5 #include <string.h> 6 #include "./editor.h" 7 #include "./common.h" 8 9 void editor_backspace(Editor *e) 10 { 11 if (e->cursor > e->data.count) { 12 e->cursor = e->data.count; 13 } 14 if (e->cursor == 0) return; 15 16 memmove( 17 &e->data.items[e->cursor - 1], 18 &e->data.items[e->cursor], 19 e->data.count - e->cursor 20 ); 21 e->cursor -= 1; 22 e->data.count -= 1; 23 editor_retokenize(e); 24 } 25 26 void editor_delete(Editor *e) 27 { 28 if (e->cursor >= e->data.count) return; 29 memmove( 30 &e->data.items[e->cursor], 31 &e->data.items[e->cursor + 1], 32 e->data.count - e->cursor - 1 33 ); 34 e->data.count -= 1; 35 editor_retokenize(e); 36 } 37 38 // TODO: make sure that you always have new line at the end of the file while saving 39 // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206 40 41 Errno editor_save_as(Editor *e, const char *file_path) 42 { 43 printf("Saving as %s...\n", file_path); 44 Errno err = write_entire_file(file_path, e->data.items, e->data.count); 45 if (err != 0) return err; 46 e->file_path.count = 0; 47 sb_append_cstr(&e->file_path, file_path); 48 sb_append_null(&e->file_path); 49 return 0; 50 } 51 52 Errno editor_save(const Editor *e) 53 { 54 assert(e->file_path.count > 0); 55 printf("Saving as %s...\n", e->file_path.items); 56 return write_entire_file(e->file_path.items, e->data.items, e->data.count); 57 } 58 59 Errno editor_load_from_file(Editor *e, const char *file_path) 60 { 61 printf("Loading %s\n", file_path); 62 63 e->data.count = 0; 64 Errno err = read_entire_file(file_path, &e->data); 65 if (err != 0) return err; 66 67 e->cursor = 0; 68 69 editor_retokenize(e); 70 71 e->file_path.count = 0; 72 sb_append_cstr(&e->file_path, file_path); 73 sb_append_null(&e->file_path); 74 75 return 0; 76 } 77 78 size_t editor_cursor_row(const Editor *e) 79 { 80 assert(e->lines.count > 0); 81 for (size_t row = 0; row < e->lines.count; ++row) { 82 Line line = e->lines.items[row]; 83 if (line.begin <= e->cursor && e->cursor <= line.end) { 84 return row; 85 } 86 } 87 return e->lines.count - 1; 88 } 89 90 void editor_move_line_up(Editor *e) 91 { 92 size_t cursor_row = editor_cursor_row(e); 93 size_t cursor_col = e->cursor - e->lines.items[cursor_row].begin; 94 if (cursor_row > 0) { 95 Line next_line = e->lines.items[cursor_row - 1]; 96 size_t next_line_size = next_line.end - next_line.begin; 97 if (cursor_col > next_line_size) cursor_col = next_line_size; 98 e->cursor = next_line.begin + cursor_col; 99 } 100 } 101 102 void editor_move_line_down(Editor *e) 103 { 104 size_t cursor_row = editor_cursor_row(e); 105 size_t cursor_col = e->cursor - e->lines.items[cursor_row].begin; 106 if (cursor_row < e->lines.count - 1) { 107 Line next_line = e->lines.items[cursor_row + 1]; 108 size_t next_line_size = next_line.end - next_line.begin; 109 if (cursor_col > next_line_size) cursor_col = next_line_size; 110 e->cursor = next_line.begin + cursor_col; 111 } 112 } 113 114 void editor_move_char_left(Editor *e) 115 { 116 if (e->cursor > 0) e->cursor -= 1; 117 } 118 119 void editor_move_char_right(Editor *e) 120 { 121 if (e->cursor < e->data.count) e->cursor += 1; 122 } 123 124 void editor_move_word_left(Editor *e) 125 { 126 while (e->cursor > 0 && !isalnum(e->data.items[e->cursor - 1])) { 127 e->cursor -= 1; 128 } 129 while (e->cursor > 0 && isalnum(e->data.items[e->cursor - 1])) { 130 e->cursor -= 1; 131 } 132 } 133 134 void editor_move_word_right(Editor *e) 135 { 136 while (e->cursor < e->data.count && !isalnum(e->data.items[e->cursor])) { 137 e->cursor += 1; 138 } 139 while (e->cursor < e->data.count && isalnum(e->data.items[e->cursor])) { 140 e->cursor += 1; 141 } 142 } 143 144 void editor_insert_char(Editor *e, char x) 145 { 146 editor_insert_buf(e, &x, 1); 147 } 148 149 void editor_insert_buf(Editor *e, char *buf, size_t buf_len) 150 { 151 if (e->cursor > e->data.count) { 152 e->cursor = e->data.count; 153 } 154 155 for (size_t i = 0; i < buf_len; ++i) { 156 da_append(&e->data, '\0'); 157 } 158 memmove( 159 &e->data.items[e->cursor + buf_len], 160 &e->data.items[e->cursor], 161 e->data.count - e->cursor - buf_len 162 ); 163 memcpy(&e->data.items[e->cursor], buf, buf_len); 164 e->cursor += buf_len; 165 editor_retokenize(e); 166 } 167 168 void editor_retokenize(Editor *e) 169 { 170 // Lines 171 { 172 e->lines.count = 0; 173 174 Line line; 175 line.begin = 0; 176 177 for (size_t i = 0; i < e->data.count; ++i) { 178 if (e->data.items[i] == '\n') { 179 line.end = i; 180 da_append(&e->lines, line); 181 line.begin = i + 1; 182 } 183 } 184 185 line.end = e->data.count; 186 da_append(&e->lines, line); 187 } 188 189 // Syntax Highlighting 190 { 191 e->tokens.count = 0; 192 Lexer l = lexer_new(e->atlas, e->data.items, e->data.count); 193 Token t = lexer_next(&l); 194 while (t.kind != TOKEN_END) { 195 da_append(&e->tokens, t); 196 t = lexer_next(&l); 197 } 198 } 199 } 200 201 bool editor_line_starts_with(Editor *e, size_t row, size_t col, const char *prefix) 202 { 203 size_t prefix_len = strlen(prefix); 204 if (prefix_len == 0) { 205 return true; 206 } 207 Line line = e->lines.items[row]; 208 if (col + prefix_len - 1 >= line.end) { 209 return false; 210 } 211 for (size_t i = 0; i < prefix_len; ++i) { 212 if (prefix[i] != e->data.items[line.begin + col + i]) { 213 return false; 214 } 215 } 216 return true; 217 } 218 219 const char *editor_line_starts_with_one_of(Editor *e, size_t row, size_t col, const char **prefixes, size_t prefixes_count) 220 { 221 for (size_t i = 0; i < prefixes_count; ++i) { 222 if (editor_line_starts_with(e, row, col, prefixes[i])) { 223 return prefixes[i]; 224 } 225 } 226 return NULL; 227 } 228 229 void editor_render(SDL_Window *window, Free_Glyph_Atlas *atlas, Simple_Renderer *sr, Editor *editor) 230 { 231 int w, h; 232 SDL_GetWindowSize(window, &w, &h); 233 234 float max_line_len = 0.0f; 235 236 sr->resolution = vec2f(w, h); 237 sr->time = (float) SDL_GetTicks() / 1000.0f; 238 239 // Render selection 240 { 241 simple_renderer_set_shader(sr, SHADER_FOR_COLOR); 242 if (editor->selection) { 243 for (size_t row = 0; row < editor->lines.count; ++row) { 244 size_t select_begin_chr = editor->select_begin; 245 size_t select_end_chr = editor->cursor; 246 if (select_begin_chr > select_end_chr) { 247 SWAP(size_t, select_begin_chr, select_end_chr); 248 } 249 250 Line line_chr = editor->lines.items[row]; 251 252 if (select_begin_chr < line_chr.begin) { 253 select_begin_chr = line_chr.begin; 254 } 255 256 if (select_end_chr > line_chr.end) { 257 select_end_chr = line_chr.end; 258 } 259 260 if (select_begin_chr <= select_end_chr) { 261 Vec2f select_begin_scr = vec2f(0, -((float)row + CURSOR_OFFSET) * FREE_GLYPH_FONT_SIZE); 262 free_glyph_atlas_measure_line_sized( 263 atlas, editor->data.items + line_chr.begin, select_begin_chr - line_chr.begin, 264 &select_begin_scr); 265 266 Vec2f select_end_scr = select_begin_scr; 267 free_glyph_atlas_measure_line_sized( 268 atlas, editor->data.items + select_begin_chr, select_end_chr - select_begin_chr, 269 &select_end_scr); 270 271 Vec4f selection_color = vec4f(.25, .25, .25, 1); 272 simple_renderer_solid_rect(sr, select_begin_scr, vec2f(select_end_scr.x - select_begin_scr.x, FREE_GLYPH_FONT_SIZE), selection_color); 273 } 274 } 275 } 276 simple_renderer_flush(sr); 277 } 278 279 // Render text 280 { 281 simple_renderer_set_shader(sr, SHADER_FOR_TEXT); 282 for (size_t i = 0; i < editor->tokens.count; ++i) { 283 Token token = editor->tokens.items[i]; 284 Vec2f pos = token.position; 285 Vec4f color = vec4fs(1); 286 switch (token.kind) { 287 case TOKEN_PREPROC: 288 color = hex_to_vec4f(0x95A99FFF); 289 break; 290 case TOKEN_KEYWORD: 291 color = hex_to_vec4f(0xFFDD33FF); 292 break; 293 case TOKEN_COMMENT: 294 color = hex_to_vec4f(0xCC8C3CFF); 295 break; 296 case TOKEN_STRING: 297 color = hex_to_vec4f(0x73c936ff); 298 break; 299 default: 300 {} 301 } 302 free_glyph_atlas_render_line_sized(atlas, sr, token.text, token.text_len, &pos, color); 303 // TODO: the max_line_len should be calculated based on what's visible on the screen right now 304 if (max_line_len < pos.x) max_line_len = pos.x; 305 } 306 simple_renderer_flush(sr); 307 } 308 309 Vec2f cursor_pos = vec2fs(0.0f); 310 { 311 size_t cursor_row = editor_cursor_row(editor); 312 Line line = editor->lines.items[cursor_row]; 313 size_t cursor_col = editor->cursor - line.begin; 314 cursor_pos.y = -((float)cursor_row + CURSOR_OFFSET) * FREE_GLYPH_FONT_SIZE; 315 cursor_pos.x = free_glyph_atlas_cursor_pos( 316 atlas, 317 editor->data.items + line.begin, line.end - line.begin, 318 vec2f(0.0, cursor_pos.y), 319 cursor_col 320 ); 321 } 322 323 // Render cursor 324 simple_renderer_set_shader(sr, SHADER_FOR_COLOR); 325 { 326 float CURSOR_WIDTH = 5.0f; 327 Uint32 CURSOR_BLINK_THRESHOLD = 500; 328 Uint32 CURSOR_BLINK_PERIOD = 1000; 329 Uint32 t = SDL_GetTicks() - editor->last_stroke; 330 331 sr->verticies_count = 0; 332 if (t < CURSOR_BLINK_THRESHOLD || t/CURSOR_BLINK_PERIOD%2 != 0) { 333 simple_renderer_solid_rect( 334 sr, 335 cursor_pos, vec2f(CURSOR_WIDTH, FREE_GLYPH_FONT_SIZE), 336 vec4fs(1)); 337 } 338 339 simple_renderer_flush(sr); 340 } 341 342 // Update camera 343 { 344 if (max_line_len > 1000.0f) { 345 max_line_len = 1000.0f; 346 } 347 348 float target_scale = w/3/(max_line_len*0.75); // TODO: division by 0 349 350 Vec2f target = cursor_pos; 351 float offset = 0.0f; 352 353 if (target_scale > 3.0f) { 354 target_scale = 3.0f; 355 } else { 356 offset = cursor_pos.x - w/3/sr->camera_scale; 357 if (offset < 0.0f) offset = 0.0f; 358 target = vec2f(w/3/sr->camera_scale + offset, cursor_pos.y); 359 } 360 361 sr->camera_vel = vec2f_mul( 362 vec2f_sub(target, sr->camera_pos), 363 vec2fs(2.0f)); 364 sr->camera_scale_vel = (target_scale - sr->camera_scale) * 2.0f; 365 366 sr->camera_pos = vec2f_add(sr->camera_pos, vec2f_mul(sr->camera_vel, vec2fs(DELTA_TIME))); 367 sr->camera_scale = sr->camera_scale + sr->camera_scale_vel * DELTA_TIME; 368 } 369 } 370 371 void editor_update_selection(Editor *e, bool shift) 372 { 373 if (shift) { 374 if (!e->selection) { 375 e->selection = true; 376 e->select_begin = e->cursor; 377 } 378 } else { 379 if (e->selection) { 380 e->selection = false; 381 } 382 } 383 } 384 385 void editor_clipboard_copy(Editor *e) 386 { 387 if (e->selection) { 388 size_t begin = e->select_begin; 389 size_t end = e->cursor; 390 if (begin > end) SWAP(size_t, begin, end); 391 392 e->clipboard.count = 0; 393 sb_append_buf(&e->clipboard, &e->data.items[begin], end - begin + 1); 394 sb_append_null(&e->clipboard); 395 396 if (SDL_SetClipboardText(e->clipboard.items) < 0) { 397 fprintf(stderr, "ERROR: SDL ERROR: %s\n", SDL_GetError()); 398 } 399 } 400 } 401 402 void editor_clipboard_paste(Editor *e) 403 { 404 char *text = SDL_GetClipboardText(); 405 size_t text_len = strlen(text); 406 if (text_len > 0) { 407 editor_insert_buf(e, text, text_len); 408 } else { 409 fprintf(stderr, "ERROR: SDL ERROR: %s\n", SDL_GetError()); 410 } 411 SDL_free(text); 412 }
