Introduction
Introduction Statistics Contact Development Disclaimer Help
tMove undo handling to buffer - 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 3572b3d7dd300642a94067f72f30fc83c8651e39
parent 123a3087ad0bc4f772f0cd0a17caf95304092f87
Author: lumidify <[email protected]>
Date: Thu, 9 Dec 2021 11:01:05 +0100
Move undo handling to buffer
Diffstat:
M buffer.c | 336 +++++++++++++++++++++++++----…
M buffer.h | 197 +++++++++++------------------…
M keys_basic.c | 109 ++++++++++++-----------------…
M keys_command.c | 47 +++++++++++++----------------…
M undo.c | 6 ++++++
M undo.h | 9 +++++++++
M view.c | 361 +++++++++++------------------…
M view.h | 23 ++++++++++++++++-------
8 files changed, 553 insertions(+), 535 deletions(-)
---
diff --git a/buffer.c b/buffer.c
t@@ -73,10 +73,103 @@ static char *strchr_len(char *text, char c, size_t len);
*/
static void init_line(ledit_buffer *buffer, ledit_line *line);
+/*
+ * Insert 'src_len' bytes from 'src_line' starting at byte position 'src_index'
+ * into line 'dst_line' at byte position 'dst_index'.
+ * 'dst_line' must not be the same as 'src_line'.
+ * If 'text_ret' is not NULL, the copied text is additionally copied into 'tex…
+ * This function does not update the views or normalize the lines, so it should
+ * only be used for efficiency purposes when performing multiple operations.
+ */
+static void buffer_insert_text_from_line_base(
+ ledit_buffer *buffer,
+ size_t dst_line, size_t dst_index,
+ size_t src_line, size_t src_index, size_t src_len,
+ txtbuf *text_ret
+);
+
+/*
+ * Insert text 'text' with length 'len' at line 'line_index' and byte position…
+ * The text must not contain newlines.
+ * This function does not update the views or normalize the lines, so it should
+ * only be used for efficiency purposes when performing multiple operations.
+ */
+static void buffer_insert_text_base(
+ ledit_buffer *buffer,
+ size_t line_index, size_t index,
+ char *text, size_t len
+);
+
+/* Insert text 'text' with length 'len' at line 'line_index' and byte position…
+ * The text may contain newlines.
+ * If end_line_ret is not NULL, the line index at the end of the insertion is
+ * written into it.
+ * If end_byte_ret is not NULL, the byte position at the end of the insertion …
+ * written into it.
+ * This function does not update the views or normalize the lines, so it should
+ * only be used for efficiency purposes when performing multiple operations.
+ */
+static void buffer_insert_text_with_newlines_base(
+ ledit_buffer *buffer,
+ size_t line_index, size_t index,
+ char *text, size_t len,
+ size_t *end_line_ret, size_t *end_char_ret
+);
+
+/*
+ * Same as buffer_insert_text_with_newlines_base, but the views are updated af…
+ */
+static void buffer_insert_text_with_newlines(
+ ledit_buffer *buffer,
+ size_t line_index, size_t index,
+ char *text, size_t len,
+ size_t *end_line_ret, size_t *end_char_ret
+);
+
+/*
+ * Append line after line at 'line_index'.
+ * if 'break_text' is not 0, the text on line 'line_index' starting at
+ * byte index 'text_index' is moved to the newly appended line.
+ * The views are notified that a line has been appended, but not told to update
+ * their line heights and offsets.
+ */
+static void buffer_append_line_base(ledit_buffer *buffer, size_t line_index, s…
+
+/*
+ * Delete lines between 'index1' and 'index2' (inclusive).
+ * The views are notified of the deletion but not told to
+ * update their line heights and offsets.
+ */
+static void buffer_delete_line_entries_base(ledit_buffer *buffer, size_t index…
+
+/*
+ * Delete the section of line 'line' starting at byte 'start' with length 'len…
+ * and notify the views.
+ * Note that this does not tell the views to recalculate their line heights an…
+ */
+static void buffer_delete_line_section_base(ledit_buffer *buffer, size_t line,…
+
static void marklist_destroy(ledit_buffer_marklist *marklist);
static ledit_buffer_marklist *marklist_create(void);
static void
+swap_sz(size_t *a, size_t *b) {
+ size_t tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+
+static void
+sort_range(size_t *l1, size_t *b1, size_t *l2, size_t *b2) {
+ if (*l1 == *l2 && *b1 > *b2) {
+ swap_sz(b1, b2);
+ } else if (*l1 > *l2) {
+ swap_sz(l1, l2);
+ swap_sz(b1, b2);
+ }
+}
+
+static void
marklist_destroy(ledit_buffer_marklist *marklist) {
for (size_t i = 0; i < marklist->len; i++) {
free(marklist->marks[i].text);
t@@ -324,22 +417,10 @@ buffer_normalize_line(ledit_line *line) {
/* FIXME: To simplify this a bit, maybe just copy text to txtbuf first and
then insert it in one go instead of having this complex logic */
-void
-buffer_insert_text_from_line(
- ledit_buffer *buffer,
- size_t dst_line, size_t dst_index,
- size_t src_line, size_t src_index, size_t src_len,
- txtbuf *text_ret) {
- buffer_insert_text_from_line_base(
- buffer, dst_line, dst_index, src_line, src_index, src_len, text_ret
- );
- buffer_recalc_line(buffer, dst_line);
-}
-
/* FIXME: check if there can be bugs when a newline is inserted in some way
other than pasting or pressing enter */
-void
+static void
buffer_insert_text_from_line_base(
ledit_buffer *buffer,
size_t dst_line, size_t dst_index,
t@@ -452,13 +533,7 @@ resize_and_move_line_gap(ledit_buffer *buffer, size_t min…
);
}
-void
-buffer_insert_text(ledit_buffer *buffer, size_t line_index, size_t index, char…
- buffer_insert_text_base(buffer, line_index, index, text, len);
- buffer_recalc_line(buffer, line_index);
-}
-
-void
+static void
buffer_insert_text_base(ledit_buffer *buffer, size_t line_index, size_t index,…
ledit_line *line = buffer_get_line(buffer, line_index);
/* \0 is not included in line->len */
t@@ -487,7 +562,7 @@ strchr_len(char *text, char c, size_t len) {
}
/* FIXME: make these functions that call recalc* also be final as described ab…
-void
+static void
buffer_insert_text_with_newlines(
ledit_buffer *buffer,
size_t line_index, size_t index,
t@@ -507,7 +582,7 @@ buffer_insert_text_with_newlines(
}
/* FIXME: also look for \r */
-void
+static void
buffer_insert_text_with_newlines_base(
ledit_buffer *buffer,
size_t line_index, size_t index,
t@@ -546,14 +621,8 @@ init_line(ledit_buffer *buffer, ledit_line *line) {
line->len = 0;
}
-void
-buffer_append_line(ledit_buffer *buffer, size_t line_index, size_t text_index,…
- buffer_append_line_base(buffer, line_index, text_index, break_text);
- buffer_recalc_from_line(buffer, line_index);
-}
-
/* FIXME: error checking (index out of bounds, etc.) */
-void
+static void
buffer_append_line_base(ledit_buffer *buffer, size_t line_index, size_t text_i…
size_t new_len = buffer->lines_num + 1;
if (new_len <= buffer->lines_num)
t@@ -582,15 +651,8 @@ buffer_append_line_base(ledit_buffer *buffer, size_t line…
}
}
-/* FIXME: set offset to 0 when recalculating first line? */
-void
-buffer_delete_line_entries(ledit_buffer *buffer, size_t index1, size_t index2)…
- buffer_delete_line_entries_base(buffer, index1, index2);
- buffer_recalc_from_line(buffer, index1 > 0 ? index1 - 1 : 0);
-}
-
/* IMPORTANT: buffer_recalc_from_line needs to be called sometime after this! …
-void
+static void
buffer_delete_line_entries_base(ledit_buffer *buffer, size_t index1, size_t in…
ledit_line *l;
assert (index2 >= index1);
t@@ -607,16 +669,6 @@ buffer_delete_line_entries_base(ledit_buffer *buffer, siz…
}
}
-void
-buffer_delete_line_entry(ledit_buffer *buffer, size_t index) {
- buffer_delete_line_entries(buffer, index, index);
-}
-
-void
-buffer_delete_line_entry_base(ledit_buffer *buffer, size_t index) {
- buffer_delete_line_entries_base(buffer, index, index);
-}
-
ledit_line *
buffer_get_line(ledit_buffer *buffer, size_t index) {
assert(index < buffer->lines_num);
t@@ -753,7 +805,7 @@ line_byte_to_char(ledit_line *line, size_t byte) {
return c;
}
-void
+static void
buffer_delete_line_section_base(ledit_buffer *buffer, size_t line, size_t star…
ledit_line *l = buffer_get_line(buffer, line);
if (start <= l->gap && start + length >= l->gap) {
t@@ -778,24 +830,178 @@ buffer_delete_line_section_base(ledit_buffer *buffer, s…
}
}
-size_t
-buffer_delete_unicode_char(ledit_buffer *buffer, size_t line_index, size_t byt…
- size_t new_index = buffer_delete_unicode_char_base(buffer, line_index,…
- buffer_recalc_line(buffer, line_index);
- return new_index;
+static void
+delete_range_base(
+ ledit_buffer *buffer,
+ size_t line_index1, size_t byte_index1,
+ size_t line_index2, size_t byte_index2,
+ txtbuf *text_ret) {
+ sort_range(&line_index1, &byte_index1, &line_index2, &byte_index2);
+ if (line_index1 == line_index2) {
+ if (text_ret) {
+ buffer_copy_text_to_txtbuf(
+ buffer, text_ret,
+ line_index1, byte_index1,
+ line_index2, byte_index2
+ );
+ }
+ buffer_delete_line_section_base(
+ buffer, line_index1, byte_index1, byte_index2 - byte_index1
+ );
+ } else {
+ if (text_ret) {
+ buffer_copy_text_to_txtbuf(
+ buffer, text_ret,
+ line_index1, byte_index1,
+ line_index2, byte_index2
+ );
+ }
+ ledit_line *line1 = buffer_get_line(buffer, line_index1);
+ ledit_line *line2 = buffer_get_line(buffer, line_index2);
+ buffer_delete_line_section_base(
+ buffer, line_index1, byte_index1, line1->len - byte_index1
+ );
+ buffer_insert_text_from_line_base(
+ buffer,
+ line_index1, byte_index1,
+ line_index2, byte_index2,
+ line2->len - byte_index2, NULL
+ );
+ buffer_delete_line_entries_base(
+ buffer, line_index1 + 1, line_index2
+ );
+ }
}
-size_t
-buffer_delete_unicode_char_base(ledit_buffer *buffer, size_t line_index, size_…
- ledit_line *l = buffer_get_line(buffer, line_index);
- size_t new_index = byte_index;
- if (dir < 0) {
- size_t i = line_prev_utf8(l, byte_index);
- buffer_delete_line_section_base(buffer, line_index, i, byte_in…
- new_index = i;
- } else {
- size_t i = line_next_utf8(l, byte_index);
- buffer_delete_line_section_base(buffer, line_index, byte_index…
+static void
+undo_insert_helper(void *data, size_t line, size_t byte, char *text, size_t te…
+ ledit_buffer *buffer = (ledit_buffer *)data;
+ buffer_insert_text_with_newlines_base(buffer, line, byte, text, text_l…
+}
+
+static void
+undo_delete_helper(void *data, size_t line1, size_t byte1, size_t line2, size_…
+ ledit_buffer *buffer = (ledit_buffer *)data;
+ delete_range_base(buffer, line1, byte1, line2, byte2, NULL);
+}
+
+void
+buffer_undo(ledit_buffer *buffer, enum ledit_mode mode, size_t *cur_line, size…
+ size_t min_line;
+ ledit_undo(
+ buffer->undo, mode, buffer, &undo_insert_helper,
+ &undo_delete_helper, cur_line, cur_byte, &min_line
+ );
+ /* FIXME: why is this check here? */
+ if (min_line < buffer->lines_num) {
+ buffer_recalc_all_views_from_line(
+ buffer, min_line > 0 ? min_line - 1 : min_line
+ );
}
- return new_index;
+}
+
+void
+buffer_redo(ledit_buffer *buffer, enum ledit_mode mode, size_t *cur_line, size…
+ size_t min_line;
+ ledit_redo(
+ buffer->undo, mode, buffer, &undo_insert_helper,
+ &undo_delete_helper, cur_line, cur_byte, &min_line
+ );
+ if (min_line < buffer->lines_num) {
+ buffer_recalc_all_views_from_line(
+ buffer, min_line > 0 ? min_line - 1 : min_line
+ );
+ }
+}
+
+void
+buffer_delete_with_undo_base(
+ ledit_buffer *buffer, ledit_range cur_range,
+ int start_undo_group, enum ledit_mode mode, /* for undo */
+ size_t line_index1, size_t byte_index1,
+ size_t line_index2, size_t byte_index2,
+ txtbuf *text_ret) {
+ /* FIXME: global txtbuf to avoid allocating each time */
+ txtbuf *buf = text_ret != NULL ? text_ret : txtbuf_new();
+ sort_range(&line_index1, &byte_index1, &line_index2, &byte_index2);
+ delete_range_base(
+ buffer, line_index1, byte_index1, line_index2, byte_index2, buf
+ );
+ ledit_range del_range = {
+ .line1 = line_index1, .byte1 = byte_index1,
+ .line2 = line_index2, .byte2 = byte_index2
+ };
+ undo_push_delete(
+ buffer->undo, buf, del_range, cur_range, start_undo_group, mode
+ );
+ if (text_ret == NULL)
+ txtbuf_destroy(buf);
+}
+
+void
+buffer_delete_with_undo(
+ ledit_buffer *buffer, ledit_range cur_range,
+ int start_undo_group, enum ledit_mode mode, /* for undo */
+ size_t line_index1, size_t byte_index1,
+ size_t line_index2, size_t byte_index2,
+ txtbuf *text_ret) {
+ buffer_delete_with_undo_base(
+ buffer, cur_range,
+ start_undo_group, mode,
+ line_index1, byte_index1,
+ line_index2, byte_index2,
+ text_ret
+ );
+ size_t min = line_index1 < line_index2 ? line_index1 : line_index2;
+ buffer_recalc_all_views_from_line(buffer, min);
+}
+
+void
+buffer_insert_with_undo_base(
+ ledit_buffer *buffer,
+ ledit_range cur_range, int set_range_end,
+ int start_undo_group, enum ledit_mode mode,
+ size_t line, size_t byte,
+ char *text, size_t len,
+ size_t *line_ret, size_t *byte_ret) {
+ txtbuf ins_buf = {.text = text, .len = len, .cap = len};
+ ledit_range ins_range;
+ ins_range.line1 = line;
+ ins_range.byte1 = byte;
+ size_t new_line, new_byte;
+ buffer_insert_text_with_newlines_base(
+ buffer, line, byte, text, len,
+ &new_line, &new_byte
+ );
+ if (set_range_end) {
+ cur_range.line2 = new_line;
+ cur_range.byte2 = new_byte;
+ }
+ ins_range.line2 = new_line;
+ ins_range.byte2 = new_byte;
+ undo_push_insert(
+ buffer->undo, &ins_buf, ins_range, cur_range, start_undo_group, mo…
+ );
+ if (line_ret != NULL)
+ *line_ret = new_line;
+ if (byte_ret != NULL)
+ *byte_ret = new_byte;
+}
+
+void
+buffer_insert_with_undo(
+ ledit_buffer *buffer,
+ ledit_range cur_range, int set_range_end,
+ int start_undo_group, enum ledit_mode mode,
+ size_t line, size_t byte,
+ char *text, size_t len,
+ size_t *line_ret, size_t *byte_ret) {
+ buffer_insert_with_undo_base(
+ buffer,
+ cur_range, set_range_end,
+ start_undo_group, mode,
+ line, byte, text, len,
+ line_ret, byte_ret
+ );
+ buffer_recalc_all_views_from_line(buffer, line);
}
diff --git a/buffer.h b/buffer.h
t@@ -5,7 +5,6 @@ typedef struct ledit_buffer ledit_buffer;
#include "view.h"
-/* FIXME: size_t for len, etc. */
typedef struct {
ledit_buffer *parent_buffer;
char *text; /* text, stored as gap buffer */
t@@ -29,7 +28,7 @@ typedef struct {
struct ledit_buffer {
ledit_common *common; /* common stuff, e.g. display, etc. */
char *filename; /* last opened filename */
- undo_stack *undo; /* undo manager */
+ undo_stack *undo; /* undo manager */
ledit_buffer_marklist *marklist; /* list of mark positions set */
ledit_line *lines; /* array of lines */
ledit_view **views; /* array of registered views */
t@@ -115,118 +114,6 @@ void buffer_destroy(ledit_buffer *buffer);
void buffer_normalize_line(ledit_line *line);
/*
- * Insert 'src_len' bytes from 'src_line' starting at byte position 'src_index'
- * into line 'dst_line' at byte position 'dst_index'.
- * 'dst_line' must not be the same as 'src_line'.
- * If 'text_ret' is not NULL, the copied text is additionally copied into 'tex…
- * This function does not update the views or normalize the lines, so it should
- * only be used for efficiency purposes when performing multiple operations.
- */
-void buffer_insert_text_from_line_base(
- ledit_buffer *buffer,
- size_t dst_line, size_t dst_index,
- size_t src_line, size_t src_index, size_t src_len,
- txtbuf *text_ret
-);
-
-/*
- * Same as buffer_insert_text_from_line_base, but the views are updated afterw…
- */
-void buffer_insert_text_from_line(
- ledit_buffer *buffer,
- size_t dst_line, size_t dst_index,
- size_t src_line, size_t src_index, size_t src_len,
- txtbuf *text_ret
-);
-
-/*
- * Insert text 'text' with length 'len' at line 'line_index' and byte position…
- * The text must not contain newlines.
- * This function does not update the views or normalize the lines, so it should
- * only be used for efficiency purposes when performing multiple operations.
- */
-void buffer_insert_text_base(
- ledit_buffer *buffer,
- size_t line_index, size_t index,
- char *text, size_t len
-);
-
-/*
- * Same as buffer_insert_text_base, but the views are updated afterwards.
- */
-void buffer_insert_text(
- ledit_buffer *buffer,
- size_t line_index, size_t index,
- char *text, size_t len
-);
-
-/* Insert text 'text' with length 'len' at line 'line_index' and byte position…
- * The text may contain newlines.
- * If end_line_ret is not NULL, the line index at the end of the insertion is
- * written into it.
- * If end_byte_ret is not NULL, the byte position at the end of the insertion …
- * written into it.
- * This function does not update the views or normalize the lines, so it should
- * only be used for efficiency purposes when performing multiple operations.
- */
-void buffer_insert_text_with_newlines_base(
- ledit_buffer *buffer,
- size_t line_index, size_t index,
- char *text, size_t len,
- size_t *end_line_ret, size_t *end_char_ret
-);
-
-/*
- * Same as buffer_insert_text_with_newlines_base, but the views are updated af…
- */
-void buffer_insert_text_with_newlines(
- ledit_buffer *buffer,
- size_t line_index, size_t index,
- char *text, size_t len,
- size_t *end_line_ret, size_t *end_char_ret
-);
-
-/*
- * Append line after line at 'line_index'.
- * if 'break_text' is not 0, the text on line 'line_index' starting at
- * byte index 'text_index' is moved to the newly appended line.
- * The views are notified that a line has been appended, but not told to update
- * their line heights and offsets.
- */
-void buffer_append_line_base(ledit_buffer *buffer, size_t line_index, size_t t…
-
-/*
- * Same as buffer_append_line_base, but the views are told to update
- * their line heights and offsets afterwards.
- */
-void buffer_append_line(ledit_buffer *buffer, size_t line_index, size_t text_i…
-
-/*
- * Delete lines between 'index1' and 'index2' (inclusive).
- * The views are notified of the deletion but not told to
- * update their line heights and offsets.
- */
-void buffer_delete_line_entries_base(ledit_buffer *buffer, size_t index1, size…
-
-/*
- * Same as buffer_delete_line_entries_base, but the views are told to
- * update their line heights and offsets.
- */
-void buffer_delete_line_entries(ledit_buffer *buffer, size_t index1, size_t in…
-
-/*
- * Convenience function to call buffer_delete_line_entries_base
- * with two times the same line index.
- */
-void buffer_delete_line_entry_base(ledit_buffer *buffer, size_t index);
-
-/*
- * Convenience function to call buffer_delete_line_entries
- * with two times the same line index.
- */
-void buffer_delete_line_entry(ledit_buffer *buffer, size_t index);
-
-/*
* Get the line at logical index 'index'.
* The returned line is only valid until the next
* action that appends or deletes line entries.
t@@ -292,33 +179,87 @@ size_t line_prev_utf8(ledit_line *line, size_t index);
/*
* Get the unicode character index of a byte position.
+ * Note that the time complexity of this is linear.
*/
size_t line_byte_to_char(ledit_line *line, size_t byte);
/*
- * Delete the section of line 'line' starting at byte 'start' with length 'len…
- * and notify the views.
- * Note that this does not tell the views to recalculate their line heights an…
+ * Insert a mark with key 'mark' at line 'line' and byte 'byte'.
*/
-void buffer_delete_line_section_base(ledit_buffer *buffer, size_t line, size_t…
+void buffer_insert_mark(ledit_buffer *buffer, char *mark, size_t len, size_t l…
/*
- * Delete the unicode char at 'line_index' and 'byte_index' if 'dir' is >= 0,
- * or the previous char if 'dir' is < 0.
- * Returns the byte index where the deleted text was located.
- * This function only notifies the views of the deletion, but does not tell
- * them to recalculate their line heights and offsets.
+ * Perform one undo step.
+ * 'mode' should be the current mode of the calling view.
+ * 'cur_line' and 'cur_byte' are filled with the new line and cursor
+ * position after the undo.
*/
-size_t buffer_delete_unicode_char_base(ledit_buffer *buffer, size_t line_index…
+void buffer_undo(ledit_buffer *buffer, enum ledit_mode mode, size_t *cur_line,…
/*
- * Same as buffer_delete_unicode_char_base, but the views are updated.
+ * Same as 'buffer_undo', but for redo.
*/
-size_t buffer_delete_unicode_char(ledit_buffer *buffer, size_t line_index, siz…
+void buffer_redo(ledit_buffer *buffer, enum ledit_mode mode, size_t *cur_line,…
/*
- * Insert a mark with key 'mark' at line 'line' and byte 'byte'.
+ * Delete the given range (which does not need to be sorted yet) and
+ * add the operation to the undo stack.
+ * 'cur_range' is the cursor range to be added to the undo stack.
+ * 'start_undo_group' and 'mode' are also used for the undo stack.
+ * If 'text_ret' is not NULL, the deleted text is written to it.
+ * This function does not tell the views to update their line heights
+ * and offsets.
*/
-void buffer_insert_mark(ledit_buffer *buffer, char *mark, size_t len, size_t l…
+void buffer_delete_with_undo_base(
+ ledit_buffer *buffer, ledit_range cur_range,
+ int start_undo_group, enum ledit_mode mode, /* for undo */
+ size_t line_index1, size_t byte_index1,
+ size_t line_index2, size_t byte_index2,
+ txtbuf *text_ret
+);
+
+/*
+ * Same as 'buffer_delete_with_undo_base', but the views are told to
+ * update their line heights and offsets afterwards.
+ */
+void buffer_delete_with_undo(
+ ledit_buffer *buffer, ledit_range cur_range,
+ int start_undo_group, enum ledit_mode mode, /* for undo */
+ size_t line_index1, size_t byte_index1,
+ size_t line_index2, size_t byte_index2,
+ txtbuf *text_ret
+);
+
+/*
+ * Insert the given 'text' with length 'len' at line 'line' and
+ * byte index 'byte and add the operation to the undo stack.
+ * 'cur_range', 'start_undo_group', and 'mode' are used for the
+ * undo stack. If 'set_range_end' is set, the end position of
+ * 'cur_range' is set to the end position of the insertion before
+ * adding the operation to the undo stack.
+ * If 'line_ret' and 'byte_ret' are not NULL, they are filled with
+ * the end position of the insertion.
+ */
+void buffer_insert_with_undo_base(
+ ledit_buffer *buffer,
+ ledit_range cur_range, int set_range_end,
+ int start_undo_group, enum ledit_mode mode,
+ size_t line, size_t byte,
+ char *text, size_t len,
+ size_t *line_ret, size_t *byte_ret
+);
+
+/*
+ * Same as 'buffer_insert_with_undo_base', but the views are told to
+ * update their line heights and offsets afterwards.
+ */
+void buffer_insert_with_undo(
+ ledit_buffer *buffer,
+ ledit_range cur_range, int set_range_end,
+ int start_undo_group, enum ledit_mode mode,
+ size_t line, size_t byte,
+ char *text, size_t len,
+ size_t *line_ret, size_t *byte_ret
+);
#endif
diff --git a/keys_basic.c b/keys_basic.c
t@@ -37,7 +37,7 @@
#include "keys_command.h"
#include "keys_basic_config.h"
-/* note: this is supposed to be global for all buffers */
+/* note: this is supposed to be global for all views/buffers */
int paste_buffer_line_based = 0;
static txtbuf *paste_buffer = NULL;
static int last_lines_scrolled = -1;
t@@ -77,7 +77,6 @@ static struct {
} key_stack = {0, 0, NULL};
static struct action (*grab_char_cb)(ledit_view *view, char *text, size_t len)…
-static int hard_line_based = 1;
void
basic_key_cleanup(void) {
t@@ -334,7 +333,7 @@ static void
get_new_line_softline(
ledit_view *view, size_t cur_line, size_t cur_index, int movement,
size_t *new_line_ret, int *new_softline_ret) {
- if (hard_line_based) {
+ if (view->buffer->hard_line_based) {
if (movement < 0 && (size_t)-movement > cur_line)
*new_line_ret = 0;
else
t@@ -403,31 +402,21 @@ delete_range(
(void)selected; /* FIXME */
if (copy_to_buffer && !paste_buffer)
paste_buffer = txtbuf_new();
- txtbuf *buf = copy_to_buffer ? paste_buffer : txtbuf_new();
- ledit_range cur_range, del_range;
- cur_range.line1 = view->cur_line;
- cur_range.byte1 = view->cur_index;
+ txtbuf *buf = copy_to_buffer ? paste_buffer : NULL;
enum delete_mode delmode = DELETE_CHAR;
if (line_based) {
- if (hard_line_based)
+ if (view->buffer->hard_line_based)
delmode = DELETE_HARDLINE;
else
delmode = DELETE_SOFTLINE;
}
view_delete_range(
- view, delmode,
+ view, delmode, 1,
line_index1, byte_index1,
line_index2, byte_index2,
&view->cur_line, &view->cur_index,
- &del_range, buf
+ buf
);
- cur_range.line2 = view->cur_line;
- cur_range.byte2 = view->cur_index;
- undo_push_delete(
- view->buffer->undo, buf, del_range, cur_range, 1, view->mode
- );
- if (!copy_to_buffer)
- txtbuf_destroy(buf);
}
/* FIXME: better interface for this; documentation */
t@@ -439,8 +428,7 @@ insert_text(
size_t cur_line1, size_t cur_index1,
size_t cur_line2, size_t cur_index2,
int set_range_start, int set_range_end, int start_group) {
- txtbuf ins_buf = {.text = text, .len = len, .cap = len};
- ledit_range cur_range, del_range;
+ ledit_range cur_range;
if (set_range_start) {
cur_range.line1 = cur_line1;
cur_range.byte1 = cur_index1;
t@@ -448,27 +436,24 @@ insert_text(
cur_range.line1 = view->cur_line;
cur_range.byte1 = view->cur_index;
}
- del_range.line1 = line;
- del_range.byte1 = index;
- size_t cur_line, cur_index;
- buffer_insert_text_with_newlines(
- view->buffer, line, index, text, len,
- &cur_line, &cur_index
- );
/* this is mainly for pasting, where the new line and index
should not be at the end of the pasted text */
if (set_range_end) {
- cur_range.line2 = view->cur_line = cur_line2;
- cur_range.byte2 = view->cur_index = cur_index2;
- } else {
- cur_range.line2 = view->cur_line = cur_line;
- cur_range.byte2 = view->cur_index = cur_index;
+ cur_range.line2 = cur_line2;
+ cur_range.byte2 = cur_index2;
}
- del_range.line2 = cur_line;
- del_range.byte2 = cur_index;
- undo_push_insert(
- view->buffer->undo, &ins_buf, del_range, cur_range, start_group, v…
+ /* FIXME: why did I ever decide to make set_range_end
+ mean exactly the opposite for the two functions? */
+ buffer_insert_with_undo(
+ view->buffer, cur_range, !set_range_end,
+ start_group, view->mode,
+ line, index, text, len,
+ &view->cur_line, &view->cur_index
);
+ if (set_range_end) {
+ view->cur_line = cur_line2;
+ view->cur_index = cur_index2;
+ }
}
static int
t@@ -562,7 +547,7 @@ append_line_above(ledit_view *view, char *text, size_t len…
/* do this here already so the mode group is the same for the newline …
enter_insert(view, text, len);
view_get_pos_softline_bounds(view, view->cur_line, view->cur_index, &s…
- if (hard_line_based || start == 0) {
+ if (view->buffer->hard_line_based || start == 0) {
insert_text(view, view->cur_line, 0, "\n", 1, 0, 0, view->cur_…
} else {
/* FIXME: this interface really is horrible */
t@@ -577,7 +562,7 @@ append_line_below(ledit_view *view, char *text, size_t len…
enter_insert(view, text, len);
view_get_pos_softline_bounds(view, view->cur_line, view->cur_index, &s…
ledit_line *ll = buffer_get_line(view->buffer, view->cur_line);
- if (hard_line_based || end == ll->len) {
+ if (view->buffer->hard_line_based || end == ll->len) {
insert_text(view, view->cur_line, ll->len, "\n", 1, 0, 0, view…
} else {
insert_text(view, view->cur_line, end, "\n\n", 2, 0, 0, view->…
t@@ -604,7 +589,7 @@ append_after_eol(ledit_view *view, char *text, size_t len)…
/* make cursor jump back to original position on undo */
push_undo_empty_insert(view, view->cur_line, view->cur_index, 1);
ledit_line *ll = buffer_get_line(view->buffer, view->cur_line);
- if (hard_line_based)
+ if (view->buffer->hard_line_based)
view->cur_index = ll->len;
else
view->cur_index = end;
t@@ -852,7 +837,7 @@ delete_to_eol(ledit_view *view, char *text, size_t len) {
return err_invalid_key(view);
size_t start, end;
ledit_line *ll = buffer_get_line(view->buffer, view->cur_line);
- if (hard_line_based) {
+ if (view->buffer->hard_line_based) {
end = ll->len;
} else {
view_get_pos_softline_bounds(view, view->cur_line, view->cur_i…
t@@ -879,7 +864,7 @@ change_to_eol(ledit_view *view, char *text, size_t len) {
view_set_mode(view, INSERT);
size_t start, end;
ledit_line *ll = buffer_get_line(view->buffer, view->cur_line);
- if (hard_line_based) {
+ if (view->buffer->hard_line_based) {
end = ll->len;
} else {
view_get_pos_softline_bounds(view, view->cur_line, view->cur_i…
t@@ -942,11 +927,11 @@ change_cb(ledit_view *view, size_t line, size_t char_pos…
/* this hackery is needed to avoid deleting the entire last line and
instead leave an empty line - this should be made nicer (FIXME) */
size_t pos1 = view->cur_index, pos2 = char_pos;
- if (line_based && !hard_line_based) {
+ if (line_based && !view->buffer->hard_line_based) {
size_t pos1, pos2, tmp;
view_get_pos_softline_bounds(view, view->cur_line, view->cur_i…
view_get_pos_softline_bounds(view, line, char_pos, &tmp, &pos2…
- } else if (line_based && hard_line_based) {
+ } else if (line_based && view->buffer->hard_line_based) {
pos1 = 0;
ledit_line *ll = buffer_get_line(view->buffer, line);
pos2 = ll->len;
t@@ -1046,7 +1031,7 @@ yank_cb(ledit_view *view, size_t line, size_t char_pos, …
swap_sz(&l1, &l2);
swap_sz(&b1, &b2);
}
- if (line_based && !hard_line_based) {
+ if (line_based && !view->buffer->hard_line_based) {
size_t start1, end2, tmp;
view_get_pos_softline_bounds(view, l1, b1, &start1, &tmp);
view_get_pos_softline_bounds(view, l2, b2, &tmp, &end2);
t@@ -1058,7 +1043,7 @@ yank_cb(ledit_view *view, size_t line, size_t char_pos, …
buffer_copy_text_to_txtbuf(
view->buffer, paste_buffer, l1, start1, l2, end2
);
- } else if (line_based && hard_line_based) {
+ } else if (line_based && view->buffer->hard_line_based) {
ledit_line *ll = buffer_get_line(view->buffer, l2);
size_t end = ll->len;
if (l2 < view->lines_num - 1) {
t@@ -1119,6 +1104,7 @@ delete(ledit_view *view, char *text, size_t len) {
/* FIXME: should this get number of lines to remove or actual end line? */
static void
delete_cb(ledit_view *view, size_t line, size_t char_pos, enum key_type type) {
+ view_wipe_line_cursor_attrs(view, view->cur_line);
int line_based = type == KEY_MOTION_LINE ? 1 : 0;
delete_range(
view, line_based, 0,
t@@ -1147,12 +1133,14 @@ paste_normal(ledit_view *view, char *text, size_t len)…
view_wipe_line_cursor_attrs(view, view->cur_line);
ledit_line *ll = buffer_get_line(view->buffer, view->cur_line);
size_t brk = 0;
- if (hard_line_based) {
+ if (view->buffer->hard_line_based) {
brk = ll->len;
} else {
size_t tmp;
view_get_pos_softline_bounds(view, view->cur_line, vie…
}
+ /* FIXME: this is a bit inefficient because insert_text does n…
+ use the *_base functions, but maybe this way is a bit safer…
insert_text(
view, view->cur_line, brk,
"\n", 1, 0, 0, view->cur_line, view->cur_index, 0, 1, 1
t@@ -1203,7 +1191,7 @@ paste_normal_backwards(ledit_view *view, char *text, siz…
view_wipe_line_cursor_attrs(view, view->cur_line);
ledit_line *ll = buffer_get_line(view->buffer, view->cur_line);
size_t brk = 0;
- if (!hard_line_based) {
+ if (!view->buffer->hard_line_based) {
size_t tmp;
view_get_pos_softline_bounds(view, view->cur_line, vie…
}
t@@ -1414,7 +1402,7 @@ move_to_eol(ledit_view *view, char *text, size_t len) {
);
ledit_line *ll = buffer_get_line(view->buffer, new_line);
size_t end_index = ll->len;
- if (!hard_line_based) {
+ if (!view->buffer->hard_line_based) {
size_t tmp;
view_get_softline_bounds(view, new_line, new_softline, &tmp, &…
}
t@@ -1683,11 +1671,6 @@ join_lines(ledit_view *view, char *text, size_t len) {
int start_group = 1;
ledit_line *ll1;
size_t cur_line = view->cur_line;
- /* FIXME: have a general tmp buf for everyone to use */
- txtbuf *buf = txtbuf_new();
- size_t oldlen;
- ledit_range cur_range, del_range;
- cur_range.line1 = cur_range.line2 = cur_line;
for (int i = 0; i < num; i++) {
if (cur_line == view->lines_num - 1)
break;
t@@ -1695,26 +1678,18 @@ join_lines(ledit_view *view, char *text, size_t len) {
I'll just leave it in case I change the way lines
are stored later */
ll1 = buffer_get_line(view->buffer, cur_line);
- oldlen = ll1->len;
/* FIXME: truncate whitespace to one space */
- view_delete_range(
- view, DELETE_CHAR,
+ view_delete_range_base(
+ view, DELETE_CHAR, start_group,
cur_line, ll1->len, cur_line + 1, 0,
- NULL, NULL, &del_range, buf
- );
- cur_range.byte1 = view->cur_index;
- cur_range.byte2 = view->cur_index =
- view_get_legal_normal_pos(view, view->cur_line, oldlen);
- undo_push_delete(
- view->buffer->undo, buf, del_range, cur_range,
- start_group, view->mode
+ &view->cur_line, &view->cur_index, NULL
);
start_group = 0;
}
+ buffer_recalc_all_views_from_line(view->buffer, cur_line);
view_set_line_cursor_attrs(
view, view->cur_line, view->cur_index
);
- txtbuf_destroy(buf);
finalize_repetition_stack();
return (struct action){ACTION_NONE, NULL};
}
t@@ -1725,7 +1700,7 @@ insert_at_beginning(ledit_view *view, char *text, size_t…
return err_invalid_key(view);
enter_insert(view, text, len);
size_t new_index = 0;
- if (!hard_line_based) {
+ if (!view->buffer->hard_line_based) {
size_t tmp;
view_get_pos_softline_bounds(view, view->cur_line, view->cur_i…
}
t@@ -1744,7 +1719,7 @@ cursor_to_first_non_ws(ledit_view *view, char *text, siz…
if (num != 0)
return err_invalid_key(view);
size_t new_index = 0;
- if (hard_line_based) {
+ if (view->buffer->hard_line_based) {
new_index = view_line_next_non_whitespace(view, view->cur_line…
} else {
size_t start, end;
t@@ -1779,7 +1754,7 @@ cursor_to_beginning(ledit_view *view, char *text, size_t…
return err_invalid_key(view);
/* FIXME: should anything be done with num? */
size_t start_index = 0;
- if (!hard_line_based) {
+ if (!view->buffer->hard_line_based) {
size_t tmp;
view_get_pos_softline_bounds(view, view->cur_line, view->cur_i…
}
diff --git a/keys_command.c b/keys_command.c
t@@ -162,44 +162,34 @@ handle_substitute(ledit_view *view, char *cmd, size_t l1…
size_t rlen = strlen(last_replacement);
txtbuf *buf = txtbuf_new(); /* FIXME: don't allocate new every…
view_wipe_line_cursor_attrs(view, view->cur_line);
+ size_t min_line = SIZE_MAX;
for (size_t i = l1 - 1; i < l2; i++) {
ledit_line *ll = buffer_get_line(view->buffer, i);
buffer_normalize_line(ll);
char *pos = strstr(ll->text, last_search);
+ if (pos != NULL && i < min_line)
+ min_line = i;
while (pos != NULL) {
size_t index = (size_t)(pos - ll->text);
- ledit_range cur_range, del_range;
+ ledit_range cur_range;
cur_range.line1 = view->cur_line;
cur_range.byte1 = view->cur_line;
- view_delete_range(
- view, DELETE_CHAR,
- i, index,
- i, index + slen,
- &view->cur_line, &view->cur_index,
- &del_range, buf
- );
- cur_range.line2 = view->cur_line;
- cur_range.byte2 = view->cur_index;
- undo_push_delete(
- view->buffer->undo, buf, del_range, cur_ra…
+ cur_range.line2 = i;
+ cur_range.byte2 = index;
+ buffer_delete_with_undo_base(
+ view->buffer, cur_range,
+ start_undo_group, view->mode,
+ i, index, i, index + slen, NULL
);
+ view->cur_line = i;
+ view->cur_index = index;
start_undo_group = 0;
- txtbuf ins_buf = {.text = last_replacement, .l…
- cur_range.line1 = view->cur_line;
- cur_range.byte1 = view->cur_index;
- del_range.line1 = i;
- del_range.byte1 = index;
- size_t cur_line, cur_index;
- buffer_insert_text_with_newlines(
- view->buffer, i, index, last_replacement, …
- &cur_line, &cur_index
- );
- cur_range.line2 = view->cur_line;
- cur_range.byte2 = view->cur_index;
- del_range.line2 = cur_line;
- del_range.byte2 = cur_index;
- undo_push_insert(
- view->buffer->undo, &ins_buf, del_range, c…
+ cur_range.line1 = i;
+ cur_range.byte1 = index;
+ buffer_insert_with_undo_base(
+ view->buffer, cur_range, 0, 0, view->mode,
+ i, index, last_replacement, rlen,
+ NULL, NULL
);
num++;
if (!global) break;
t@@ -207,6 +197,7 @@ handle_substitute(ledit_view *view, char *cmd, size_t l1, …
pos = strstr(ll->text + index + rlen, last_sea…
}
}
+ buffer_recalc_all_views_from_line(view->buffer, min_line);
/* FIXME: show number replaced */
/* this doesn't need to be added to the undo stack since it's …
view->cur_index = view_get_legal_normal_pos(view, view->cur_li…
diff --git a/undo.c b/undo.c
t@@ -267,3 +267,9 @@ ledit_redo(undo_stack *undo, enum ledit_mode mode, void *c…
*min_line_ret = min_line;
return UNDO_NORMAL;
}
+
+void
+undo_change_last_cur_range(undo_stack *undo, ledit_range cur_range) {
+ undo_elem *e = peek_undo_elem(undo);
+ e->cursor_range = cur_range;
+}
diff --git a/undo.h b/undo.h
t@@ -106,3 +106,12 @@ undo_status ledit_redo(
void *callback_data, undo_insert_callback insert_cb, undo_delete_callback …
size_t *cur_line_ret, size_t *cur_index_ret, size_t *min_line_ret
);
+
+/*
+ * Change the cursor range stored for the last operation.
+ * This is sort of a hack used by view_delete_range and some other
+ * functions to set the cursor range later if it isn't known yet before
+ * inserting/deleting text.
+ * Fails silently if the stack is empty.
+ */
+void undo_change_last_cur_range(undo_stack *undo, ledit_range cur_range);
diff --git a/view.c b/view.c
t@@ -188,14 +188,23 @@ resize_and_move_line_gap(ledit_view *view, size_t min_si…
);
}
+/* Checking vl->cursor_index_valid in these notify functions is needed
+ to avoid re-setting the cursor index for lines that were wiped but
+ where the line/index of the view hasn't been updated yet (e.g. when
+ the current line is wiped, then view_delete_range is called to delete
+ 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 le…
ledit_view_line *vl = view_get_line(view, line);
vl->text_dirty = 1;
if (line == view->cur_line && index < view->cur_index) {
view->cur_index += len;
- view_set_line_cursor_attrs(view, line, view->cur_index);
+ ledit_view_line *vl = view_get_line(view, line);
+ 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)
view_set_selection(view, view->cur_line, view->cur_index, view…
}
t@@ -216,7 +225,9 @@ view_notify_delete_text(ledit_view *view, size_t line, siz…
view, view->cur_line, view->cur_index
);
}
- view_set_line_cursor_attrs(view, line, view->cur_index);
+ ledit_view_line *vl = view_get_line(view, line);
+ if (vl->cursor_index_valid)
+ view_set_line_cursor_attrs(view, line, view->cur_index…
}
if (view->sel_valid)
view_set_selection(view, view->cur_line, view->cur_index, view…
t@@ -255,6 +266,9 @@ view_notify_delete_lines(ledit_view *view, size_t index1, …
view->cur_line = 0;
view->cur_index = 0;
}
+ ledit_view_line *vl = view_get_line(view, view->cur_line);
+ if (vl->cursor_index_valid)
+ view_set_line_cursor_attrs(view, view->cur_line, view-…
}
if (view->sel_valid)
view_set_selection(view, view->cur_line, view->cur_index, view…
t@@ -1132,22 +1146,23 @@ view_get_legal_normal_pos(ledit_view *view, size_t lin…
void
view_delete_range(
- ledit_view *view, enum delete_mode delmode,
+ ledit_view *view,
+ enum delete_mode delmode, int start_undo_group,
size_t line_index1, size_t byte_index1,
size_t line_index2, size_t byte_index2,
size_t *new_line_ret, size_t *new_byte_ret,
- ledit_range *final_range_ret, txtbuf *text_ret) {
+ txtbuf *text_ret) {
view_delete_range_base(
- view, delmode,
+ view,
+ delmode, start_undo_group,
line_index1, byte_index1,
line_index2, byte_index2,
new_line_ret, new_byte_ret,
- final_range_ret, text_ret
+ text_ret
);
/* need to start recalculating one line before in case first
line was deleted and offset is now wrong */
size_t min = line_index1 < line_index2 ? line_index1 : line_index2;
- /* FIXME: a bit ugly to do this here */
buffer_recalc_all_views_from_line(
view->buffer, min > 0 ? min - 1 : min
);
t@@ -1162,29 +1177,31 @@ view_delete_range(
given, but I couldn't reproduce this bug */
void
view_delete_range_base(
- ledit_view *view, enum delete_mode delmode,
+ ledit_view *view,
+ enum delete_mode delmode, int start_undo_group,
size_t line_index1, size_t byte_index1,
size_t line_index2, size_t byte_index2,
size_t *new_line_ret, size_t *new_byte_ret,
- ledit_range *final_range_ret, txtbuf *text_ret) {
+ txtbuf *text_ret) {
/* FIXME: Oh boy, this is nasty */
/* range line x, range byte x */
size_t rgl1 = 0, rgb1 = 0, rgl2 = 0, rgb2 = 0;
+ /* line_index1 and byte_index1 are used as cursor start position
+ -> FIXME: why not just use view->cur_line, view->cur_index here? */
+ size_t cur_line = line_index1;
+ size_t cur_byte = byte_index1;
+ view_sort_selection(&line_index1, &byte_index1, &line_index2, &byte_in…
size_t new_line = 0, new_byte = 0;
assert(line_index1 < view->lines_num);
assert(line_index2 < view->lines_num);
+ ledit_range cur_range = {0, 0, 0, 0};
/* FIXME: could this be simplified by just calculating the range and t…
the non-line-based version? */
if (delmode == DELETE_HARDLINE) {
int x, sl_useless;
size_t l1 = line_index1, l2 = line_index2;
- if (line_index1 > line_index2) {
- l1 = line_index2;
- l2 = line_index1;
- }
- size_t dell1 = l1, dell2 = l2;
- ledit_line *ll = buffer_get_line(view->buffer, line_index1);
- view_pos_to_x_softline(view, line_index1, byte_index1, &x, &sl…
+ ledit_line *ll;
+ view_pos_to_x_softline(view, cur_line, cur_byte, &x, &sl_usele…
if (l1 > 0 && l2 < view->lines_num - 1) {
rgl1 = l1;
rgb1 = 0;
t@@ -1209,13 +1226,6 @@ view_delete_range_base(
ll = buffer_get_line(view->buffer, rgl2);
rgb2 = ll->len;
}
- if (text_ret) {
- buffer_copy_text_to_txtbuf(
- view->buffer, text_ret,
- rgl1, rgb1, rgl2, rgb2
- );
- }
- /* default is dell1 = l1, dell2 = l2 */
if (l2 < view->lines_num - 1) {
new_line = l1;
new_byte = view_x_softline_to_pos(
t@@ -1227,30 +1237,24 @@ view_delete_range_base(
view, l1 - 1, x, 0
);
} else {
- dell1 = l1 + 1;
- dell2 = l2;
- new_line = l1;
+ new_line = 0;
new_byte = 0;
- /* happens when all lines are deleted, so one line has…
- ll = buffer_get_line(view->buffer, l1);
- buffer_delete_line_section_base(
- view->buffer, l1, 0, ll->len
- );
- }
- if (dell1 <= dell2) {
- buffer_delete_line_entries_base(view->buffer, dell1, d…
}
+ buffer_delete_with_undo_base(
+ view->buffer, cur_range,
+ start_undo_group, view->mode,
+ rgl1, rgb1, rgl2, rgb2, text_ret
+ );
} else if (delmode == DELETE_SOFTLINE) {
- int x, softline1, softline2;
- ledit_line *line1 = buffer_get_line(view->buffer, line_index1);
- ledit_view_line *vline1 = view_get_line(view, line_index1);
- view_pos_to_x_softline(view, line_index1, byte_index1, &x, &so…
+ int x, sl_useless;
+ view_pos_to_x_softline(view, cur_line, cur_byte, &x, &sl_usele…
if (line_index1 == line_index2) {
- int x_useless;
+ int x_useless, l1, l2;
+ ledit_line *line1 = buffer_get_line(view->buffer, line…
+ ledit_view_line *vline1 = view_get_line(view, line_ind…
+ view_pos_to_x_softline(view, line_index1, byte_index1,…
+ view_pos_to_x_softline(view, line_index2, byte_index2,…
PangoLayout *layout = get_pango_layout(view, line_inde…
- pango_layout_index_to_line_x(layout, byte_index2, 0, &…
- int l1 = softline1 < softline2 ? softline1 : softline2;
- int l2 = softline1 < softline2 ? softline2 : softline1;
PangoLayoutLine *pl1 = pango_layout_get_line_readonly(…
PangoLayoutLine *pl2 = pango_layout_get_line_readonly(…
/* don't delete entire line if it is the last one rema…
t@@ -1258,11 +1262,9 @@ view_delete_range_base(
if (line_index1 < view->lines_num - 1) {
/* cursor can be moved to next hard li…
new_line = line_index1;
- size_t tmp_byte;
- tmp_byte = view_x_softline_to_pos(
+ new_byte = view_x_softline_to_pos(
view, line_index1 + 1, x, 0
);
- new_byte = (size_t)tmp_byte;
rgl1 = line_index1;
rgb1 = 0;
rgl2 = line_index1 + 1;
t@@ -1283,50 +1285,41 @@ view_delete_range_base(
rgl2 = line_index1;
rgb2 = line1->len;
}
- if (text_ret) {
- buffer_copy_text_to_txtbuf(
- view->buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- buffer_delete_line_entry_base(view->buffer, li…
+ buffer_delete_with_undo_base(
+ view->buffer, cur_range,
+ start_undo_group, view->mode,
+ rgl1, rgb1, rgl2, rgb2, text_ret
+ );
} else {
assert(pl2->start_index + pl2->length >= pl1->…
rgl1 = rgl2 = line_index1;
rgb1 = (size_t)pl1->start_index;
rgb2 = (size_t)(pl2->start_index + pl2->length…
- if (text_ret) {
- buffer_copy_text_to_txtbuf(
- view->buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- buffer_delete_line_section_base(
- view->buffer, line_index1, rgb1, rgb2 - rg…
+ /* the deletion has to happen before calculati…
+ position because deleting softlines could c…
+ wrapping as well */
+ buffer_delete_with_undo_base(
+ view->buffer, cur_range,
+ start_undo_group, view->mode,
+ rgl1, rgb1, rgl2, rgb2, text_ret
);
- if (l2 == vline1->softlines - 1 && line_index1…
+ set_pango_text_and_highlight(view, line_index1…
+ vline1 = view_get_line(view, line_index1);
+ if (l1 == vline1->softlines && line_index1 < v…
new_line = line_index1 + 1;
- size_t tmp_byte;
- tmp_byte = view_x_softline_to_pos(
+ new_byte = view_x_softline_to_pos(
view, line_index1 + 1, x, 0
);
- new_byte = (size_t)tmp_byte;
- } else if (l2 < vline1->softlines - 1) {
+ } else if (l1 <= vline1->softlines - 1) {
new_line = line_index1;
- size_t tmp_byte;
- tmp_byte = view_x_softline_to_pos(
+ new_byte = view_x_softline_to_pos(
view, line_index1, x, l1
);
- new_byte = (size_t)tmp_byte;
} else if (l1 > 0) {
new_line = line_index1;
- size_t tmp_byte;
- tmp_byte = view_x_softline_to_pos(
+ new_byte = view_x_softline_to_pos(
view, line_index1, x, l1 - 1
);
- new_byte = (size_t)tmp_byte;
} else {
/* the line has been emptied and is th…
new_line = 0;
t@@ -1335,19 +1328,8 @@ view_delete_range_base(
}
} else {
int x_useless, sl1, sl2;
- size_t l1, l2, b1, b2;
- if (line_index1 < line_index2) {
- l1 = line_index1;
- b1 = byte_index1;
- l2 = line_index2;
- b2 = byte_index2;
- } else {
- l1 = line_index2;
- b1 = byte_index2;
- l2 = line_index1;
- b2 = byte_index1;
- }
- ledit_line *ll1 = buffer_get_line(view->buffer, l1);
+ size_t l1 = line_index1, b1 = byte_index1;
+ size_t l2 = line_index2, b2 = byte_index2;
ledit_line *ll2 = buffer_get_line(view->buffer, l2);
ledit_view_line *vl1 = view_get_line(view, l1);
ledit_view_line *vl2 = view_get_line(view, l2);
t@@ -1363,15 +1345,6 @@ view_delete_range_base(
rgl2 = l2;
rgb1 = 0;
rgb2 = ll2->len;
- if (text_ret) {
- buffer_copy_text_to_txtbuf(
- view->buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- buffer_delete_line_section_base(view->…
- buffer_delete_line_entries_base(view->…
new_line = 0;
new_byte = 0;
} else {
t@@ -1396,31 +1369,24 @@ view_delete_range_base(
rgl2 = l2 + 1;
rgb2 = 0;
}
- if (text_ret) {
- buffer_copy_text_to_txtbuf(
- view->buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- buffer_delete_line_entries_base(view->…
}
+ buffer_delete_with_undo_base(
+ view->buffer, cur_range,
+ start_undo_group, view->mode,
+ rgl1, rgb1, rgl2, rgb2, text_ret
+ );
} else if (sl1 == 0) {
rgl1 = l1;
rgb1 = 0;
rgl2 = l2;
rgb2 = (size_t)(pl2->start_index + pl2->length…
- if (text_ret) {
- buffer_copy_text_to_txtbuf(
- view->buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- buffer_delete_line_section_base(view->buffer, …
+ buffer_delete_with_undo_base(
+ view->buffer, cur_range,
+ start_undo_group, view->mode,
+ rgl1, rgb1, rgl2, rgb2, text_ret
+ );
new_line = l1;
- new_byte = view_x_softline_to_pos(view, l2, x,…
- buffer_delete_line_entries_base(view->buffer, …
+ new_byte = view_x_softline_to_pos(view, l1, x,…
} else if (sl2 == vl2->softlines - 1) {
rgl1 = l1;
rgb1 = (size_t)pl1->start_index;
t@@ -1435,38 +1401,27 @@ view_delete_range_base(
view, l2 + 1, x, 0
);
}
- if (text_ret) {
- buffer_copy_text_to_txtbuf(
- view->buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- buffer_delete_line_section_base(view->buffer, …
- buffer_delete_line_entries_base(view->buffer, …
+ buffer_delete_with_undo_base(
+ view->buffer, cur_range,
+ start_undo_group, view->mode,
+ rgl1, rgb1, rgl2, rgb2, text_ret
+ );
} else {
- /* FIXME: this could be made nicer by just usi…
- delete all in one go at the end */
rgl1 = l1;
rgb1 = (size_t)pl1->start_index;
rgl2 = l2;
rgb2 = (size_t)(pl2->start_index + pl2->length…
- if (text_ret) {
- buffer_copy_text_to_txtbuf(
- view->buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- buffer_delete_line_section_base(view->buffer, …
- buffer_insert_text_from_line_base(
- view->buffer,
- l1, rgb1, l2, rgb2,
- ll2->len - rgb2, NULL
+ buffer_delete_with_undo_base(
+ view->buffer, cur_range,
+ start_undo_group, view->mode,
+ rgl1, rgb1, rgl2, rgb2, text_ret
);
- buffer_delete_line_entries_base(view->buffer, …
new_line = l1;
+ /* important so vl1->softlines is updated */
set_pango_text_and_highlight(view, l1);
+ /* important because line pointers may only st…
+ valid until something is deleted or inserte…
+ vl1 = view_get_line(view, l1);
/* it's technically possible that the remainin…
second line is so small that it doesn't gen…
softline, so there needs to be a special ca…
t@@ -1479,64 +1434,26 @@ view_delete_range_base(
}
}
} else {
- if (line_index1 == line_index2) {
- rgl1 = rgl2 = line_index1;
- if (byte_index1 < byte_index2) {
- rgb1 = byte_index1;
- rgb2 = byte_index2;
- } else {
- rgb1 = byte_index2;
- rgb2 = byte_index1;
- }
- if (text_ret) {
- buffer_copy_text_to_txtbuf(
- view->buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- buffer_delete_line_section_base(view->buffer, line_ind…
- new_line = line_index1;
- new_byte = rgb1;
- } else {
- if (line_index1 < line_index2) {
- rgl1 = line_index1;
- rgb1 = byte_index1;
- rgl2 = line_index2;
- rgb2 = byte_index2;
- } else {
- rgl1 = line_index2;
- rgb1 = byte_index2;
- rgl2 = line_index1;
- rgb2 = byte_index1;
- }
- if (text_ret) {
- buffer_copy_text_to_txtbuf(
- view->buffer, text_ret,
- rgl1, rgb1,
- rgl2, rgb2
- );
- }
- ledit_line *line1 = buffer_get_line(view->buffer, rgl1…
- ledit_line *line2 = buffer_get_line(view->buffer, rgl2…
- buffer_delete_line_section_base(view->buffer, rgl1, rg…
- buffer_insert_text_from_line_base(
- view->buffer, rgl1, rgb1, rgl2, rgb2, line2->len -…
- );
- new_line = rgl1;
- new_byte = rgb1;
- buffer_delete_line_entries_base(view->buffer, rgl1 + 1…
- }
- /* FIXME: too much magic - maybe don't include this here */
- if (view->mode == NORMAL)
- new_byte = view_get_legal_normal_pos(view, new_line, n…
- }
- if (final_range_ret) {
- final_range_ret->line1 = rgl1;
- final_range_ret->byte1 = rgb1;
- final_range_ret->line2 = rgl2;
- final_range_ret->byte2 = rgb2;
+ rgl1 = line_index1;
+ rgb1 = byte_index1;
+ rgl2 = line_index2;
+ rgb2 = byte_index2;
+ new_line = rgl1;
+ new_byte = rgb1;
+ buffer_delete_with_undo_base(
+ view->buffer, cur_range,
+ start_undo_group, view->mode,
+ rgl1, rgb1, rgl2, rgb2, text_ret
+ );
}
+ cur_range.line1 = view->cur_line;
+ cur_range.byte1 = view->cur_index;
+ cur_range.line2 = new_line;
+ cur_range.byte2 = new_byte;
+ undo_change_last_cur_range(view->buffer->undo, cur_range);
+ /* FIXME: too much magic - maybe don't include this here */
+ if (view->mode == NORMAL)
+ new_byte = view_get_legal_normal_pos(view, new_line, new_byte);
if (new_line_ret)
*new_line_ret = new_line;
if (new_byte_ret)
t@@ -2040,27 +1957,11 @@ view_redraw(ledit_view *view) {
}
}
-static void
-undo_insert_helper(void *data, size_t line, size_t byte, char *text, size_t te…
- ledit_view *view = (ledit_view *)data;
- buffer_insert_text_with_newlines_base(view->buffer, line, byte, text, …
-}
-
-static void
-undo_delete_helper(void *data, size_t line1, size_t byte1, size_t line2, size_…
- ledit_view *view = (ledit_view *)data;
- view_delete_range_base(view, DELETE_CHAR, line1, byte1, line2, byte2, …
-}
-
void
view_undo(ledit_view *view) {
/* FIXME: maybe wipe selection */
- size_t min_line;
size_t old_line = view->cur_line;
- ledit_undo(
- view->buffer->undo, view->mode, view, &undo_insert_helper,
- &undo_delete_helper, &view->cur_line, &view->cur_index, &min_line
- );
+ buffer_undo(view->buffer, view->mode, &view->cur_line, &view->cur_inde…
if (view->mode == NORMAL) {
view->cur_index = view_get_legal_normal_pos(
view, view->cur_line, view->cur_index
t@@ -2068,23 +1969,13 @@ view_undo(ledit_view *view) {
}
view_wipe_line_cursor_attrs(view, old_line);
view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
- /* FIXME: why is this check here? */
- if (min_line < view->lines_num) {
- buffer_recalc_all_views_from_line(
- view->buffer, min_line > 0 ? min_line - 1 : min_line
- );
- }
/* FIXME: show undo message */
}
void
view_redo(ledit_view *view) {
- size_t min_line;
size_t old_line = view->cur_line;
- ledit_redo(
- view->buffer->undo, view->mode, view, &undo_insert_helper,
- &undo_delete_helper, &view->cur_line, &view->cur_index, &min_line
- );
+ buffer_redo(view->buffer, view->mode, &view->cur_line, &view->cur_inde…
if (view->mode == NORMAL) {
view->cur_index = view_get_legal_normal_pos(
view, view->cur_line, view->cur_index
t@@ -2092,33 +1983,23 @@ view_redo(ledit_view *view) {
}
view_wipe_line_cursor_attrs(view, old_line);
view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
- if (min_line < view->lines_num) {
- buffer_recalc_all_views_from_line(
- view->buffer, min_line > 0 ? min_line - 1 : min_line
- );
- }
/* FIXME: show undo message */
}
static void
paste_callback(void *data, char *text, size_t len) {
ledit_view *view = (ledit_view *)data;
- txtbuf ins_buf = {.text = text, .len = len, .cap = len};
- ledit_range cur_range, ins_range;
- cur_range.line1 = ins_range.line1 = view->cur_line;
- cur_range.byte1 = ins_range.byte1 = view->cur_index;
- buffer_insert_text_with_newlines(
- view->buffer, view->cur_line, view->cur_index,
- text, len, &view->cur_line, &view->cur_index
- );
- cur_range.line2 = ins_range.line2 = view->cur_line;
- cur_range.byte2 = ins_range.byte2 = view->cur_index;
- undo_push_insert(
- view->buffer->undo, &ins_buf, ins_range, cur_range, 1, view->mode
+ ledit_range cur_range;
+ cur_range.line1 = view->cur_line;
+ cur_range.byte1 = view->cur_index;
+ buffer_insert_with_undo(
+ view->buffer, cur_range, 1, 1, view->mode,
+ view->cur_line, view->cur_index, text, len,
+ &view->cur_line, &view->cur_index
);
}
-/* FIXME: guard against buffer being destroyed before paste callback is nulled…
+/* FIXME: guard against view being destroyed before paste callback is nulled */
void
view_paste_clipboard(ledit_view *view) {
diff --git a/view.h b/view.h
t@@ -339,7 +339,7 @@ size_t view_x_softline_to_pos(ledit_view *view, size_t lin…
size_t view_get_legal_normal_pos(ledit_view *view, size_t line, size_t pos);
/*
- * Delete a range accorxing to a delete_mode.
+ * Delete a range according to a delete_mode.
* The line and byte indeces do not need to be sorted (in fact, they often
* shouldn't be, as shown in the next sentence).
* If 'delmode' is DELETE_HARDLINE or DELETE_SOFTLINE, 'line_index1' and
t@@ -352,19 +352,27 @@ size_t view_get_legal_normal_pos(ledit_view *view, size_…
* in the buffer afterwards, although it may have its text deleted.
* If 'delmode' is DELETE_CHAR, the exact specified range is deleted, and
* the new line and byte are simply the beginning of the range.
- * In all cases, the final deletion range is written to 'final_range_ret',
- * and the deleted text is written to 'text_ret'.
+ * The deleted text is written to 'text_ret'.
* In normal mode, the new cursor index is always at a valid normal mode
* position.
* All return arguments may be NULL.
+ * The deletion is added to the undo stack with 'start_undo_group'
+ * specifying whether a new undo group should be started.
+ * The start cursor position for the undo stack is taken directly from
+ * the view's current position. The end cursor position is the same as
+ * what is returned in 'new_line_ret' and 'new_byte_ret', except that it
+ * is set before calling 'view_get_legal_normal_pos'.
+ * If different cursor positions are needed, call
+ * 'undo_change_last_cur_range' afterwards.
* This function does not recalculate the line heights or offsets.
*/
void view_delete_range_base(
- ledit_view *view, enum delete_mode delmode,
+ ledit_view *view,
+ enum delete_mode delmode, int start_undo_group,
size_t line_index1, size_t byte_index1,
size_t line_index2, size_t byte_index2,
size_t *new_line_ret, size_t *new_byte_ret,
- ledit_range *final_range_ret, txtbuf *text_ret
+ txtbuf *text_ret
);
/*
t@@ -372,11 +380,12 @@ void view_delete_range_base(
* all views are recalculated afterwards.
*/
void view_delete_range(
- ledit_view *view, enum delete_mode delmode,
+ ledit_view *view,
+ enum delete_mode delmode, int start_undo_group,
size_t line_index1, size_t byte_index1,
size_t line_index2, size_t byte_index2,
size_t *new_line_ret, size_t *new_byte_ret,
- ledit_range *final_range_ret, txtbuf *text_ret
+ txtbuf *text_ret
);
/*
You are viewing proxied material from lumidify.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.