diff --git a/ChangeLog b/ChangeLog
index a12556314a23e90d83753c0c7bf0e35f5b8e81b0..4a549bcd9943659246cbcb98a65502c343dbdda6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2014-05-25  Mark Majeres  <mark@engine12.com>
+	* src/chars.c (addstrings): New function, concatenates two allocated
+	strings, tacking the second onto the first and freeing the second.
+	* src/cut.c (do_uncut_text): Update the undo structure for a paste.
+	* src/text.c (undo_cut, redo_cut, add_undo, update_undo): Place the
+	cursor after an undo there where it was before the do, and handle
+	multibyte characters correctly.
+
 2014-05-23  Benno Schulenberg  <bensberg@justemail.net>
 	* src/winio.c (edit_draw): Finally, the proper fix for bug #31743;
 	telling ncurses to really redraw the line, without optimization, so
diff --git a/src/chars.c b/src/chars.c
index b09a6d33c499c7629e4906b0fc927530b17f3ead..65c340ebba6eaf10f47e9a40326d3af7f8e5a068 100644
--- a/src/chars.c
+++ b/src/chars.c
@@ -43,6 +43,17 @@ static const wchar_t bad_wchar = 0xFFFD;
 static const char *const bad_mbchar = "\xEF\xBF\xBD";
 static const int bad_mbchar_len = 3;
 
+/* Concatenate two allocated strings. */
+char* addstrings(char* str1, size_t len1, char* str2, size_t len2)
+{
+    str1 = charealloc(str1, len1 + len2 + 1);
+    str1[len1] = '\0';
+    strncat(&str1[len1], str2, len2);
+    free(str2);
+
+    return str1;
+}
+
 /* Enable UTF-8 support. */
 void utf8_init(void)
 {
diff --git a/src/cut.c b/src/cut.c
index 6f98e743ddce8c84db931cc1eb7050b6438376bb..e766d92a92856a7b33084aa625f8b5a69c691e2f 100644
--- a/src/cut.c
+++ b/src/cut.c
@@ -274,6 +274,10 @@ void do_uncut_text(void)
      * at the current cursor position. */
     copy_from_filestruct(cutbuffer);
 
+#ifndef NANO_TINY
+    update_undo(PASTE);
+#endif
+
     /* Set the current place we want to where the text from the
      * cutbuffer ends. */
     openfile->placewewant = xplustabs();
diff --git a/src/nano.h b/src/nano.h
index c97faad6e7d29138d52066c5069bdddb6d313cf2..f338b95a6227b6997e393abebf57c9c33fe28337 100644
--- a/src/nano.h
+++ b/src/nano.h
@@ -572,6 +572,7 @@ enum
 #define UNdel_del		(1<<0)
 #define UNdel_backspace	(1<<1)
 #define UNsplit_madenew	(1<<2)
+#define UNcut_cutline		(1<<3)
 #endif /* !NANO_TINY */
 
 #define VIEW TRUE
diff --git a/src/proto.h b/src/proto.h
index c1f17b9b689b8c6fa95166081edc50f46ae63632..de10f57f1703dcc56427176ca852235089b67989 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -162,6 +162,7 @@ char *striponedir(const char *path);
 void utf8_init(void);
 bool using_utf8(void);
 #endif
+char *addstrings(char* str1, size_t len1, char* str2, size_t len2);
 #ifndef HAVE_ISBLANK
 bool nisblank(int c);
 #endif
diff --git a/src/text.c b/src/text.c
index 662b3fd9819ee749b4d990899f8cbb5c2219b2a0..b49c29f0b4430f5e5cdd54297a82573b2418d9b3 100644
--- a/src/text.c
+++ b/src/text.c
@@ -375,11 +375,17 @@ void undo_cut(undo *u)
 	;
 
     /* Get to where we need to uncut from. */
-    goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
+    if (u->xflags == UNcut_cutline)
+	goto_line_posx(u->mark_begin_lineno, 0);
+    else
+	goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
 
     copy_from_filestruct(cutbuffer);
     free_filestruct(cutbuffer);
     cutbuffer = NULL;
+
+    if (u->xflags == UNcut_cutline)
+	goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
 }
 
 /* Redo a cut, or undo an uncut. */
@@ -406,7 +412,7 @@ void redo_cut(undo *u)
     if (!ISSET(CUT_TO_END))
 	openfile->mark_set = TRUE;
 
-    openfile->mark_begin_x = u->mark_begin_x;
+    openfile->mark_begin_x = (u->xflags == UNcut_cutline) ? 0 : u->mark_begin_x;
     do_cut_text(FALSE, u->to_end, TRUE);
     openfile->mark_set = FALSE;
     openfile->mark_begin = NULL;
