diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2021-02-01 19:58:27 -0500 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2021-02-01 19:58:27 -0500 |
commit | bb9c6b6ff3ca196977f9ddd73120897c679e2515 (patch) | |
tree | ab908d86a55cb6266a10851d9a3fb2a492089e05 | |
parent | 01bfdf98e4475e13e7b4bb8b8fbd382fa836986e (diff) |
cache syntax highlighting
-rw-r--r-- | buffer.c | 49 | ||||
-rw-r--r-- | ted.h | 9 |
2 files changed, 47 insertions, 11 deletions
@@ -632,6 +632,8 @@ Status buffer_load_file(TextBuffer *buffer, char const *filename) { buffer_clear(buffer); buffer->lines = lines; buffer->nlines = nlines; + buffer->frame_earliest_line_modified = 0; + buffer->frame_latest_line_modified = nlines - 1; buffer->lines_capacity = lines_capacity; buffer->filename = filename_copy; } @@ -1270,6 +1272,16 @@ void buffer_cursor_move_to_end_of_file(TextBuffer *buffer) { buffer_cursor_move_to_pos(buffer, buffer_end_of_file(buffer)); } + +static void buffer_lines_modified(TextBuffer *buffer, u32 first_line, u32 last_line) { + assert(last_line >= first_line); + buffer->modified = true; + if (first_line < buffer->frame_earliest_line_modified) + buffer->frame_earliest_line_modified = first_line; + if (last_line > buffer->frame_latest_line_modified) + buffer->frame_latest_line_modified = last_line; +} + // insert `number` empty lines starting at index `where`. static Status buffer_insert_lines(TextBuffer *buffer, u32 where, u32 number) { assert(!buffer->is_line_buffer); @@ -1382,7 +1394,7 @@ BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32 // We need to put this after the end so the emptiness-checking is done after the edit is made. buffer_remove_last_edit_if_empty(buffer); - buffer->modified = true; + buffer_lines_modified(buffer, pos.line, line_idx); BufferPos b = {.line = line_idx, .index = index}; return b; @@ -1627,7 +1639,7 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_) // cursor position could have been invalidated by this edit buffer_validate_cursor(buffer); - buffer->modified = true; + buffer_lines_modified(buffer, line_idx, line_idx); } // Delete characters between the given buffer positions. Returns number of characters deleted. @@ -2002,27 +2014,44 @@ void buffer_render(TextBuffer *buffer, Rect r) { // scroll <= sel - scrolloff text_state.y -= (float)(buffer->scroll_y - start_line) * char_height; - SyntaxState syntax_state = {0}; Language language = buffer_language(buffer); // dynamic array of character types, to be filled by syntax_highlight SyntaxCharType *char_types = NULL; bool syntax_highlighting = language && settings->syntax_highlighting; - if (syntax_highlighting) { - for (u32 line_idx = 0; line_idx < start_line; ++line_idx) { - Line *line = &lines[line_idx]; - syntax_highlight(&syntax_state, language, line->str, line->len, NULL); - } - } else { + if (!syntax_highlighting) { gl_color_rgba(colors[COLOR_TEXT]); } + if (buffer->frame_latest_line_modified >= buffer->frame_earliest_line_modified) { + // update syntax cache + Line *earliest = &buffer->lines[buffer->frame_earliest_line_modified]; + Line *latest = &buffer->lines[buffer->frame_latest_line_modified]; + Line *buffer_last_line = &buffer->lines[buffer->nlines - 1]; + Line *start = earliest == buffer->lines ? earliest : earliest - 1; + + for (Line *line = start; line != buffer_last_line; ++line) { + SyntaxState syntax = line->syntax; + syntax_highlight(&syntax, language, line->str, line->len, NULL); + if (line > latest && line[1].syntax == syntax) { + // no further necessary changes to the cache + break; + } else { + line[1].syntax = syntax; + } + } + } + buffer->frame_earliest_line_modified = U32_MAX; + buffer->frame_latest_line_modified = 0; + for (u32 line_idx = start_line; line_idx < nlines; ++line_idx) { Line *line = &lines[line_idx]; if (arr_len(char_types) < line->len) { arr_set_len(char_types, line->len); } - if (language) + if (syntax_highlighting) { + SyntaxState syntax_state = line->syntax; syntax_highlight(&syntax_state, language, line->str, line->len, char_types); + } for (u32 i = 0; i < line->len; ++i) { char32_t c = line->str[i]; if (syntax_highlighting) { @@ -18,7 +18,7 @@ enum { SYNTAX_STATE_STRING = 1<<SYNTAX_STATE_STRING_SHIFT, }; -typedef u16 SyntaxState; +typedef u8 SyntaxState; ENUM_U16 { LANG_NONE, @@ -89,6 +89,7 @@ typedef struct { } BufferPos; typedef struct { + SyntaxState syntax; u32 len; u32 capacity; char32_t *str; @@ -116,6 +117,12 @@ typedef struct { float x1, y1, x2, y2; u32 nlines; u32 lines_capacity; + + // to cache syntax highlighting properly, it is important to keep track of the + // first and last line modified since last frame. + u32 frame_earliest_line_modified; + u32 frame_latest_line_modified; + Line *lines; char error[256]; BufferEdit *undo_history; // dynamic array of undo history |