From 81354f84a463ef782f53358a3a3f9b359ece9a64 Mon Sep 17 00:00:00 2001 From: pommicket Date: Sun, 6 Aug 2023 22:48:10 -0400 Subject: rework edit notify --- buffer.c | 57 ++++++++++++++++++++++++--------------------------------- find.c | 17 +++++++++++++++++ main.c | 9 +++++++-- ted-internal.h | 14 ++++++++++---- ted.c | 20 ++++++++++++++++++++ ted.h | 32 ++++++++++++++++++++++++-------- 6 files changed, 102 insertions(+), 47 deletions(-) diff --git a/buffer.c b/buffer.c index efed7fe..2c8e8e2 100644 --- a/buffer.c +++ b/buffer.c @@ -24,12 +24,6 @@ struct BufferEdit { double time; // time at start of edit (i.e. the time just before the edit), in seconds since epoch }; -struct EditNotifyInfo { - EditNotify fn; - void *context; - EditNotifyID id; -}; - // this is a macro so we get -Wformat warnings #define buffer_error(buffer, ...) \ snprintf(buffer->error, sizeof buffer->error - 1, __VA_ARGS__) @@ -791,7 +785,6 @@ void buffer_free(TextBuffer *buffer) { arr_free(buffer->undo_history); arr_free(buffer->redo_history); - arr_free(buffer->edit_notifys); memset(buffer, 0, sizeof *buffer); } @@ -1739,9 +1732,17 @@ BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32 BufferPos b = {.line = line_idx, .index = index}; free(str_alloc); + const EditInfo info = { + .pos = pos, + .chars_deleted = 0, + .newlines_deleted = 0, + .chars_inserted = insertion_len, + .newlines_inserted = n_added_lines, + }; + signature_help_retrigger(buffer->ted); - arr_foreach_ptr(buffer->edit_notifys, EditNotifyInfo, n) { - n->fn(buffer, n->context, pos, 0, insertion_len); + arr_foreach_ptr(buffer->ted->edit_notifys, EditNotifyInfo, n) { + n->fn(n->context, buffer, &info); } return b; @@ -2209,6 +2210,8 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_) u32 line_idx = pos.line; u32 index = pos.index; Line *line = &buffer->lines[line_idx], *lines_end = &buffer->lines[buffer->nlines]; + u32 newlines_deleted = 0; + if (nchars + index > line->len) { // delete rest of line nchars -= line->len - index + 1; // +1 for the newline that got deleted @@ -2223,6 +2226,7 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_) // delete everything to the end of the file for (u32 idx = line_idx + 1; idx < buffer->nlines; ++idx) { buffer_line_free(&buffer->lines[idx]); + ++newlines_deleted; } buffer_shorten(buffer, line_idx + 1); } else { @@ -2235,8 +2239,8 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_) // remove all lines between line + 1 and last_line (inclusive). buffer_delete_lines(buffer, line_idx + 1, (u32)(last_line - line)); - u32 lines_removed = (u32)(last_line - line); - buffer_shorten(buffer, buffer->nlines - lines_removed); + newlines_deleted = (u32)(last_line - line); + buffer_shorten(buffer, buffer->nlines - newlines_deleted); } } else { // just delete characters from this line @@ -2254,8 +2258,15 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_) buffer_lines_modified(buffer, line_idx, line_idx); signature_help_retrigger(buffer->ted); - arr_foreach_ptr(buffer->edit_notifys, EditNotifyInfo, info) { - info->fn(buffer, info->context, pos, deletion_len, 0); + const EditInfo info = { + .pos = pos, + .chars_inserted = 0, + .newlines_inserted = 0, + .chars_deleted = deletion_len, + .newlines_deleted = newlines_deleted, + }; + arr_foreach_ptr(buffer->ted->edit_notifys, EditNotifyInfo, n) { + n->fn(n->context, buffer, &info); } } @@ -3519,23 +3530,3 @@ void buffer_highlight_lsp_range(TextBuffer *buffer, LSPRange range, ColorSetting gl_geometry_rect(r2, colors[COLOR_HOVER_HL]); } } - -u64 buffer_add_edit_notify(TextBuffer *buffer, EditNotify notify, void *context) { - EditNotifyInfo info = { - .fn = notify, - .context = context, - .id = ++buffer->edit_notify_id, - }; - arr_add(buffer->edit_notifys, info); - return info.id; -} - -void buffer_remove_edit_notify(TextBuffer *buffer, EditNotifyID id) { - u32 i; - for (i = 0; i < arr_len(buffer->edit_notifys); ++i) { - if (buffer->edit_notifys[i].id == id) { - arr_remove(buffer->edit_notifys, i); - break; - } - } -} diff --git a/find.c b/find.c index de5ec15..046cef1 100644 --- a/find.c +++ b/find.c @@ -25,6 +25,23 @@ TextBuffer *find_search_buffer(Ted *ted) { return ted->prev_active_buffer; } +static void find_edit_notify(void *context, TextBuffer *buffer, const EditInfo *info) { + (void)context; + Ted *ted = buffer->ted; + if (!ted->find) { + return; + } + if (buffer != find_search_buffer(ted)) + return; + + // TODO: update find result locations +// printf("%s %u\n",buffer_get_path(buffer),info->newlines_inserted); +} + +void find_init(Ted *ted) { + ted_add_edit_notify(ted, find_edit_notify, NULL); +} + static void ted_error_from_pcre2_error(Ted *ted, int err) { char32_t buf[256] = {0}; diff --git a/main.c b/main.c index 19d4b6c..3dd4fe5 100644 --- a/main.c +++ b/main.c @@ -1,9 +1,11 @@ /* +TODO: +- robust find (results shouldn't move around when you type things) + FUTURE FEATURES: - autodetect indentation (tabs vs spaces) -- robust find (results shouldn't move around when you type things) - config variables -- bind key to multiple commands +- bind key to series of commands - convert macro to command list - plugins? - built-in plugins @@ -501,6 +503,7 @@ int main(int argc, char **argv) { hover_init(ted); rename_symbol_init(ted); document_link_init(ted); + find_init(ted); PROFILE_TIME(gl_end) @@ -1193,6 +1196,8 @@ int main(int argc, char **argv) { rename_symbol_quit(ted); document_link_quit(ted); menu_quit(ted); + arr_free(ted->edit_notifys); + for (int i = 0; i < TED_LSP_MAX; ++i) { if (!ted->lsps[i]) break; diff --git a/ted-internal.h b/ted-internal.h index fdd46ef..3f5481a 100644 --- a/ted-internal.h +++ b/ted-internal.h @@ -167,7 +167,11 @@ typedef struct ConfigPart ConfigPart; /// A single undoable edit to a buffer typedef struct BufferEdit BufferEdit; -typedef struct EditNotifyInfo EditNotifyInfo; +typedef struct EditNotifyInfo { + EditNotify fn; + void *context; + EditNotifyID id; +} EditNotifyInfo; struct TextBuffer { /// NULL if this buffer is untitled or doesn't correspond to a file (e.g. line buffers) @@ -250,9 +254,6 @@ struct TextBuffer { BufferEdit *undo_history; /// dynamic array of redo history BufferEdit *redo_history; - - u64 edit_notify_id; - EditNotifyInfo *edit_notifys; }; /// an entry in a selector menu (e.g. the "open" menu) @@ -588,6 +589,10 @@ struct Ted { MessageType message_type; MessageType message_shown_type; char message_shown[512]; + + + u64 edit_notify_id; + EditNotifyInfo *edit_notifys; }; // === buffer.c === @@ -661,6 +666,7 @@ void config_free(Ted *ted); long context_score(const char *path, Language lang, const SettingsContext *context); // === find.c === +void find_init(Ted *ted); /// height of the find/find+replace menu in pixels float find_menu_height(Ted *ted); void find_menu_frame(Ted *ted, Rect menu_bounds); diff --git a/ted.c b/ted.c index 175e905..14cc440 100644 --- a/ted.c +++ b/ted.c @@ -859,3 +859,23 @@ void ted_color_settings_for_message_type(MessageType type, ColorSetting *bg_colo } } + +u64 ted_add_edit_notify(Ted *ted, EditNotify notify, void *context) { + EditNotifyInfo info = { + .fn = notify, + .context = context, + .id = ++ted->edit_notify_id, + }; + arr_add(ted->edit_notifys, info); + return info.id; +} + +void ted_remove_edit_notify(Ted *ted, EditNotifyID id) { + u32 i; + for (i = 0; i < arr_len(ted->edit_notifys); ++i) { + if (ted->edit_notifys[i].id == id) { + arr_remove(ted->edit_notifys, i); + break; + } + } +} diff --git a/ted.h b/ted.h index 1b9338a..66e8c04 100644 --- a/ted.h +++ b/ted.h @@ -281,12 +281,28 @@ typedef struct { char reserved[128]; } MenuInfo; +/// information about an edit provided to \ref EditNotify. +/// +/// NOTE: more members may be added in the future (this does not affect backwards compatibility) +typedef struct { + /// position where the edit took place + BufferPos pos; + /// number of characters (unicode codepoints, including newlines) deleted + u32 chars_deleted; + /// number of characters (unicode codepoints, including newlines) inserted + u32 chars_inserted; + /// number of newlines deleted + u32 newlines_deleted; + /// number of newlines inserted + u32 newlines_inserted; +} EditInfo; + /// this type of callback is called right after an edit is made to the buffer. /// /// you will be given the number of characters deleted at the position, the number /// of characters inserted after the position, and the context pointer -/// which was passed to \ref buffer_add_edit_notify. -typedef void (*EditNotify)(TextBuffer *buffer, void *context, BufferPos pos, u32 chars_deleted, u32 chars_inserted); +/// which was passed to \ref ted_add_edit_notify. +typedef void (*EditNotify)(void *context, TextBuffer *buffer, const EditInfo *info); typedef u64 EditNotifyID; @@ -642,12 +658,6 @@ int buffer_pos_cmp(BufferPos p1, BufferPos p2); /// returns "`p2 - p1`", that is, the number of characters between `p1` and `p2`, /// but negative if `p1` comes after `p2`. i64 buffer_pos_diff(TextBuffer *buffer, BufferPos p1, BufferPos p2); -/// add a \ref EditNotify callback which will be called whenever `buffer` is edited. -/// -/// returns an ID which can be used with \ref buffer_remove_edit_notify -EditNotifyID buffer_add_edit_notify(TextBuffer *buffer, EditNotify notify, void *context); -/// remove edit notify callback. if `id` is zero or invalid, no action is taken. -void buffer_remove_edit_notify(TextBuffer *buffer, EditNotifyID id); // === build.c === /// clear build errors and stop @@ -1021,6 +1031,12 @@ Status ted_get_mouse_buffer_pos(Ted *ted, TextBuffer **pbuffer, BufferPos *ppos) void ted_flash_error_cursor(Ted *ted); /// how tall is a line buffer? float ted_line_buffer_height(Ted *ted); +/// add a \ref EditNotify callback which will be called whenever `buffer` is edited. +/// +/// returns an ID which can be used with \ref ted_remove_edit_notify +EditNotifyID ted_add_edit_notify(Ted *ted, EditNotify notify, void *context); +/// remove edit notify callback. if `id` is zero or invalid, no action is taken. +void ted_remove_edit_notify(Ted *ted, EditNotifyID id); // === ui.c === /// move selector cursor up by `n` entries -- cgit v1.2.3