@@ -460,9 +466,7 @@ void do_undo(void)
 	strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]);
 	free(f->data);
 	f->data = data;
-	if (u->xflags == UNdel_backspace)
-	    openfile->current_x += strlen(u->strdata);
-	goto_line_posx(u->mark_begin_lineno, u->mark_begin_x + 1);
+	goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
 	break;
 #ifndef DISABLE_WRAPPING
     case SPLIT:
@@ -489,7 +493,7 @@ void do_undo(void)
 	free(f->data);
 	f->data = data;
 	splice_node(f, t, f->next);
-	gotolinecolumn = TRUE;
+	goto_line_posx(u->lineno, u->begin);
 	break;
     case CUT_EOF:
     case CUT:
@@ -504,8 +508,8 @@ void do_undo(void)
 	undidmsg = _("line break");
 	if (f->next) {
 	    filestruct *foo = f->next;
-	    f->data = (char *) nrealloc(f->data, strlen(f->data) + strlen(f->next->data) + 1);
-	    strcat(f->data, f->next->data);
+	    f->data = (char *) nrealloc(f->data, strlen(f->data) + strlen(&f->next->data[u->mark_begin_x]) + 1);
+	    strcat(f->data, &f->next->data[u->mark_begin_x]);
 	    unlink_node(foo);
 	    delete_node(foo);
 	}
@@ -629,7 +633,7 @@ void do_redo(void)
 	    delete_node(tmp);
 	}
 	renumber(f);
-	gotolinecolumn = TRUE;
+	goto_line_posx(u->lineno, u->begin);
 	break;
     case CUT_EOF:
     case CUT:
@@ -723,6 +727,11 @@ void do_enter(bool undoing)
 
     openfile->placewewant = xplustabs();
 
+#ifndef NANO_TINY
+    if (!undoing)
+	update_undo(ENTER);
+#endif
+
     edit_refresh_needed = TRUE;
 }
 
@@ -879,15 +888,14 @@ void add_undo(undo_type current_action)
     /* We need to start copying data into the undo buffer
      * or we won't be able to restore it later. */
     case ADD:
-        data = charalloc(2);
-	data[0] = '\0';
-        u->strdata = data;
 	break;
     case DEL:
 	if (u->begin != strlen(fs->current->data)) {
-            data = mallocstrncpy(NULL, &fs->current->data[u->begin], 2);
-            data[1] = '\0';
-            u->strdata = data;
+	    char *char_buf = charalloc(mb_cur_max() + 1);
+	    int char_buf_len = parse_mbchar(&fs->current->data[u->begin], char_buf, NULL);
+	    char_buf[char_buf_len] = '\0';
+	    u->strdata = char_buf;  /* Note: there is likely more memory allocated than necessary. */
+	    u->mark_begin_x += char_buf_len;
 	    break;
 	}
 	/* Else purposely fall into unsplit code. */
@@ -929,7 +937,7 @@ void add_undo(undo_type current_action)
 	else if (!ISSET(CUT_TO_END) && !u->to_end) {
 	    /* The entire line is being cut regardless of the cursor position. */
 	    u->begin = 0;
-	    u->mark_begin_x = 0;
+	    u->xflags = UNcut_cutline;
 	}
 	break;
     case PASTE:
@@ -942,18 +950,6 @@ void add_undo(undo_type current_action)
 	    u->mark_begin_lineno = fs->current->lineno;
 	    u->mark_begin_x = fs->current_x;
 	    u->lineno = fs->current->lineno + cutbottom->lineno - cutbuffer->lineno;
-
-	    filestruct *fs_buff = cutbuffer;
-	    if (fs_buff->lineno == cutbottom->lineno)
-		u->begin = fs->current_x + get_totsize(fs_buff, cutbottom);
-	    else {
-		/* Advance fs_buff to the last line in the cutbuffer. */
-		while (fs_buff->lineno != cutbottom->lineno && fs_buff->next != NULL)
-		    fs_buff = fs_buff->next;
-		assert(fs_buff->next != NULL);
-		u->begin = get_totsize(fs_buff, cutbottom);
-	    }
-
 	    u->mark_set = TRUE;
 	}
 	break;
