summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--buffer.c75
-rw-r--r--main.c16
-rw-r--r--ted.h3
-rw-r--r--util.c18
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 <intrin.h>
+#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<<i))
+ ++count;
+ return count;
+#endif
+}
+
static bool util_is_power_of_2(u64 x) {
return util_popcount(x) == 1;
}