From cdca3cc10dceda9580b2d87c2105c0654aa084fc Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Sat, 13 Feb 2021 13:33:05 -0500 Subject: removed line->capacity also fixed shift+click to select --- README.md | 1 + buffer.c | 75 ++++++++++++++++++++++++++++++++++++++------------------------- main.c | 16 +++----------- ted.h | 3 +-- util.c | 18 +++++++++++++++ 5 files changed, 68 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index d7a121e..22878d3 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ a simple editor that starts up practically instantaneously, and performs well on - Auto-indent - Customization of (pretty much) all colours and keyboard commands. - Syntax highlighting for C, C++, Rust, and Python. +- Find and replace (with regular expressions!) ## Building from source diff --git a/buffer.c b/buffer.c index 9ac5fd5..7bf1c74 100644 --- a/buffer.c +++ b/buffer.c @@ -536,26 +536,37 @@ static void buffer_remove_last_edit_if_empty(TextBuffer *buffer) { } } -// grow capacity of line to at least minimum_capacity // returns true if allocation was succesful -static Status buffer_line_set_min_capacity(TextBuffer *buffer, Line *line, u32 minimum_capacity) { - while (line->capacity < minimum_capacity) { - // double capacity of line - u32 new_capacity = line->capacity == 0 ? 4 : line->capacity * 2; - if (new_capacity < line->capacity) { - // this could only happen if line->capacity * 2 overflows. - buffer_seterr(buffer, "Line %td is too large.", line - buffer->lines); - return false; +static Status buffer_line_set_len(TextBuffer *buffer, Line *line, u32 new_len) { + if (new_len >= 8) { + u32 curr_capacity = (u32)1 << (32 - util_count_leading_zeroes(line->len)); + + if (new_len >= curr_capacity) { + u8 leading_zeroes = util_count_leading_zeroes(new_len); + if (leading_zeroes == 0) { + // this line is too big + return false; + } else { + u32 new_capacity = (u32)1 << (32 - leading_zeroes); + assert(new_capacity > new_len); + char32_t *new_str = buffer_realloc(buffer, line->str, new_capacity * sizeof *line->str); + if (!new_str) { + // allocation failed ): + return false; + } + // allocation successful + line->str = new_str; + } } - char32_t *new_str = buffer_realloc(buffer, line->str, new_capacity * sizeof *line->str); - if (!new_str) { - // allocation failed ): + } else if (line->len == 0) { + // start by allocating 8 code points + line->str = buffer_malloc(buffer, 8 * sizeof *line->str); + if (!line->str) { + // ): return false; } - // allocation successful - line->str = new_str; - line->capacity = new_capacity; } + line->len = new_len; return true; } @@ -579,8 +590,8 @@ static Status buffer_lines_set_min_capacity(TextBuffer *buffer, Line **lines, u3 } static void buffer_line_append_char(TextBuffer *buffer, Line *line, char32_t c) { - if (buffer_line_set_min_capacity(buffer, line, line->len + 1)) - line->str[line->len++] = c; + if (buffer_line_set_len(buffer, line, line->len + 1)) + line->str[line->len-1] = c; } static void buffer_line_free(Line *line) { @@ -695,7 +706,13 @@ void buffer_text_dimensions(TextBuffer *buffer, u32 *lines, u32 *columns) { *lines = buffer->nlines; } if (columns) { - *columns = buffer->longest_line_on_screen; + u32 longest_line = 0; + // which line on screen is the longest? + for (u32 l = buffer->first_line_on_screen; l <= buffer->last_line_on_screen && l < buffer->nlines; ++l) { + Line *line = &buffer->lines[l]; + longest_line = max_u32(longest_line, line->len); + } + *columns = longest_line; } } @@ -719,6 +736,7 @@ static void buffer_correct_scroll(TextBuffer *buffer) { u32 nlines, ncols; buffer_text_dimensions(buffer, &nlines, &ncols); double max_scroll_x = (double)ncols - buffer_display_cols(buffer); + max_scroll_x += 2; // allow "overscroll" (makes it so you can see the cursor when it's on the right side of the screen) double max_scroll_y = (double)nlines - buffer_display_lines(buffer); if (max_scroll_x <= 0) { buffer->scroll_x = 0; @@ -1225,10 +1243,9 @@ BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32 Line *last_line = &buffer->lines[line_idx + n_added_lines]; u32 chars_moved = line->len - index; if (chars_moved) { - if (buffer_line_set_min_capacity(buffer, last_line, chars_moved)) { + if (buffer_line_set_len(buffer, last_line, chars_moved)) { memcpy(last_line->str, line->str + index, chars_moved * sizeof(char32_t)); line->len -= chars_moved; - last_line->len += chars_moved; } } } @@ -1240,15 +1257,13 @@ BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32 u32 old_len = line->len; u32 new_len = old_len + text_line_len; if (new_len > old_len) { // handles both overflow and empty text lines - if (buffer_line_set_min_capacity(buffer, line, new_len)) { + if (buffer_line_set_len(buffer, line, new_len)) { // make space for text memmove(line->str + index + (new_len - old_len), line->str + index, (old_len - index) * sizeof(char32_t)); // insert text memcpy(line->str + index, str.str, text_line_len * sizeof(char32_t)); - - line->len = new_len; } str.str += text_line_len; @@ -1490,11 +1505,11 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_) } buffer_shorten(buffer, line_idx + 1); } else { - // join last_line to line. + // join last_line[nchars:] to line. u32 last_line_chars_left = (u32)(last_line->len - nchars); - if (buffer_line_set_min_capacity(buffer, line, line->len + last_line_chars_left)) { - memcpy(line->str + line->len, last_line->str + nchars, last_line_chars_left * sizeof(char32_t)); - line->len += last_line_chars_left; + u32 old_len = line->len; + if (buffer_line_set_len(buffer, line, old_len + last_line_chars_left)) { + memcpy(line->str + old_len, last_line->str + nchars, last_line_chars_left * sizeof(char32_t)); } // remove all lines between line + 1 and last_line (inclusive). buffer_delete_lines(buffer, line_idx + 1, (u32)(last_line - line)); @@ -2139,8 +2154,6 @@ void buffer_render(TextBuffer *buffer, Rect r) { buffer->frame_earliest_line_modified = U32_MAX; buffer->frame_latest_line_modified = 0; - buffer->longest_line_on_screen = 0; - TextRenderState text_state = text_render_state_default; text_state.x = render_start_x; @@ -2151,9 +2164,10 @@ void buffer_render(TextBuffer *buffer, Rect r) { text_state.max_y = y2; if (!syntax_highlighting) rgba_u32_to_floats(colors[COLOR_TEXT], text_state.color); + + buffer->first_line_on_screen = start_line; for (u32 line_idx = start_line; line_idx < nlines; ++line_idx) { Line *line = &lines[line_idx]; - buffer->longest_line_on_screen = max_u32(buffer->longest_line_on_screen, line->len); if (arr_len(char_types) < line->len) { arr_set_len(char_types, line->len); } @@ -2187,6 +2201,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { // next line text_state.x = render_start_x; if (text_state.y > text_state.max_y) { + buffer->last_line_on_screen = line_idx; // made it to the bottom of the buffer view. break; } diff --git a/main.c b/main.c index 2d13318..772a8b3 100644 --- a/main.c +++ b/main.c @@ -356,8 +356,9 @@ int main(int argc, char **argv) { #if DEBUG //printf("\033[H\033[2J"); #endif + #if PROFILE double frame_start = time_get_seconds(); - + #endif SDL_Event event; Uint8 const *keyboard_state = SDL_GetKeyboardState(NULL); @@ -398,14 +399,6 @@ int main(int argc, char **argv) { } break; case SDL_MOUSEBUTTONDOWN: { Uint32 button = event.button.button; - - if (button == SDL_BUTTON_LEFT) { - // shift+left click = right click - if (shift_down) button = SDL_BUTTON_RIGHT; - // ctrl+left click = middle click - if (ctrl_down) button = SDL_BUTTON_MIDDLE; - } - float x = (float)event.button.x, y = (float)event.button.y; if (button < arr_count(ted->nmouse_clicks) @@ -658,16 +651,13 @@ int main(int argc, char **argv) { glFinish(); - double frame_end_noswap = time_get_seconds(); #if PROFILE + double frame_end_noswap = time_get_seconds(); { print("Frame (noswap): %.1f ms\n", (frame_end_noswap - frame_start) * 1000); } #endif - u32 ms_wait = (u32)((frame_end_noswap - frame_start) * 1000); - if (ms_wait) ms_wait -= 1; // give swap an extra ms to make sure it's actually vsynced - SDL_Delay(ms_wait); SDL_GL_SwapWindow(window); PROFILE_TIME(frame_end); diff --git a/ted.h b/ted.h index 60cb06d..15a2dca 100644 --- a/ted.h +++ b/ted.h @@ -108,7 +108,6 @@ typedef struct { typedef struct { SyntaxState syntax; u32 len; - u32 capacity; char32_t *str; } Line; @@ -142,7 +141,7 @@ typedef struct { u32 lines_capacity; u32 undo_history_write_pos; // where in the undo history was the last write? used by buffer_unsaved_changes - u32 longest_line_on_screen; // length of the longest line on screen. used to determine how far right we can scroll. + u32 first_line_on_screen, last_line_on_screen; // which lines are on screen? updated when buffer_render is called. // to cache syntax highlighting properly, it is important to keep track of the // first and last line modified since last frame. diff --git a/util.c b/util.c index 1584e0b..73f1e02 100644 --- a/util.c +++ b/util.c @@ -1,3 +1,7 @@ +#if _WIN32 +#include +#endif + static u8 util_popcount(u64 x) { #ifdef __GNUC__ return (u8)__builtin_popcountll(x); @@ -11,6 +15,20 @@ static u8 util_popcount(u64 x) { #endif } +static u8 util_count_leading_zeroes(u64 x) { +#if __GNUC__ + return (u8)__builtin_clzll(x); +#elif _WIN32 + return (u8)__lzcnt64(x); +#else + u8 count = 0; + for (int i = 63; i >= 0; --i) + if (x & ((u64)1<