@@ -979,8 +975,6 @@ void add_undo(undo_type current_action)
 void update_undo(undo_type action)
 {
     undo *u;
-    char *data;
-    int len = 0;
     openfilestruct *fs = openfile;
 
     if (!ISSET(UNDOABLE))
@@ -998,7 +992,7 @@ void update_undo(undo_type action)
     /* Change to an add if we're not using the same undo struct
      * that we should be using. */
     if (action != fs->last_action
-	|| (action != CUT && action != INSERT && action != SPLIT
+	|| (action != ENTER && action != CUT && action != INSERT && action != SPLIT
 	    && openfile->current->lineno != fs->current_undo->lineno)) {
         add_undo(action);
 	return;
@@ -1008,55 +1002,35 @@ void update_undo(undo_type action)
     u = fs->undotop;
 
     switch (u->type) {
-    case ADD:
+    case ADD: {
 #ifdef DEBUG
         fprintf(stderr, "fs->current->data = \"%s\", current_x = %lu, u->begin = %d\n",
 			fs->current->data, (unsigned long) fs->current_x, u->begin);
 #endif
-        len = strlen(u->strdata) + 2;
-        data = (char *) nrealloc((void *) u->strdata, len * sizeof(char *));
-        data[len-2] = fs->current->data[fs->current_x - 1];
-        data[len-1] = '\0';
-        u->strdata = (char *) data;
+	char *char_buf = charalloc(mb_cur_max());
+	size_t char_buf_len = parse_mbchar(&fs->current->data[u->mark_begin_x], char_buf, NULL);
+	u->strdata = addstrings(u->strdata, u->strdata?strlen(u->strdata):0, char_buf, char_buf_len);
 #ifdef DEBUG
 	fprintf(stderr, "current undo data now \"%s\"\n", u->strdata);
 #endif
 	u->mark_begin_lineno = fs->current->lineno;
 	u->mark_begin_x = fs->current_x;
 	break;
-    case DEL:
-	len = strlen(u->strdata) + 2;
-	assert(len > 2);
+    }
+    case DEL: {
+	char *char_buf = charalloc(mb_cur_max());
+	size_t char_buf_len = parse_mbchar(&fs->current->data[fs->current_x], char_buf, NULL);
         if (fs->current_x == u->begin) {
 	    /* They're deleting. */
-	    if (!u->xflags)
-		u->xflags = UNdel_del;
-	    else if (u->xflags != UNdel_del) {
-		add_undo(action);
-		return;
-	    }
-	    data = charalloc(len);
-	    strcpy(data, u->strdata);
-	    data[len-2] = fs->current->data[fs->current_x];
-	    data[len-1] = '\0';
-	    free(u->strdata);
-	    u->strdata = data;
-	} else if (fs->current_x == u->begin - 1) {
+	    u->strdata = addstrings(u->strdata, strlen(u->strdata), char_buf, char_buf_len);
+	    u->mark_begin_x = fs->current_x;
+	} else if (fs->current_x == u->begin - char_buf_len){
 	    /* They're backspacing. */
-	    if (!u->xflags)
-		u->xflags = UNdel_backspace;
-	    else if (u->xflags != UNdel_backspace) {
-		add_undo(action);
-		return;
-	    }
-	    data = charalloc(len);
-	    data[0] = fs->current->data[fs->current_x];
-	    strcpy(&data[1], u->strdata);
-	    free(u->strdata);
-	    u->strdata = data;
-	    u->begin--;
+	    u->strdata = addstrings(char_buf, char_buf_len, u->strdata, strlen(u->strdata));
+	    u->begin = fs->current_x;
 	} else {
 	    /* They deleted something else on the line. */
+	    free(char_buf);
 	    add_undo(DEL);
 	    return;
 	}
@@ -1064,6 +1038,7 @@ void update_undo(undo_type action)
 	fprintf(stderr, "current undo data now \"%s\"\nu->begin = %d\n", u->strdata, u->begin);
 #endif
 	break;
+    }
     case CUT_EOF:
     case CUT:
 	if (!cutbuffer)
@@ -1095,11 +1070,15 @@ void update_undo(undo_type action)
 	break;
     case REPLACE:
     case PASTE:
-	add_undo(action);
+	u->begin = fs->current_x;
+	u->lineno = openfile->current->lineno;
 	break;
     case INSERT:
 	u->mark_begin_lineno = openfile->current->lineno;
 	break;
+    case ENTER:
+	u->mark_begin_x = fs->current_x;
+	break;
 #ifndef DISABLE_WRAPPING
     case SPLIT:
 	/* This will only be called if we made a completely new line,
@@ -1109,7 +1088,6 @@ void update_undo(undo_type action)
 #endif /* !DISABLE_WRAPPING */
     case UNSPLIT:
 	/* These cases are handled by the earlier check for a new line and action. */
-    case ENTER:
     case OTHER:
 	break;
     }