[Bf-blender-cvs] [366865dd020] master: Undo System: replace with simpler binary diffing buffer storage
Campbell Barton
noreply at git.blender.org
Wed Jul 17 13:22:21 CEST 2019
Commit: 366865dd020904116086e6d9ec46b8f70c42cdd1
Author: Campbell Barton
Date: Thu Jul 11 15:25:52 2019 +1000
Branches: master
https://developer.blender.org/rB366865dd020904116086e6d9ec46b8f70c42cdd1
Undo System: replace with simpler binary diffing buffer storage
Applying/undoing incremental changes didn't fit well when
mixed with periodic snapshots from mem-file undo.
This moves to a much simpler undo system.
- Uses array storage with de-duplication from `BLI_array_store`.
- Loads the buffer into existing text data,
for better performance on large files.
- Has the advantage that Python operators can be supported
since we don't depend on hard coded undo operations.
Solves T67045, T66695, T65909.
===================================================================
M source/blender/blenkernel/BKE_text.h
M source/blender/blenkernel/intern/text.c
M source/blender/editors/include/ED_text.h
M source/blender/editors/interface/interface_ops.c
M source/blender/editors/space_text/text_autocomplete.c
M source/blender/editors/space_text/text_ops.c
M source/blender/editors/space_text/text_undo.c
M source/blender/makesdna/DNA_text_types.h
M source/blender/makesrna/intern/rna_text_api.c
===================================================================
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index c78faa9dd18..6509788932c 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -30,7 +30,6 @@ extern "C" {
struct Main;
struct Text;
struct TextLine;
-struct TextUndoBuf;
void BKE_text_free_lines(struct Text *text);
void BKE_text_free(struct Text *text);
@@ -49,8 +48,8 @@ void BKE_text_copy_data(struct Main *bmain,
const int flag);
struct Text *BKE_text_copy(struct Main *bmain, const struct Text *ta);
void BKE_text_make_local(struct Main *bmain, struct Text *text, const bool lib_local);
-void BKE_text_clear(struct Text *text, struct TextUndoBuf *utxt);
-void BKE_text_write(struct Text *text, struct TextUndoBuf *utxt, const char *str);
+void BKE_text_clear(struct Text *text);
+void BKE_text_write(struct Text *text, const char *str);
int BKE_text_file_modified_check(struct Text *text);
void BKE_text_file_modified_ignore(struct Text *text);
@@ -77,29 +76,26 @@ void txt_move_eol(struct Text *text, const bool sel);
void txt_move_toline(struct Text *text, unsigned int line, const bool sel);
void txt_move_to(struct Text *text, unsigned int line, unsigned int ch, const bool sel);
void txt_pop_sel(struct Text *text);
-void txt_delete_char(struct Text *text, struct TextUndoBuf *utxt);
-void txt_delete_word(struct Text *text, struct TextUndoBuf *utxt);
-void txt_delete_selected(struct Text *text, struct TextUndoBuf *utxt);
+void txt_delete_char(struct Text *text);
+void txt_delete_word(struct Text *text);
+void txt_delete_selected(struct Text *text);
void txt_sel_all(struct Text *text);
void txt_sel_clear(struct Text *text);
void txt_sel_line(struct Text *text);
char *txt_sel_to_buf(struct Text *text, int *r_buf_strlen);
-void txt_insert_buf(struct Text *text, struct TextUndoBuf *utxt, const char *in_buffer);
-void txt_undo_add_op(struct Text *text, struct TextUndoBuf *utxt, int op);
-void txt_do_undo(struct Text *text, struct TextUndoBuf *utxt);
-void txt_do_redo(struct Text *text, struct TextUndoBuf *utxt);
-void txt_split_curline(struct Text *text, struct TextUndoBuf *utxt);
-void txt_backspace_char(struct Text *text, struct TextUndoBuf *utxt);
-void txt_backspace_word(struct Text *text, struct TextUndoBuf *utxt);
-bool txt_add_char(struct Text *text, struct TextUndoBuf *utxt, unsigned int add);
-bool txt_add_raw_char(struct Text *text, struct TextUndoBuf *utxt, unsigned int add);
-bool txt_replace_char(struct Text *text, struct TextUndoBuf *utxt, unsigned int add);
-void txt_unindent(struct Text *text, struct TextUndoBuf *utxt);
-void txt_comment(struct Text *text, struct TextUndoBuf *utxt);
-void txt_indent(struct Text *text, struct TextUndoBuf *utxt);
-void txt_uncomment(struct Text *text, struct TextUndoBuf *utxt);
-void txt_move_lines(struct Text *text, struct TextUndoBuf *utxt, const int direction);
-void txt_duplicate_line(struct Text *text, struct TextUndoBuf *utxt);
+void txt_insert_buf(struct Text *text, const char *in_buffer);
+void txt_split_curline(struct Text *text);
+void txt_backspace_char(struct Text *text);
+void txt_backspace_word(struct Text *text);
+bool txt_add_char(struct Text *text, unsigned int add);
+bool txt_add_raw_char(struct Text *text, unsigned int add);
+bool txt_replace_char(struct Text *text, unsigned int add);
+void txt_unindent(struct Text *text);
+void txt_comment(struct Text *text);
+void txt_indent(struct Text *text);
+void txt_uncomment(struct Text *text);
+void txt_move_lines(struct Text *text, const int direction);
+void txt_duplicate_line(struct Text *text);
int txt_setcurr_tab_spaces(struct Text *text, int space);
bool txt_cursor_is_line_start(struct Text *text);
bool txt_cursor_is_line_end(struct Text *text);
@@ -125,10 +121,9 @@ enum {
TXT_MOVE_LINE_DOWN = 1,
};
-typedef struct TextUndoBuf {
- char *buf;
- int pos, len;
-} TextUndoBuf;
+/* Fast non-validating buffer conversion for undo. */
+char *txt_to_buf_for_undo(struct Text *text, int *r_buf_strlen);
+void txt_from_buf_for_undo(struct Text *text, const char *buf, int buf_len);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 1d6de646255..b922aabc171 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -79,96 +79,24 @@
*
* Display
* --
+ *
* The st->top determines at what line the top of the text is displayed.
* If the user moves the cursor the st containing that cursor should
* be popped ... other st's retain their own top location.
- *
- * Undo
- * --
- * Undo/Redo works by storing
- * events in a queue, and a pointer
- * to the current position in the
- * queue...
- *
- * Events are stored using an
- * arbitrary op-code system
- * to keep track of
- * a) the two cursors (normal and selected)
- * b) input (visible and control (ie backspace))
- *
- * input data is stored as its
- * ASCII value, the opcodes are
- * then selected to not conflict.
- *
- * opcodes with data in between are
- * written at the beginning and end
- * of the data to allow undo and redo
- * to simply check the code at the current
- * undo position
*/
-/* Undo opcodes */
-
-enum {
- /* Complex editing */
- /* 1 - opcode is followed by 1 byte for ascii character and opcode (repeat)) */
- /* 2 - opcode is followed by 2 bytes for utf-8 character and opcode (repeat)) */
- /* 3 - opcode is followed by 3 bytes for utf-8 character and opcode (repeat)) */
- /* 4 - opcode is followed by 4 bytes for unicode character and opcode (repeat)) */
- UNDO_INSERT_1 = 013,
- UNDO_INSERT_2 = 014,
- UNDO_INSERT_3 = 015,
- UNDO_INSERT_4 = 016,
-
- UNDO_BS_1 = 017,
- UNDO_BS_2 = 020,
- UNDO_BS_3 = 021,
- UNDO_BS_4 = 022,
-
- UNDO_DEL_1 = 023,
- UNDO_DEL_2 = 024,
- UNDO_DEL_3 = 025,
- UNDO_DEL_4 = 026,
-
- /* Text block (opcode is followed
- * by 4 character length ID + the text
- * block itself + the 4 character length
- * ID (repeat) and opcode (repeat)) */
- UNDO_DBLOCK = 027, /* Delete block */
- UNDO_IBLOCK = 030, /* Insert block */
-
- /* Misc */
- UNDO_INDENT = 032,
- UNDO_UNINDENT = 033,
- UNDO_COMMENT = 034,
- UNDO_UNCOMMENT = 035,
-
- UNDO_MOVE_LINES_UP = 036,
- UNDO_MOVE_LINES_DOWN = 037,
-
- UNDO_DUPLICATE = 040,
-};
-
/***/
static void txt_pop_first(Text *text);
static void txt_pop_last(Text *text);
-static void txt_undo_add_blockop(Text *text, TextUndoBuf *utxt, int op, const char *buf);
static void txt_delete_line(Text *text, TextLine *line);
-static void txt_delete_sel(Text *text, TextUndoBuf *utxt);
+static void txt_delete_sel(Text *text);
static void txt_make_dirty(Text *text);
/***/
/**
- * Set to true when undoing (so we don't generate undo steps while undoing).
- *
- * Also use to disable undo entirely.
- */
-static bool undoing;
-
-/**
- * \note caller must handle `undo_buf` and `compiled` members.
+ * \note caller must handle `compiled` member.
*/
void BKE_text_free_lines(Text *text)
{
@@ -516,29 +444,17 @@ void BKE_text_make_local(Main *bmain, Text *text, const bool lib_local)
BKE_id_make_local_generic(bmain, &text->id, true, lib_local);
}
-void BKE_text_clear(Text *text, TextUndoBuf *utxt) /* called directly from rna */
+void BKE_text_clear(Text *text) /* called directly from rna */
{
- const bool undoing_orig = undoing;
- undoing = (utxt == NULL);
-
txt_sel_all(text);
- txt_delete_sel(text, utxt);
-
- undoing = undoing_orig;
-
+ txt_delete_sel(text);
txt_make_dirty(text);
}
-void BKE_text_write(Text *text, TextUndoBuf *utxt, const char *str) /* called directly from rna */
+void BKE_text_write(Text *text, const char *str) /* called directly from rna */
{
- const bool undoing_orig = undoing;
- undoing = (utxt == NULL);
-
- txt_insert_buf(text, utxt, str);
+ txt_insert_buf(text, str);
txt_move_eof(text, 0);
-
- undoing = undoing_orig;
-
txt_make_dirty(text);
}
@@ -1270,7 +1186,7 @@ bool txt_has_sel(Text *text)
return ((text->curl != text->sell) || (text->curc != text->selc));
}
-static void txt_delete_sel(Text *text, TextUndoBuf *utxt)
+static void txt_delete_sel(Text *text)
{
TextLine *tmpl;
char *buf;
@@ -1288,12 +1204,6 @@ static void txt_delete_sel(Text *text, TextUndoBuf *utxt)
txt_order_cursors(text, false);
- if (!undoing) {
- buf = txt_sel_to_buf(text, NULL);
- txt_undo_add_blockop(text, utxt, UNDO_DBLOCK, buf);
- MEM_freeN(buf);
- }
-
buf = MEM_mallocN(text->curc + (text->sell->len - text->selc) + 1, "textline_string");
strncpy(buf, text->curl->line, text->curc);
@@ -1349,6 +1259,106 @@ void txt_sel_line(Text *text)
text->selc = text->sell->len;
}
+/* -------------------------------------------------------------------- */
+/** \name Buffer Conversion for Undo/Redo
+ *
+ * Buffer conversion functions that rely on the buffer already being validated.
+ *
+ * The only requirement for these functions is that they're reverse-able,
+ * the undo logic doesn't inspect their content.
+ *
+ * Currently buffers:
+ * - Always ends with a new-line.
+ * - Are not null terminated.
+ * \{ */
+
+/**
+ * Create a buffer, the only requirement is #txt_from_buf_for_undo can decode it.
+ */
+char *txt_to_buf_for_undo(Text *text, int *r_buf_len)
+{
+ int buf_len = 0;
+ for (const TextLine *l = text->lines.first; l; l = l->next) {
+ buf_len += l->len + 1;
+ }
+ char *buf = MEM_mallocN(buf_len, __func__);
+ char *buf_step = buf;
+ for (const TextLine *l = text->lines.first; l; l = l->next) {
+ memcpy(buf_step, l->line, l->len);
+ buf_step += l->len;
+ *buf_step++ = '\n';
+ }
+ *r_buf_len = buf_len;
+ return buf;
+}
+
+/**
+ * Decode a buffer from #txt_to_buf_for_undo.
+ */
+void txt_from_buf_for_undo(Text *text, const char *buf, int buf_len)
+{
+ const char *buf_end = buf + buf_len;
+ const char *buf_step = buf;
+
+ /* First re-use existing lines.
+ * Good for undo since it means in practice many operations re-use all
+ * except for the modified line. */
+ TextLine *l_src = text->lines.first;
+ BLI_listbase_clear(&text->lines);
+ while (buf_step != buf_end && l_src) {
+ /* New lines are ensured by #txt_to_buf
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list