ledit

Text editor (WIP)
git clone git://lumidify.org/ledit.git (fast, but not encrypted)
git clone https://lumidify.org/git/ledit.git (encrypted, but very slow)
Log | Files | Refs | README | LICENSE

commit 155a081f559a9ecfddd8b086c7d91187c2af4bc2
parent 81ddea61d765938b662b3456b3fe80369cfbc138
Author: lumidify <nobody@lumidify.org>
Date:   Wed, 25 Oct 2023 13:42:10 +0200

Fix crash and other misc. bugs

Diffstat:
Mbuffer.c | 14++++++++++----
Mkeys_basic.c | 8++++----
Mleditrc.5 | 6+++---
Mmemory.c | 4+++-
Mview.c | 30++++++++++++++----------------
5 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/buffer.c b/buffer.c @@ -574,8 +574,8 @@ buffer_insert_text_base(ledit_buffer *buffer, size_t line_index, size_t index, c ledit_assert(index <= line->len); /* \0 is not included in line->len */ resize_and_move_text_gap(line, add_sz3(line->len, len, 1), index); - /* the gap is now located at 'index' and least large enough to hold the new text */ - memcpy(line->text + index, text, len); + /* the gap is now located at 'index' and at least large enough to hold the new text */ + memmove(line->text + index, text, len); line->gap += len; line->len += len; for (size_t i = 0; i < buffer->views_num; i++) { @@ -920,8 +920,10 @@ buffer_delete_line_section_base(ledit_buffer *buffer, size_t line, size_t start, (void)add_sz(start, length); /* just check that no overflow */ ledit_assert(start + length <= l->len); if (start <= l->gap && start + length >= l->gap) { + /* range includes gap */ l->gap = start; - } else if (start < l->gap && start + length < l->gap) { + } else if (start < l->gap && start + length <= l->gap) { + /* entire range is before gap */ memmove( l->text + l->cap - l->len + start + length, l->text + start + length, @@ -929,11 +931,15 @@ buffer_delete_line_section_base(ledit_buffer *buffer, size_t line, size_t start, ); l->gap = start; } else { + /* entire range is after gap */ + /* move piece between end of gap and + start of range to beginning of gap */ memmove( l->text + l->gap, l->text + l->gap + l->cap - l->len, - start - l->gap - l->cap + l->len + start - l->gap ); + l->gap += start - l->gap; } l->len -= length; /* possibly decrease size of line */ diff --git a/keys_basic.c b/keys_basic.c @@ -1930,18 +1930,18 @@ move_cursor_up_down(ledit_view *view, int dir) { view_get_softline_bounds(view, new_line, new_softline, &start, &end); cb(view, new_line, start, KEY_MOTION_LINE); } else { - int lineno, x; + int lineno, x, diff = 0, old_line = view->cur_line; view_pos_to_x_softline(view, view->cur_line, view->cur_index, &x, &lineno); view->cur_index = view_x_softline_to_pos(view, new_line, x, new_softline); if (view->cur_line != new_line) - view_wipe_line_cursor_attrs(view, view->cur_line); + diff = 1; view->cur_line = new_line; if (view->mode == VISUAL) { view_set_selection(view, view->sel.line1, view->sel.byte1, view->cur_line, view->cur_index); - } else if (view->mode == INSERT && view->sel_valid) { - view_wipe_selection(view); } else if (view->mode == NORMAL) { + if (diff) + view_wipe_line_cursor_attrs(view, old_line); view_set_line_cursor_attrs(view, view->cur_line, view->cur_index); } view->redraw = 1; diff --git a/leditrc.5 b/leditrc.5 @@ -1,4 +1,4 @@ -.Dd October 5, 2023 +.Dd October 6, 2023 .Dt LEDITRC 5 .Os .Sh NAME @@ -68,7 +68,7 @@ Yes, this is inconsistent and confusing. As defined by Unicode (UAX #29). A grapheme may be composed of multiple Unicode characters. The cursor is only allowed to be at valid grapheme boundaries, but -some operations work with characters, while other work with graphemes. +some operations work with characters, while others work with graphemes. .It Ar paste buffer When text is deleted or explicitly copied (yanked), it is written to the paste buffer so that it can be pasted later. @@ -82,7 +82,7 @@ A hardline is an actual line separated from the other lines by a newline character. A softline is a displayed line, but might only be part of a hardline if the text is wrapped. -.Nm +.Xr ledit 1 can be in hardline or softline mode. Some commands change their behavior depending on this mode, for instance to move the cursor down a certain number of softlines instead of hardlines. diff --git a/memory.c b/memory.c @@ -162,6 +162,7 @@ resize_and_move_gap( size_t old_gap, size_t old_cap, size_t len, size_t min_size, size_t index, size_t *new_gap_ret, size_t *new_cap_ret) { + ledit_assert(array != NULL || (len == 0 && old_cap == 0)); ledit_assert(index <= len); ledit_assert(len <= old_cap); ledit_assert(old_gap <= len); @@ -213,7 +214,8 @@ resize_and_move_gap( /* otherwise, parts may be cut off */ ledit_assert(min_size >= len); /* FIXME: optimize this */ - move_gap(array, elem_size, len, old_gap, old_cap, len, NULL); + if (array) + move_gap(array, elem_size, len, old_gap, old_cap, len, NULL); array = ledit_reallocarray(array, new_cap, elem_size); move_gap(array, elem_size, index, len, new_cap, len, NULL); } diff --git a/view.c b/view.c @@ -198,6 +198,8 @@ resize_and_move_line_gap(ledit_view *view, size_t min_size, size_t index) { a part, which may cause these notification functions to be called) */ void view_notify_insert_text(ledit_view *view, size_t line, size_t index, size_t len) { + int sel_valid = view->sel_valid; + view_wipe_selection(view); ledit_view_line *vl = view_get_line(view, line); vl->text_dirty = 1; if (line == view->cur_line && index < view->cur_index) { @@ -206,14 +208,14 @@ view_notify_insert_text(ledit_view *view, size_t line, size_t index, size_t len) if (vl->cursor_index_valid) view_set_line_cursor_attrs(view, line, view->cur_index); } - /* FIXME: maybe just wipe selection completely, or at least - when in insert mode? */ - if (view->sel_valid) + if (sel_valid) view_set_selection(view, view->cur_line, view->cur_index, view->cur_line, view->cur_index); } void view_notify_delete_text(ledit_view *view, size_t line, size_t index, size_t len) { + int sel_valid = view->sel_valid; + view_wipe_selection(view); ledit_view_line *vl = view_get_line(view, line); vl->text_dirty = 1; if (line == view->cur_line) { @@ -232,12 +234,14 @@ view_notify_delete_text(ledit_view *view, size_t line, size_t index, size_t len) if (vl->cursor_index_valid) view_set_line_cursor_attrs(view, line, view->cur_index); } - if (view->sel_valid) + if (sel_valid) view_set_selection(view, view->cur_line, view->cur_index, view->cur_line, view->cur_index); } void view_notify_append_line(ledit_view *view, size_t line) { + int sel_valid = view->sel_valid; + view_wipe_selection(view); cache_invalidate_from_line( view->cache, line + 1, view, &invalidate_pixmap_line_helper, &invalidate_layout_line_helper @@ -245,12 +249,12 @@ view_notify_append_line(ledit_view *view, size_t line) { resize_and_move_line_gap(view, add_sz(view->lines_num, 1), line + 1); if (line < view->cur_line) view->cur_line++; - if (view->sel_valid) - view_set_selection(view, view->cur_line, view->cur_index, view->cur_line, view->cur_index); view->lines_num++; view->lines_gap++; ledit_view_line *vl = view_get_line(view, line + 1); init_line(view, vl); + if (sel_valid) + view_set_selection(view, view->cur_line, view->cur_index, view->cur_line, view->cur_index); } void @@ -277,8 +281,6 @@ view_notify_delete_lines(ledit_view *view, size_t index1, size_t index2) { if (vl->cursor_index_valid) view_set_line_cursor_attrs(view, view->cur_line, view->cur_index); } - if (sel_valid) - view_set_selection(view, view->cur_line, view->cur_index, view->cur_line, view->cur_index); cache_invalidate_from_line( view->cache, index1, view, &invalidate_pixmap_line_helper, &invalidate_layout_line_helper @@ -295,6 +297,8 @@ view_notify_delete_lines(ledit_view *view, size_t index1, size_t index2) { ledit_view_line *vl = view_get_line(view, 0); vl->y_offset = 0; } + if (sel_valid) + view_set_selection(view, view->cur_line, view->cur_index, view->cur_line, view->cur_index); } void @@ -1760,14 +1764,8 @@ view_wipe_selection(ledit_view *view) { } } view->sel_valid = 0; - /* FIXME: check what makes most sense here - this used to be set to 0, but that - caused "jumping effects" because some functions (cursor movement) use these - values without checking view->sel_valid before (which should actually be - changed because it is an error) */ - view->sel.line1 = view->sel.line2 = view->cur_line; - view->sel.byte1 = view->sel.byte2 = view->cur_index; - if (view->mode == NORMAL) - view_set_line_cursor_attrs(view, view->cur_line, view->cur_index); + view->sel.line1 = view->sel.line2 = 0; + view->sel.byte1 = view->sel.byte2 = 0; } void