aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <rhaberkorn@fmsbw.de>2026-09-25 01:43:56 +0200
committerRobin Haberkorn <rhaberkorn@fmsbw.de>2026-09-25 01:43:56 +0200
commite371b5fc710c597e175e6b7d7645b3a224a731a1 (patch)
tree3861fa4949adfd1c95a06ae0b7dd41c4167a3b7a
parent207af96f4eb3220534ea06c2e107517372246544 (diff)
instead of relying on Scintilla undo actions, use SciTECO undo tokens exclusivelyHEADmaster-fmsbw-cimaster
Previously we were using both Scintilla undo actions and our own undo tokens and both had to be coordinated via `undo__teco_interface_ssm(SCI_UNDO, 0, 0)`. This was error prone since we have to predict when an undo action is actually generated. Furthermore, you had to update SCI_SETUNDOCOLLECTION on all buffers and the Q-Reg view whenever switching to and from interactive mode. Also, this probably wasted memory for the doubled undo bookkeeping. Now, we always set SCI_SETUNDOCOLLECTION(FALSE), even in interactive mode. teco_undo_view_insert() was introduced to undo text deletions. While this saves almost no lines of code, it's just a clearer and simpler architecture.
-rw-r--r--src/cmdline.c3
-rw-r--r--src/core-commands.c64
-rw-r--r--src/glob.c17
-rw-r--r--src/interface.h6
-rw-r--r--src/main.c5
-rw-r--r--src/move-commands.c21
-rw-r--r--src/qreg-commands.c15
-rw-r--r--src/qreg.c19
-rw-r--r--src/ring.c11
-rw-r--r--src/ring.h2
-rw-r--r--src/search.c27
-rw-r--r--src/spawn.c12
-rw-r--r--src/view.c58
-rw-r--r--src/view.h10
14 files changed, 131 insertions, 139 deletions
diff --git a/src/cmdline.c b/src/cmdline.c
index d2d9d04..99bc802 100644
--- a/src/cmdline.c
+++ b/src/cmdline.c
@@ -382,9 +382,6 @@ teco_cmdline_keypress(const gchar *data, gsize len, GError **error)
}
teco_undo_clear();
- /* also empties all Scintilla undo buffers */
- teco_ring_set_scintilla_undo(TRUE);
- teco_view_set_scintilla_undo(teco_qreg_view, TRUE);
/*
* FIXME: Reset main machine?
*/
diff --git a/src/core-commands.c b/src/core-commands.c
index 612d980..6362d95 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -291,13 +291,11 @@ teco_state_start_backslash(teco_machine_main_t *ctx, GError **error)
teco_current_doc_set_dot(teco_ranges[0].to);
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
+ if (teco_current_doc_must_undo())
+ undo__teco_interface_ssm(SCI_DELETERANGE,
+ teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0), len);
teco_interface_ssm(SCI_ADDTEXT, len, (sptr_t)str);
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
teco_ring_dirtify();
-
- if (teco_current_doc_must_undo())
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
} else {
teco_qreg_t *qreg = ctx->qreg_table_locals->radix;
assert(qreg != NULL);
@@ -566,16 +564,11 @@ teco_state_start_cmdline_push(teco_machine_main_t *ctx, GError **error)
const gchar *macro = (const gchar *)teco_cmdline_ssm(SCI_GETCHARACTERPOINTER, 0, 0);
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
+ /* must always support undo on global register */
+ teco_undo_interface_insert(0, teco_interface_ssm(SCI_GETLENGTH, 0, 0));
teco_interface_ssm(SCI_CLEARALL, 0, 0);
+ undo__teco_interface_ssm(SCI_CLEARALL, 0, 0);
teco_interface_ssm(SCI_ADDTEXT, teco_cmdline.pc, (sptr_t)macro);
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
-
- /*
- * Must always support undo on global register.
- * A undo action should always have been generated.
- */
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
/*
* FIXME: If we would maintain dot in the command line,
@@ -2736,16 +2729,15 @@ teco_state_ecommand_encoding(teco_machine_main_t *ctx, GError **error)
if (!converted)
return;
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
- teco_interface_ssm(SCI_CLEARALL, 0, 0);
- teco_interface_ssm(SCI_APPENDTEXT, converted_len, (sptr_t)converted);
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
- teco_ring_dirtify();
-
if (teco_current_doc_must_undo()) {
undo__teco_interface_ssm(SCI_GOTOPOS, dot_bytes, 0);
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
+ teco_undo_interface_insert(0, teco_interface_ssm(SCI_GETLENGTH, 0, 0));
+ undo__teco_interface_ssm(SCI_CLEARALL, 0, 0);
}
+
+ teco_interface_ssm(SCI_CLEARALL, 0, 0);
+ teco_interface_ssm(SCI_APPENDTEXT, converted_len, (sptr_t)converted);
+ teco_ring_dirtify();
}
if (new_cp == SC_CP_UTF8) {
@@ -2985,6 +2977,9 @@ teco_state_insert_initial(teco_machine_main_t *ctx, GError **error)
return TRUE;
}
+ gsize dot_bytes = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+ gsize added_len = 0;
+
if (teco_interface_ssm(SCI_GETCODEPAGE, 0, 0) == SC_CP_UTF8) {
/* detect possible errors before introducing side effects */
for (gint i = args; i > 0; i--) {
@@ -2994,12 +2989,12 @@ teco_state_insert_initial(teco_machine_main_t *ctx, GError **error)
return FALSE;
}
}
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
for (gint i = args; i > 0; i--) {
/* 4 bytes should be enough, but we better follow the documentation */
gchar buf[6];
gsize len = g_unichar_to_utf8(teco_expressions_peek_num(i-1), buf);
teco_interface_ssm(SCI_ADDTEXT, len, (sptr_t)buf);
+ added_len += len;
}
} else {
/* everything else is a single-byte encoding */
@@ -3010,17 +3005,16 @@ teco_state_insert_initial(teco_machine_main_t *ctx, GError **error)
return FALSE;
}
}
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
for (gint i = args; i > 0; i--) {
gchar chr = (gchar)teco_expressions_peek_num(i-1);
teco_interface_ssm(SCI_ADDTEXT, 1, (sptr_t)&chr);
}
+ added_len = args;
}
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
teco_ring_dirtify();
if (teco_current_doc_must_undo())
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
+ undo__teco_interface_ssm(SCI_DELETERANGE, dot_bytes, added_len);
/* This is done only now because it can _theoretically_ fail. */
for (gint i = 0; i < args; i++)
@@ -3038,15 +3032,14 @@ teco_state_insert_process(teco_machine_main_t *ctx, teco_string_t str,
{
g_assert(new_chars > 0);
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
+ if (teco_current_doc_must_undo())
+ undo__teco_interface_ssm(SCI_DELETERANGE,
+ teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0), new_chars);
+
teco_interface_ssm(SCI_ADDTEXT, new_chars,
(sptr_t)(str.data + str.len - new_chars));
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
teco_ring_dirtify();
- if (teco_current_doc_must_undo())
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
-
return TRUE;
}
@@ -3100,8 +3093,11 @@ teco_state_insert_indent_initial(teco_machine_main_t *ctx, GError **error)
if (!teco_state_insert_initial(ctx, error))
return FALSE;
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
if (teco_interface_ssm(SCI_GETUSETABS, 0, 0)) {
+ if (teco_current_doc_must_undo())
+ undo__teco_interface_ssm(SCI_DELETERANGE,
+ teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0), 1);
+
teco_interface_ssm(SCI_ADDTEXT, 1, (sptr_t)"\t");
/* teco_state_insert_done() expects this */
@@ -3115,16 +3111,16 @@ teco_state_insert_indent_initial(teco_machine_main_t *ctx, GError **error)
/* teco_state_insert_done() expects this */
teco_undo_int(teco_ranges[0].to) += len;
+ if (teco_current_doc_must_undo())
+ undo__teco_interface_ssm(SCI_DELETERANGE,
+ teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0), len);
+
gchar space = ' ';
while (len-- > 0)
teco_interface_ssm(SCI_ADDTEXT, 1, (sptr_t)&space);
}
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
teco_ring_dirtify();
- if (teco_current_doc_must_undo())
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
-
return TRUE;
}
diff --git a/src/glob.c b/src/glob.c
index cb571c4..c1efe47 100644
--- a/src/glob.c
+++ b/src/glob.c
@@ -482,6 +482,7 @@ teco_state_glob_filename_done(teco_machine_main_t *ctx, teco_string_t str, GErro
gboolean matching = FALSE;
gboolean colon_modified = teco_machine_main_eval_colon(ctx) > 0;
+ gsize added_len = 0;
teco_int_t teco_test_mode;
@@ -517,6 +518,8 @@ teco_state_glob_filename_done(teco_machine_main_t *ctx, teco_string_t str, GErro
return NULL;
}
+ sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+
if (str.len > 0) {
/*
* Match pattern against provided file name
@@ -535,12 +538,10 @@ teco_state_glob_filename_done(teco_machine_main_t *ctx, teco_string_t str, GErro
gsize len = strlen(filename);
filename[len] = '\n';
- sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
teco_undo_int(teco_ranges[0].from) = teco_current_doc_get_dot();
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
teco_interface_ssm(SCI_ADDTEXT, len+1, (sptr_t)filename);
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
+ added_len += len+1;
teco_int_t to = teco_interface_bytes2glyphs_rel(teco_ranges[0].from, pos, len + 1);
teco_undo_int(teco_ranges[0].to) = to;
@@ -568,12 +569,9 @@ teco_state_glob_filename_done(teco_machine_main_t *ctx, teco_string_t str, GErro
g_autoptr(teco_globber_t) globber;
globber = teco_globber_new(pattern_str.data, file_flags);
- sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
gsize total_len = 0;
teco_undo_int(teco_ranges[0].from) = teco_current_doc_get_dot();
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
-
gchar *globbed_filename;
while ((globbed_filename = teco_globber_next(globber))) {
gsize len = strlen(globbed_filename);
@@ -585,13 +583,12 @@ teco_state_glob_filename_done(teco_machine_main_t *ctx, teco_string_t str, GErro
*/
globbed_filename[len] = '\n';
teco_interface_ssm(SCI_ADDTEXT, len+1, (sptr_t)globbed_filename);
+ added_len += len+1;
g_free(globbed_filename);
matching = TRUE;
}
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
-
teco_int_t to = teco_interface_bytes2glyphs_rel(teco_ranges[0].from, pos, total_len);
teco_undo_int(teco_ranges[0].to) = to;
teco_undo_guint(teco_ranges_count) = 1;
@@ -600,11 +597,11 @@ teco_state_glob_filename_done(teco_machine_main_t *ctx, teco_string_t str, GErro
if (colon_modified) {
teco_expressions_push(teco_bool(matching));
- } else if (matching) {
+ } else if (added_len) {
/* text has been inserted */
teco_ring_dirtify();
if (teco_current_doc_must_undo())
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
+ undo__teco_interface_ssm(SCI_DELETERANGE, pos, added_len);
}
if (!glob_reg->vtable->set_integer(glob_reg, teco_bool(matching), error))
diff --git a/src/interface.h b/src/interface.h
index 9c3d31e..20d9773 100644
--- a/src/interface.h
+++ b/src/interface.h
@@ -286,6 +286,12 @@ teco_interface_get_character(gsize pos, gsize len)
return teco_view_get_character(teco_interface_current_view, pos, len);
}
+static inline void
+teco_undo_interface_insert(gsize pos, gsize len)
+{
+ return teco_undo_view_insert(teco_interface_current_view, pos, len);
+}
+
/*
* The following functions are here for lack of a better place.
* They could also be in sciteco.h, but only if declared as non-inline
diff --git a/src/main.c b/src/main.c
index 29ef024..43f3dc4 100644
--- a/src/main.c
+++ b/src/main.c
@@ -600,8 +600,6 @@ main(int argc, char **argv)
teco_qreg_table_replace(&teco_qreg_table_globals, teco_qreg_plain_new("\e", 1));
teco_undo_enabled = TRUE;
- teco_ring_set_scintilla_undo(TRUE);
- teco_view_set_scintilla_undo(teco_qreg_view, TRUE);
/*
* FIXME: Perhaps we should simply call teco_cmdline_init() and
@@ -633,9 +631,6 @@ main(int argc, char **argv)
*/
teco_undo_enabled = FALSE;
teco_undo_clear();
- /* also empties all Scintilla undo buffers */
- teco_ring_set_scintilla_undo(FALSE);
- teco_view_set_scintilla_undo(teco_qreg_view, FALSE);
if (!teco_ed_hook(TECO_ED_HOOK_QUIT, &error))
goto cleanup;
diff --git a/src/move-commands.c b/src/move-commands.c
index 9ef893e..868bb19 100644
--- a/src/move-commands.c
+++ b/src/move-commands.c
@@ -472,14 +472,10 @@ teco_state_start_delete_words(teco_machine_main_t *ctx, const gchar *cmd, gint f
if (start_pos < pos)
teco_current_doc_set_dot(teco_interface_bytes2glyphs_absdot(start_pos));
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
- teco_interface_ssm(SCI_DELETERANGE, start_pos, end_pos-start_pos);
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
+ if (teco_current_doc_must_undo())
+ teco_undo_interface_insert(start_pos, end_pos-start_pos);
- if (teco_current_doc_must_undo()) {
- undo__teco_interface_ssm(SCI_GOTOPOS, pos, 0);
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
- }
+ teco_interface_ssm(SCI_DELETERANGE, start_pos, end_pos-start_pos);
teco_ring_dirtify();
}
@@ -562,17 +558,10 @@ teco_state_start_kill(teco_machine_main_t *ctx, const gchar *cmd, gboolean by_li
if (len == 0 || teco_is_failure(rc))
return TRUE;
- if (teco_current_doc_must_undo()) {
- undo__teco_interface_ssm(SCI_GOTOPOS, pos, 0);
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
- }
+ if (teco_current_doc_must_undo())
+ teco_undo_interface_insert(from, len);
- /*
- * Should always generate an undo action.
- */
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
teco_interface_ssm(SCI_DELETERANGE, from, len);
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
teco_ring_dirtify();
return TRUE;
diff --git a/src/qreg-commands.c b/src/qreg-commands.c
index a6390a1..0c4c8d4 100644
--- a/src/qreg-commands.c
+++ b/src/qreg-commands.c
@@ -563,13 +563,11 @@ teco_state_getqregstring_got_register(teco_machine_main_t *ctx, teco_qreg_t *qre
sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
if (str.len > 0) {
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
teco_interface_ssm(SCI_ADDTEXT, str.len, (sptr_t)str.data);
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
teco_ring_dirtify();
if (teco_current_doc_must_undo())
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
+ undo__teco_interface_ssm(SCI_DELETERANGE, pos, str.len);
}
teco_undo_int(teco_ranges[0].from) = teco_current_doc_get_dot();
@@ -835,17 +833,10 @@ teco_state_copytoqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
/*
* If @-modified, cut into the register
*/
- if (teco_current_doc_must_undo()) {
- undo__teco_interface_ssm(SCI_GOTOPOS, pos, 0);
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
- }
+ if (teco_current_doc_must_undo())
+ teco_undo_interface_insert(from, len);
- /*
- * Should always generate an undo action.
- */
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
teco_interface_ssm(SCI_DELETERANGE, from, len);
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
teco_ring_dirtify();
if (from+len < pos)
diff --git a/src/qreg.c b/src/qreg.c
index 559373c..9e19202 100644
--- a/src/qreg.c
+++ b/src/qreg.c
@@ -188,7 +188,9 @@ teco_qreg_plain_append_string(teco_qreg_t *qreg, const gchar *str, gsize len, GE
teco_doc_undo_edit(&teco_qreg_current->string);
teco_doc_undo_reset(&qreg->string);
- undo__teco_view_ssm(teco_qreg_view, SCI_UNDO, 0, 0);
+
+ sptr_t pos = teco_view_ssm(teco_qreg_view, SCI_GETCURRENTPOS, 0, 0);
+ undo__teco_view_ssm(teco_qreg_view, SCI_DELETERANGE, pos, len);
}
if (teco_qreg_current)
@@ -196,9 +198,7 @@ teco_qreg_plain_append_string(teco_qreg_t *qreg, const gchar *str, gsize len, GE
teco_doc_edit(&qreg->string, teco_default_codepage());
- teco_view_ssm(teco_qreg_view, SCI_BEGINUNDOACTION, 0, 0);
teco_view_ssm(teco_qreg_view, SCI_APPENDTEXT, len, (sptr_t)str);
- teco_view_ssm(teco_qreg_view, SCI_ENDUNDOACTION, 0, 0);
if (teco_qreg_current)
teco_doc_edit(&teco_qreg_current->string, 0);
@@ -469,12 +469,12 @@ teco_qreg_external_edit(teco_qreg_t *qreg, GError **error)
!qreg->vtable->get_string(qreg, &str.data, &str.len, NULL, error))
return FALSE;
- teco_view_ssm(teco_qreg_view, SCI_BEGINUNDOACTION, 0, 0);
+ teco_undo_view_insert(teco_qreg_view, 0,
+ teco_view_ssm(teco_qreg_view, SCI_GETLENGTH, 0, 0));
teco_view_ssm(teco_qreg_view, SCI_CLEARALL, 0, 0);
+ undo__teco_view_ssm(teco_qreg_view, SCI_CLEARALL, 0, 0);
teco_view_ssm(teco_qreg_view, SCI_ADDTEXT, str.len, (sptr_t)str.data);
- teco_view_ssm(teco_qreg_view, SCI_ENDUNDOACTION, 0, 0);
- undo__teco_view_ssm(teco_qreg_view, SCI_UNDO, 0, 0);
return TRUE;
}
@@ -586,12 +586,11 @@ teco_qreg_external_save(teco_qreg_t *qreg, const gchar *filename, GError **error
if (!qreg->vtable->get_string(qreg, &str.data, &str.len, NULL, error))
return FALSE;
- teco_view_ssm(teco_qreg_view, SCI_BEGINUNDOACTION, 0, 0);
+ teco_undo_view_insert(teco_qreg_view, 0,
+ teco_view_ssm(teco_qreg_view, SCI_GETLENGTH, 0, 0));
teco_view_ssm(teco_qreg_view, SCI_CLEARALL, 0, 0);
+ undo__teco_view_ssm(teco_qreg_view, SCI_CLEARALL, 0, 0);
teco_view_ssm(teco_qreg_view, SCI_ADDTEXT, str.len, (sptr_t)str.data);
- teco_view_ssm(teco_qreg_view, SCI_ENDUNDOACTION, 0, 0);
-
- undo__teco_view_ssm(teco_qreg_view, SCI_UNDO, 0, 0);
gboolean ret = teco_view_save(teco_qreg_view, filename, error);
diff --git a/src/ring.c b/src/ring.c
index dc43ac5..d7643d0 100644
--- a/src/ring.c
+++ b/src/ring.c
@@ -503,15 +503,6 @@ teco_ring_undo_close(void)
undo__teco_ring_remove_buffer(teco_ring_current);
}
-void
-teco_ring_set_scintilla_undo(gboolean state)
-{
- for (teco_tailq_entry_t *cur = teco_ring_head.first; cur != NULL; cur = cur->next) {
- teco_buffer_t *buffer = (teco_buffer_t *)cur;
- teco_view_set_scintilla_undo(buffer->view, state);
- }
-}
-
gboolean
teco_ring_sync_lsp(GError **error)
{
@@ -783,7 +774,7 @@ teco_state_read_file_done(teco_machine_main_t *ctx, teco_string_t str, GError **
teco_ring_dirtify();
if (teco_current_doc_must_undo())
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
+ undo__teco_interface_ssm(SCI_DELETERANGE, from, to-from);
}
return &teco_state_start;
diff --git a/src/ring.h b/src/ring.h
index 126f455..f5606d1 100644
--- a/src/ring.h
+++ b/src/ring.h
@@ -121,8 +121,6 @@ teco_ring_undo_edit(void)
gboolean teco_ring_close(teco_buffer_t *buffer, GError **error);
void teco_ring_undo_close(void);
-void teco_ring_set_scintilla_undo(gboolean state);
-
gboolean teco_ring_sync_lsp(GError **error);
void teco_ring_cleanup(void);
diff --git a/src/search.c b/src/search.c
index 2b2a696..31a551e 100644
--- a/src/search.c
+++ b/src/search.c
@@ -1353,7 +1353,6 @@ teco_state_search_kill_done(teco_machine_main_t *ctx, teco_string_t str, GError
sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
if (teco_search_parameters.pos < pos) {
/* kill forwards */
sptr_t anchor = teco_interface_ssm(SCI_GETANCHOR, 0, 0);
@@ -1361,17 +1360,13 @@ teco_state_search_kill_done(teco_machine_main_t *ctx, teco_string_t str, GError
teco_interface_bytes2glyphs_absdot(teco_search_parameters.pos);
if (teco_current_doc_must_undo())
- undo__teco_interface_ssm(SCI_GOTOPOS, pos, 0);
+ teco_undo_interface_insert(teco_search_parameters.pos,
+ anchor - teco_search_parameters.pos);
teco_interface_ssm(SCI_GOTOPOS, anchor, 0);
teco_interface_ssm(SCI_DELETERANGE, teco_search_parameters.pos,
anchor - teco_search_parameters.pos);
- /* NOTE: An undo action is not always created. */
- if (teco_current_doc_must_undo() &&
- teco_search_parameters.pos != anchor)
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
-
/* fix up ranges (^Y) */
for (guint i = 0; i < teco_ranges_count; i++) {
teco_ranges[i].from -= len_glyphs;
@@ -1384,14 +1379,10 @@ teco_state_search_kill_done(teco_machine_main_t *ctx, teco_string_t str, GError
/* kill backwards */
teco_current_doc_set_dot(teco_interface_bytes2glyphs_absdot(pos));
+ if (teco_current_doc_must_undo())
+ teco_undo_interface_insert(pos, teco_search_parameters.pos - pos);
teco_interface_ssm(SCI_DELETERANGE, pos, teco_search_parameters.pos - pos);
-
- /* NOTE: An undo action is not always created. */
- if (teco_current_doc_must_undo() &&
- teco_search_parameters.pos != pos)
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
}
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
teco_ring_dirtify();
return &teco_state_start;
@@ -1438,13 +1429,13 @@ teco_state_search_delete_done(teco_machine_main_t *ctx, teco_string_t str, GErro
sptr_t anchor = teco_interface_ssm(SCI_GETANCHOR, 0, 0);
teco_current_doc_set_dot(teco_interface_bytes2glyphs_absdot(anchor));
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
+ if (teco_current_doc_must_undo()) {
+ gsize start = teco_interface_ssm(SCI_GETSELECTIONSTART, 0, 0);
+ teco_undo_interface_insert(start, teco_interface_ssm(SCI_GETSELECTIONEND, 0, 0) - start);
+ }
+
teco_interface_ssm(SCI_REPLACESEL, 0, (sptr_t)"");
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
teco_ring_dirtify();
-
- if (teco_current_doc_must_undo())
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
}
return &teco_state_start;
diff --git a/src/spawn.c b/src/spawn.c
index a4bf381..933d8f4 100644
--- a/src/spawn.c
+++ b/src/spawn.c
@@ -422,10 +422,16 @@ teco_state_execute_done(teco_machine_main_t *ctx, teco_string_t str, GError **er
teco_interface_ssm(SCI_GOTOPOS, teco_spawn_ctx.to, 0);
}
- teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
teco_spawn_ctx.start = teco_spawn_ctx.from;
g_main_loop_run(teco_spawn_ctx.mainloop);
if (!teco_spawn_ctx.register_argument) {
+ if (teco_current_doc_must_undo()) {
+ undo__teco_interface_ssm(SCI_DELETERANGE, teco_spawn_ctx.to,
+ teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0)-teco_spawn_ctx.to);
+ teco_undo_interface_insert(teco_spawn_ctx.from,
+ teco_spawn_ctx.to - teco_spawn_ctx.from);
+ }
+
teco_interface_ssm(SCI_DELETERANGE, teco_spawn_ctx.from,
teco_spawn_ctx.to - teco_spawn_ctx.from);
@@ -437,7 +443,6 @@ teco_state_execute_done(teco_machine_main_t *ctx, teco_string_t str, GError **er
teco_current_doc_set_dot(to);
}
- teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
if (teco_spawn_ctx.register_argument) {
if (teco_spawn_ctx.stdout_reader.eol_style >= 0) {
@@ -446,9 +451,6 @@ teco_state_execute_done(teco_machine_main_t *ctx, teco_string_t str, GError **er
teco_spawn_ctx.stdout_reader.eol_style);
}
} else if (teco_spawn_ctx.from != teco_spawn_ctx.to || teco_spawn_ctx.text_added) {
- /* undo action has only been created if it changed anything */
- if (teco_current_doc_must_undo())
- undo__teco_interface_ssm(SCI_UNDO, 0, 0);
teco_ring_dirtify();
}
diff --git a/src/view.c b/src/view.c
index 43cdd3f..d866a5e 100644
--- a/src/view.c
+++ b/src/view.c
@@ -65,10 +65,9 @@ teco_view_setup(teco_view_t *ctx)
SC_MOD_INSERTTEXT | SC_MOD_BEFOREDELETE, 0);
/*
- * Start with or without undo collection,
- * depending on teco_undo_enabled.
+ * We are exclusively using SciTECO's undo tokens.
*/
- teco_view_ssm(ctx, SCI_SETUNDOCOLLECTION, teco_undo_enabled, 0);
+ teco_view_ssm(ctx, SCI_SETUNDOCOLLECTION, FALSE, 0);
teco_view_ssm(ctx, SCI_SETFOCUS, TRUE, 0);
@@ -248,7 +247,6 @@ teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel,
teco_view_ssm(ctx, SCI_RELEASELINECHARACTERINDEX,
SC_LINECHARACTERINDEX_UTF32, 0);
- teco_view_ssm(ctx, SCI_BEGINUNDOACTION, 0, 0);
if (clear) {
teco_view_ssm(ctx, SCI_CLEARALL, 0, 0);
@@ -322,8 +320,6 @@ teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel,
"Inconsistent EOL styles normalized");
cleanup:
- teco_view_ssm(ctx, SCI_ENDUNDOACTION, 0, 0);
-
if (cp == SC_CP_UTF8)
teco_view_ssm(ctx, SCI_ALLOCATELINECHARACTERINDEX,
SC_LINECHARACTERINDEX_UTF32, 0);
@@ -835,6 +831,56 @@ teco_view_get_character(teco_view_t *ctx, gsize pos, gsize len)
return rc < 0 ? rc-1 : rc;
}
+typedef struct {
+ teco_view_t *view;
+ /** dot in bytes before the deletion */
+ gsize dot_bytes;
+ gsize position, length;
+ gchar text[];
+} teco_undo_view_insert_t;
+
+static void
+teco_undo_view_insert_action(teco_undo_view_insert_t *ctx, gboolean run)
+{
+ if (!run)
+ return;
+ teco_view_ssm(ctx->view, SCI_GOTOPOS, ctx->position, 0);
+ teco_view_ssm(ctx->view, SCI_ADDTEXT, ctx->length, (sptr_t)ctx->text);
+ teco_view_ssm(ctx->view, SCI_GOTOPOS, ctx->dot_bytes, 0);
+}
+
+/**
+ * During undo, insert a string from the given view.
+ * This can be used to undo text deletions.
+ *
+ * @param view The view that contains the string
+ * @param pos Beginning of string in bytes
+ * @param len Length of string in bytes
+ */
+void
+teco_undo_view_insert(teco_view_t *view, gsize pos, gsize len)
+{
+ if (!len)
+ return;
+
+ teco_undo_view_insert_t *ctx;
+ ctx = teco_undo_push_size((teco_undo_action_t)teco_undo_view_insert_action,
+ sizeof(*ctx) + len + 1);
+ if (!ctx)
+ return;
+
+ ctx->view = view;
+ ctx->dot_bytes = teco_view_ssm(view, SCI_GETCURRENTPOS, 0, 0);
+ ctx->position = pos;
+ ctx->length = len;
+
+ struct Sci_TextRangeFull range = {
+ .chrg = {pos, pos + len},
+ .lpstrText = ctx->text
+ };
+ teco_view_ssm(view, SCI_GETTEXTRANGEFULL, 0, (sptr_t)&range);
+}
+
void
teco_view_process_notify(teco_view_t *ctx, const SCNotification *notify)
{
diff --git a/src/view.h b/src/view.h
index 887642a..e7c6fa7 100644
--- a/src/view.h
+++ b/src/view.h
@@ -44,14 +44,6 @@ void undo__teco_view_ssm(teco_view_t *, unsigned int, uptr_t, sptr_t);
void teco_view_set_representations(teco_view_t *ctx);
-/** @memberof teco_view_t */
-static inline void
-teco_view_set_scintilla_undo(teco_view_t *ctx, gboolean state)
-{
- teco_view_ssm(ctx, SCI_EMPTYUNDOBUFFER, 0, 0);
- teco_view_ssm(ctx, SCI_SETUNDOCOLLECTION, state, 0);
-}
-
gboolean teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel,
gboolean clear, GError **error);
gboolean teco_view_load_from_file(teco_view_t *ctx, const gchar *filename,
@@ -92,4 +84,6 @@ teco_int_t teco_view_bytes2glyphs_rel(teco_view_t *ctx, teco_int_t pos_glyphs,
teco_int_t teco_view_get_character(teco_view_t *ctx, gsize pos, gsize len);
+void teco_undo_view_insert(teco_view_t *view, gsize pos, gsize len);
+
void teco_view_process_notify(teco_view_t *ctx, const SCNotification *notify);