Fix crash with auto-indent
[claws.git] / src / undo.c
index ec24e6f2ad564bd15adc3f9001d13b09be634062..61c4573404d907cd81ccc388bf390e22f63424a7 100644 (file)
@@ -307,7 +307,7 @@ static void undo_add(const gchar *text,
                                      undostruct->change_state_data);
 
        if (undostruct->paste != 0) {
-               if (action == UNDO_ACTION_INSERT) 
+               if (action == UNDO_ACTION_INSERT)
                        action = UNDO_ACTION_REPLACE_INSERT;
                else 
                        action = UNDO_ACTION_REPLACE_DELETE;
@@ -394,7 +394,7 @@ void undo_undo(UndoMain *undostruct)
                gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, undoinfo->start_pos);
                gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, undoinfo->end_pos);
                gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
-               /* "pull" another data structure from the list */
+               /* "pull" previous matching DELETE data structure from the list */
                if (undostruct->undo){
                        undoinfo = (UndoInfo *)undostruct->undo->data;
                        undostruct->redo = g_list_prepend(undostruct->redo, undoinfo);
@@ -405,7 +405,19 @@ void undo_undo(UndoMain *undostruct)
                }
                break;
        case UNDO_ACTION_REPLACE_DELETE:
-               g_warning("This should not happen. UNDO_REPLACE_DELETE");
+               gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, undoinfo->start_pos);
+               gtk_text_buffer_insert(buffer, &start_iter, undoinfo->text, -1);
+               /* "pull" previous matching INSERT data structure from the list */
+               if (undostruct->undo){
+                       undoinfo = (UndoInfo *)undostruct->undo->data;
+                       undostruct->redo = g_list_prepend(undostruct->redo, undoinfo);
+                       undostruct->undo = g_list_remove(undostruct->undo, undoinfo);
+                       cm_return_if_fail(undoinfo != NULL);
+                       cm_return_if_fail(undoinfo->action == UNDO_ACTION_REPLACE_INSERT);
+                       gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, undoinfo->start_pos);
+                       gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, undoinfo->end_pos);
+                       gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
+               }
                break;
        default:
                g_assert_not_reached();
@@ -478,7 +490,7 @@ void undo_redo(UndoMain *undostruct)
                gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, redoinfo->end_pos);
                gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
                debug_print("UNDO_ACTION_REPLACE %s\n", redoinfo->text);
-               /* "pull" another data structure from the list */
+               /* "pull" previous matching INSERT data structure from the list */
                redoinfo = (UndoInfo *)undostruct->redo->data;
                cm_return_if_fail(redoinfo != NULL);
                undostruct->undo = g_list_prepend(undostruct->undo, redoinfo);
@@ -487,9 +499,19 @@ void undo_redo(UndoMain *undostruct)
                gtk_text_buffer_insert(buffer, &start_iter, redoinfo->text, -1);
                break;
        case UNDO_ACTION_REPLACE_INSERT:
-               /* This is needed only if we redo from a middle-click button */
                gtk_text_buffer_get_iter_at_offset(buffer, &iter, redoinfo->start_pos);
                gtk_text_buffer_insert(buffer, &iter, redoinfo->text, -1);
+               /* "pull" previous matching DELETE structure from the list */
+               redoinfo = (UndoInfo *)undostruct->redo->data;
+               /* Do nothing if we redo from a middle-click button
+                * and next action is not UNDO_ACTION_REPLACE_DELETE */
+               if (redoinfo && redoinfo->action == UNDO_ACTION_REPLACE_DELETE) {
+                       undostruct->undo = g_list_prepend(undostruct->undo, redoinfo);
+                       undostruct->redo = g_list_remove(undostruct->redo, redoinfo);
+                       gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, redoinfo->start_pos);
+                       gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, redoinfo->end_pos);
+                       gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
+               }
                break;
        default:
                g_assert_not_reached();
@@ -578,6 +600,9 @@ static void end_wrap_undo(UndoMain *undostruct)
        if (undostruct->wrap_info->start_pos == -1)
                goto cleanup;
 
+       cm_return_if_fail(undostruct->wrap_info->end_pos > undostruct->wrap_info->start_pos);
+       cm_return_if_fail(undostruct->wrap_info->end_pos - undostruct->wrap_info->len_change > undostruct->wrap_info->start_pos);
+
        /* get the whole new (wrapped) contents */
        buffer = gtk_text_view_get_buffer(undostruct->textview);
        gtk_text_buffer_get_start_iter(buffer, &start);
@@ -646,14 +671,18 @@ static void update_wrap_undo(UndoMain *undostruct, const gchar *text, int start,
                 * change, and the total length of the changed region
                 * increases.
                 */
-               undostruct->wrap_info->end_pos = end;
+               if (end > undostruct->wrap_info->end_pos) {
+                       undostruct->wrap_info->end_pos = end;
+               }
                undostruct->wrap_info->len_change += len;
        } else if (action == UNDO_ACTION_DELETE) {
                /* If deleting, the end of the region is at the start of the
                 * change, and the total length of the changed region
                 * decreases.
                 */
-               undostruct->wrap_info->end_pos = start;
+               if (start > undostruct->wrap_info->end_pos) {
+                       undostruct->wrap_info->end_pos = start;
+               }
                undostruct->wrap_info->len_change -= len;
        }
 }