summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-12-27 15:16:54 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2020-12-27 15:16:54 -0500
commit0fcc0682080da33edc81fa98c450a904165d5b5a (patch)
tree4c3d330dafb2876dc5753250903e779ee5fbc06e
parenta3c71115434018e16c5f3c2a4c3672ee3a12b7dc (diff)
split edits based on time, fixed delete undo bug
-rw-r--r--buffer.c36
-rw-r--r--main.c1
-rw-r--r--time.c30
3 files changed, 54 insertions, 13 deletions
diff --git a/buffer.c b/buffer.c
index 308c12d..fac72af 100644
--- a/buffer.c
+++ b/buffer.c
@@ -18,7 +18,7 @@ typedef struct BufferEdit {
u32 new_len;
u32 prev_len;
char32_t *prev_text;
- double time; // time in seconds since epoch
+ double time; // time at start of edit (i.e. the time just before the edit), in seconds since epoch
} BufferEdit;
typedef struct {
@@ -288,6 +288,7 @@ static void buffer_pos_print(BufferPos p) {
}
static Status buffer_edit_create(TextBuffer *buffer, BufferEdit *edit, BufferPos start, u32 prev_len, u32 new_len) {
+ edit->time = time_get_seconds();
if (prev_len == 0)
edit->prev_text = NULL; // if there's no previous text, don't allocate anything
else
@@ -372,6 +373,15 @@ static bool buffer_edit_does_anything(TextBuffer *buffer, BufferEdit *edit) {
}
}
+// has enough time passed since the last edit that we should create a new one?
+static bool buffer_edit_split(TextBuffer *buffer) {
+ double curr_time = time_get_seconds();
+ double undo_time_cutoff = 6.0; // only keep around edits for this long (in seconds). @SETTINGS
+ BufferEdit *last_edit = arr_lastp(buffer->undo_history);
+ if (!last_edit) return true;
+ return curr_time - last_edit->time > undo_time_cutoff;
+}
+
// removes the last edit in the undo history if it doesn't do anything
static void buffer_remove_last_edit_if_empty(TextBuffer *buffer) {
if (buffer->store_undo_events) {
@@ -1106,12 +1116,16 @@ BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32
if (buffer->store_undo_events) {
BufferEdit *last_edit = arr_lastp(buffer->undo_history);
i64 where_in_last_edit = last_edit ? buffer_pos_diff(buffer, last_edit->pos, pos) : -1;
- if (where_in_last_edit >= 0 && where_in_last_edit <= (i64)last_edit->new_len) {
- // merge this edit into the previous one.
- last_edit->new_len += str.len;
- } else {
+ // create a new edit, rather than adding to the old one if:
+ bool create_new_edit = where_in_last_edit < 0 || where_in_last_edit > last_edit->new_len // insertion is happening outside the previous edit,
+ || buffer_edit_split(buffer); // or enough time has elapsed to warrant a new one.
+
+ if (create_new_edit) {
// create a new edit for this insertion
buffer_edit(buffer, pos, 0, (u32)str.len);
+ } else {
+ // merge this edit into the previous one.
+ last_edit->new_len += str.len;
}
}
@@ -1249,7 +1263,9 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_)
bool create_new_edit =
!last_edit || // if there is no previous edit to combine it with
buffer_pos_cmp(del_end, edit_start) < 0 || // or if delete does not overlap last_edit
- buffer_pos_cmp(del_start, edit_end) > 0;
+ buffer_pos_cmp(del_start, edit_end) > 0 ||
+ buffer_edit_split(buffer); // or if enough time has passed to warrant a new edit
+
if (create_new_edit) {
// create a new edit
buffer_edit(buffer, pos, nchars, 0);
@@ -1261,7 +1277,7 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_)
u32 updated_prev_len = (u32)(chars_before_edit + last_edit->prev_len);
if (buffer_edit_resize_prev_text(buffer, last_edit, updated_prev_len)) {
// make space
- memmove(last_edit->prev_text + chars_before_edit, last_edit->prev_text, last_edit->prev_len);
+ memmove(last_edit->prev_text + chars_before_edit, last_edit->prev_text, last_edit->prev_len * sizeof(char32_t));
// prepend these chracters to the edit's text
buffer_get_text_at_pos(buffer, del_start, last_edit->prev_text, (size_t)chars_before_edit);
@@ -1287,8 +1303,10 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_)
if (new_text_del_start < 0) new_text_del_start = 0;
i64 new_text_del_end = buffer_pos_diff(buffer, edit_start, del_end);
if (new_text_del_end > last_edit->new_len) new_text_del_end = last_edit->new_len;
- // shrink length to get rid of that text
- last_edit->new_len -= new_text_del_end - new_text_del_start;
+ if (new_text_del_end > new_text_del_start) {
+ // shrink length to get rid of that text
+ last_edit->new_len -= new_text_del_end - new_text_del_start;
+ }
}
}
diff --git a/main.c b/main.c
index 790503a..ae197ac 100644
--- a/main.c
+++ b/main.c
@@ -9,6 +9,7 @@ no_warn_end
#include <GL/gl.h>
#include <locale.h>
#include <wctype.h>
+#include "time.c"
#include "unicode.h"
#include "util.c"
#define MATH_GL
diff --git a/time.c b/time.c
index fb007ba..fdd5278 100644
--- a/time.c
+++ b/time.c
@@ -1,16 +1,19 @@
#include <time.h>
#include <errno.h>
#include <sys/stat.h>
+#if _WIN32
+#include <sysinfoapi.h>
+#endif
static struct timespec time_last_modified(char const *filename) {
#if __unix__
- struct stat statbuf = {};
+ struct stat statbuf = {0};
stat(filename, &statbuf);
return statbuf.st_mtim;
#else
// windows' _stat does not have st_mtim
- struct _stat statbuf = {};
- struct timespec ts = {};
+ struct _stat statbuf = {0};
+ struct timespec ts = {0};
_stat(filename, &statbuf);
ts.tv_sec = statbuf.st_mtime;
return ts;
@@ -33,10 +36,29 @@ static struct timespec timespec_max(struct timespec a, struct timespec b) {
return timespec_cmp(a, b) < 0 ? b : a;
}
+static double timespec_to_seconds(struct timespec ts) {
+ return (double)ts.tv_sec
+ + (double)ts.tv_nsec * 0.000000001;
+}
+
+static struct timespec time_get(void) {
+ struct timespec ts = {0};
+#if _WIN32
+ timespec_get(&ts, TIME_UTC);
+#else
+ clock_gettime(CLOCK_REALTIME, &ts);
+#endif
+ return ts;
+}
+
+static double time_get_seconds(void) {
+ return timespec_to_seconds(time_get());
+}
+
// sleep for a certain number of nanoseconds
static void sleep_ns(u64 ns) {
#if __unix__
- struct timespec rem = {}, req = {
+ struct timespec rem = {0}, req = {
(time_t)(ns / 1000000000),
(long)(ns % 1000000000)
};