Placing the cursor after an undo there where it was before the do,
and handling multibyte characters correctly. *Patch by Mark Majeres.* git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@4908 35c25a1d-7b9e-4130-9fde-d3aeb78583b8master
parent
0ae38b4ef8
commit
f5ac8c1ee1
|
@ -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>
|
2014-05-23 Benno Schulenberg <bensberg@justemail.net>
|
||||||
* src/winio.c (edit_draw): Finally, the proper fix for bug #31743;
|
* src/winio.c (edit_draw): Finally, the proper fix for bug #31743;
|
||||||
telling ncurses to really redraw the line, without optimization, so
|
telling ncurses to really redraw the line, without optimization, so
|
||||||
|
|
11
src/chars.c
11
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 char *const bad_mbchar = "\xEF\xBF\xBD";
|
||||||
static const int bad_mbchar_len = 3;
|
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. */
|
/* Enable UTF-8 support. */
|
||||||
void utf8_init(void)
|
void utf8_init(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -274,6 +274,10 @@ void do_uncut_text(void)
|
||||||
* at the current cursor position. */
|
* at the current cursor position. */
|
||||||
copy_from_filestruct(cutbuffer);
|
copy_from_filestruct(cutbuffer);
|
||||||
|
|
||||||
|
#ifndef NANO_TINY
|
||||||
|
update_undo(PASTE);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Set the current place we want to where the text from the
|
/* Set the current place we want to where the text from the
|
||||||
* cutbuffer ends. */
|
* cutbuffer ends. */
|
||||||
openfile->placewewant = xplustabs();
|
openfile->placewewant = xplustabs();
|
||||||
|
|
|
@ -572,6 +572,7 @@ enum
|
||||||
#define UNdel_del (1<<0)
|
#define UNdel_del (1<<0)
|
||||||
#define UNdel_backspace (1<<1)
|
#define UNdel_backspace (1<<1)
|
||||||
#define UNsplit_madenew (1<<2)
|
#define UNsplit_madenew (1<<2)
|
||||||
|
#define UNcut_cutline (1<<3)
|
||||||
#endif /* !NANO_TINY */
|
#endif /* !NANO_TINY */
|
||||||
|
|
||||||
#define VIEW TRUE
|
#define VIEW TRUE
|
||||||
|
|
|
@ -162,6 +162,7 @@ char *striponedir(const char *path);
|
||||||
void utf8_init(void);
|
void utf8_init(void);
|
||||||
bool using_utf8(void);
|
bool using_utf8(void);
|
||||||
#endif
|
#endif
|
||||||
|
char *addstrings(char* str1, size_t len1, char* str2, size_t len2);
|
||||||
#ifndef HAVE_ISBLANK
|
#ifndef HAVE_ISBLANK
|
||||||
bool nisblank(int c);
|
bool nisblank(int c);
|
||||||
#endif
|
#endif
|
||||||
|
|
110
src/text.c
110
src/text.c
|
@ -375,11 +375,17 @@ void undo_cut(undo *u)
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Get to where we need to uncut from. */
|
/* Get to where we need to uncut from. */
|
||||||
|
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);
|
goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
|
||||||
|
|
||||||
copy_from_filestruct(cutbuffer);
|
copy_from_filestruct(cutbuffer);
|
||||||
free_filestruct(cutbuffer);
|
free_filestruct(cutbuffer);
|
||||||
cutbuffer = NULL;
|
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. */
|
/* Redo a cut, or undo an uncut. */
|
||||||
|
@ -406,7 +412,7 @@ void redo_cut(undo *u)
|
||||||
if (!ISSET(CUT_TO_END))
|
if (!ISSET(CUT_TO_END))
|
||||||
openfile->mark_set = TRUE;
|
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);
|
do_cut_text(FALSE, u->to_end, TRUE);
|
||||||
openfile->mark_set = FALSE;
|
openfile->mark_set = FALSE;
|
||||||
openfile->mark_begin = NULL;
|
openfile->mark_begin = NULL;
|
||||||
|
@ -460,9 +466,7 @@ void do_undo(void)
|
||||||
strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]);
|
strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]);
|
||||||
free(f->data);
|
free(f->data);
|
||||||
f->data = data;
|
f->data = data;
|
||||||
if (u->xflags == UNdel_backspace)
|
goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
|
||||||
openfile->current_x += strlen(u->strdata);
|
|
||||||
goto_line_posx(u->mark_begin_lineno, u->mark_begin_x + 1);
|
|
||||||
break;
|
break;
|
||||||
#ifndef DISABLE_WRAPPING
|
#ifndef DISABLE_WRAPPING
|
||||||
case SPLIT:
|
case SPLIT:
|
||||||
|
@ -489,7 +493,7 @@ void do_undo(void)
|
||||||
free(f->data);
|
free(f->data);
|
||||||
f->data = data;
|
f->data = data;
|
||||||
splice_node(f, t, f->next);
|
splice_node(f, t, f->next);
|
||||||
gotolinecolumn = TRUE;
|
goto_line_posx(u->lineno, u->begin);
|
||||||
break;
|
break;
|
||||||
case CUT_EOF:
|
case CUT_EOF:
|
||||||
case CUT:
|
case CUT:
|
||||||
|
@ -504,8 +508,8 @@ void do_undo(void)
|
||||||
undidmsg = _("line break");
|
undidmsg = _("line break");
|
||||||
if (f->next) {
|
if (f->next) {
|
||||||
filestruct *foo = f->next;
|
filestruct *foo = f->next;
|
||||||
f->data = (char *) nrealloc(f->data, strlen(f->data) + strlen(f->next->data) + 1);
|
f->data = (char *) nrealloc(f->data, strlen(f->data) + strlen(&f->next->data[u->mark_begin_x]) + 1);
|
||||||
strcat(f->data, f->next->data);
|
strcat(f->data, &f->next->data[u->mark_begin_x]);
|
||||||
unlink_node(foo);
|
unlink_node(foo);
|
||||||
delete_node(foo);
|
delete_node(foo);
|
||||||
}
|
}
|
||||||
|
@ -629,7 +633,7 @@ void do_redo(void)
|
||||||
delete_node(tmp);
|
delete_node(tmp);
|
||||||
}
|
}
|
||||||
renumber(f);
|
renumber(f);
|
||||||
gotolinecolumn = TRUE;
|
goto_line_posx(u->lineno, u->begin);
|
||||||
break;
|
break;
|
||||||
case CUT_EOF:
|
case CUT_EOF:
|
||||||
case CUT:
|
case CUT:
|
||||||
|
@ -723,6 +727,11 @@ void do_enter(bool undoing)
|
||||||
|
|
||||||
openfile->placewewant = xplustabs();
|
openfile->placewewant = xplustabs();
|
||||||
|
|
||||||
|
#ifndef NANO_TINY
|
||||||
|
if (!undoing)
|
||||||
|
update_undo(ENTER);
|
||||||
|
#endif
|
||||||
|
|
||||||
edit_refresh_needed = TRUE;
|
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
|
/* We need to start copying data into the undo buffer
|
||||||
* or we won't be able to restore it later. */
|
* or we won't be able to restore it later. */
|
||||||
case ADD:
|
case ADD:
|
||||||
data = charalloc(2);
|
|
||||||
data[0] = '\0';
|
|
||||||
u->strdata = data;
|
|
||||||
break;
|
break;
|
||||||
case DEL:
|
case DEL:
|
||||||
if (u->begin != strlen(fs->current->data)) {
|
if (u->begin != strlen(fs->current->data)) {
|
||||||
data = mallocstrncpy(NULL, &fs->current->data[u->begin], 2);
|
char *char_buf = charalloc(mb_cur_max() + 1);
|
||||||
data[1] = '\0';
|
int char_buf_len = parse_mbchar(&fs->current->data[u->begin], char_buf, NULL);
|
||||||
u->strdata = data;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
/* Else purposely fall into unsplit code. */
|
/* 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) {
|
else if (!ISSET(CUT_TO_END) && !u->to_end) {
|
||||||
/* The entire line is being cut regardless of the cursor position. */
|
/* The entire line is being cut regardless of the cursor position. */
|
||||||
u->begin = 0;
|
u->begin = 0;
|
||||||
u->mark_begin_x = 0;
|
u->xflags = UNcut_cutline;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PASTE:
|
case PASTE:
|
||||||
|
@ -942,18 +950,6 @@ void add_undo(undo_type current_action)
|
||||||
u->mark_begin_lineno = fs->current->lineno;
|
u->mark_begin_lineno = fs->current->lineno;
|
||||||
u->mark_begin_x = fs->current_x;
|
u->mark_begin_x = fs->current_x;
|
||||||
u->lineno = fs->current->lineno + cutbottom->lineno - cutbuffer->lineno;
|
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;
|
u->mark_set = TRUE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -979,8 +975,6 @@ void add_undo(undo_type current_action)
|
||||||
void update_undo(undo_type action)
|
void update_undo(undo_type action)
|
||||||
{
|
{
|
||||||
undo *u;
|
undo *u;
|
||||||
char *data;
|
|
||||||
int len = 0;
|
|
||||||
openfilestruct *fs = openfile;
|
openfilestruct *fs = openfile;
|
||||||
|
|
||||||
if (!ISSET(UNDOABLE))
|
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
|
/* Change to an add if we're not using the same undo struct
|
||||||
* that we should be using. */
|
* that we should be using. */
|
||||||
if (action != fs->last_action
|
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)) {
|
&& openfile->current->lineno != fs->current_undo->lineno)) {
|
||||||
add_undo(action);
|
add_undo(action);
|
||||||
return;
|
return;
|
||||||
|
@ -1008,55 +1002,35 @@ void update_undo(undo_type action)
|
||||||
u = fs->undotop;
|
u = fs->undotop;
|
||||||
|
|
||||||
switch (u->type) {
|
switch (u->type) {
|
||||||
case ADD:
|
case ADD: {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf(stderr, "fs->current->data = \"%s\", current_x = %lu, u->begin = %d\n",
|
fprintf(stderr, "fs->current->data = \"%s\", current_x = %lu, u->begin = %d\n",
|
||||||
fs->current->data, (unsigned long) fs->current_x, u->begin);
|
fs->current->data, (unsigned long) fs->current_x, u->begin);
|
||||||
#endif
|
#endif
|
||||||
len = strlen(u->strdata) + 2;
|
char *char_buf = charalloc(mb_cur_max());
|
||||||
data = (char *) nrealloc((void *) u->strdata, len * sizeof(char *));
|
size_t char_buf_len = parse_mbchar(&fs->current->data[u->mark_begin_x], char_buf, NULL);
|
||||||
data[len-2] = fs->current->data[fs->current_x - 1];
|
u->strdata = addstrings(u->strdata, u->strdata?strlen(u->strdata):0, char_buf, char_buf_len);
|
||||||
data[len-1] = '\0';
|
|
||||||
u->strdata = (char *) data;
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf(stderr, "current undo data now \"%s\"\n", u->strdata);
|
fprintf(stderr, "current undo data now \"%s\"\n", u->strdata);
|
||||||
#endif
|
#endif
|
||||||
u->mark_begin_lineno = fs->current->lineno;
|
u->mark_begin_lineno = fs->current->lineno;
|
||||||
u->mark_begin_x = fs->current_x;
|
u->mark_begin_x = fs->current_x;
|
||||||
break;
|
break;
|
||||||
case DEL:
|
}
|
||||||
len = strlen(u->strdata) + 2;
|
case DEL: {
|
||||||
assert(len > 2);
|
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) {
|
if (fs->current_x == u->begin) {
|
||||||
/* They're deleting. */
|
/* They're deleting. */
|
||||||
if (!u->xflags)
|
u->strdata = addstrings(u->strdata, strlen(u->strdata), char_buf, char_buf_len);
|
||||||
u->xflags = UNdel_del;
|
u->mark_begin_x = fs->current_x;
|
||||||
else if (u->xflags != UNdel_del) {
|
} else if (fs->current_x == u->begin - char_buf_len){
|
||||||
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) {
|
|
||||||
/* They're backspacing. */
|
/* They're backspacing. */
|
||||||
if (!u->xflags)
|
u->strdata = addstrings(char_buf, char_buf_len, u->strdata, strlen(u->strdata));
|
||||||
u->xflags = UNdel_backspace;
|
u->begin = fs->current_x;
|
||||||
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--;
|
|
||||||
} else {
|
} else {
|
||||||
/* They deleted something else on the line. */
|
/* They deleted something else on the line. */
|
||||||
|
free(char_buf);
|
||||||
add_undo(DEL);
|
add_undo(DEL);
|
||||||
return;
|
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);
|
fprintf(stderr, "current undo data now \"%s\"\nu->begin = %d\n", u->strdata, u->begin);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case CUT_EOF:
|
case CUT_EOF:
|
||||||
case CUT:
|
case CUT:
|
||||||
if (!cutbuffer)
|
if (!cutbuffer)
|
||||||
|
@ -1095,11 +1070,15 @@ void update_undo(undo_type action)
|
||||||
break;
|
break;
|
||||||
case REPLACE:
|
case REPLACE:
|
||||||
case PASTE:
|
case PASTE:
|
||||||
add_undo(action);
|
u->begin = fs->current_x;
|
||||||
|
u->lineno = openfile->current->lineno;
|
||||||
break;
|
break;
|
||||||
case INSERT:
|
case INSERT:
|
||||||
u->mark_begin_lineno = openfile->current->lineno;
|
u->mark_begin_lineno = openfile->current->lineno;
|
||||||
break;
|
break;
|
||||||
|
case ENTER:
|
||||||
|
u->mark_begin_x = fs->current_x;
|
||||||
|
break;
|
||||||
#ifndef DISABLE_WRAPPING
|
#ifndef DISABLE_WRAPPING
|
||||||
case SPLIT:
|
case SPLIT:
|
||||||
/* This will only be called if we made a completely new line,
|
/* 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 */
|
#endif /* !DISABLE_WRAPPING */
|
||||||
case UNSPLIT:
|
case UNSPLIT:
|
||||||
/* These cases are handled by the earlier check for a new line and action. */
|
/* These cases are handled by the earlier check for a new line and action. */
|
||||||
case ENTER:
|
|
||||||
case OTHER:
|
case OTHER:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue