Going to the correct positions for undoing and redoing cuts and
pastes. This fixes many undo problems and Savannah bug #25585. *Patch by Mark Majeres.* git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@4893 35c25a1d-7b9e-4130-9fde-d3aeb78583b8master
parent
4774ca645f
commit
6081546161
|
@ -1,3 +1,8 @@
|
||||||
|
2014-05-15 Mark Majeres <mark@engine12.com>
|
||||||
|
* src/*, but mainly src/text.c (undo_cut, redo_cut, do_undo, do_redo):
|
||||||
|
Go to the correct positions for undoing/redoing the cuts and pastes.
|
||||||
|
This fixes several undo problems and Savannah bug #25585.
|
||||||
|
|
||||||
2014-05-15 Benno Schulenberg <bensberg@justemail.net>
|
2014-05-15 Benno Schulenberg <bensberg@justemail.net>
|
||||||
* doc/syntax/c.nanorc: Improve the magic regex, plus tweaks.
|
* doc/syntax/c.nanorc: Improve the magic regex, plus tweaks.
|
||||||
* src/color.c (color_update): Adjust a comment, and be clearer.
|
* src/color.c (color_update): Adjust a comment, and be clearer.
|
||||||
|
|
|
@ -44,6 +44,9 @@ void cutbuffer_reset(void)
|
||||||
* current line. */
|
* current line. */
|
||||||
void cut_line(void)
|
void cut_line(void)
|
||||||
{
|
{
|
||||||
|
if(!openfile->mark_begin)
|
||||||
|
openfile->mark_begin = openfile->current;
|
||||||
|
|
||||||
if (openfile->current != openfile->filebot)
|
if (openfile->current != openfile->filebot)
|
||||||
move_to_filestruct(&cutbuffer, &cutbottom, openfile->current, 0,
|
move_to_filestruct(&cutbuffer, &cutbottom, openfile->current, 0,
|
||||||
openfile->current->next, 0);
|
openfile->current->next, 0);
|
||||||
|
@ -204,7 +207,7 @@ void do_cut_text(
|
||||||
if (!old_no_newlines)
|
if (!old_no_newlines)
|
||||||
UNSET(NO_NEWLINES);
|
UNSET(NO_NEWLINES);
|
||||||
} else if (!undoing)
|
} else if (!undoing)
|
||||||
update_undo(CUT);
|
update_undo(cut_till_end ? CUT_EOF : CUT);
|
||||||
|
|
||||||
/* Leave the text in the cutbuffer, and mark the file as
|
/* Leave the text in the cutbuffer, and mark the file as
|
||||||
* modified. */
|
* modified. */
|
||||||
|
@ -249,7 +252,7 @@ void do_copy_text(void)
|
||||||
/* Cut from the current cursor position to the end of the file. */
|
/* Cut from the current cursor position to the end of the file. */
|
||||||
void do_cut_till_end(void)
|
void do_cut_till_end(void)
|
||||||
{
|
{
|
||||||
add_undo(CUT);
|
add_undo(CUT_EOF);
|
||||||
do_cut_text(FALSE, TRUE, FALSE);
|
do_cut_text(FALSE, TRUE, FALSE);
|
||||||
}
|
}
|
||||||
#endif /* !NANO_TINY */
|
#endif /* !NANO_TINY */
|
||||||
|
@ -264,7 +267,7 @@ void do_uncut_text(void)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
update_undo(UNCUT);
|
add_undo(PASTE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Add a copy of the text in the cutbuffer to the current filestruct
|
/* Add a copy of the text in the cutbuffer to the current filestruct
|
||||||
|
|
|
@ -570,7 +570,7 @@ void do_down(
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If we're at the bottom of the file, get out. */
|
/* If we're at the bottom of the file, get out. */
|
||||||
if (openfile->current == openfile->filebot)
|
if (openfile->current == openfile->filebot || !openfile->current->next)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert(ISSET(SOFTWRAP) || openfile->current_y == openfile->current->lineno - openfile->edittop->lineno);
|
assert(ISSET(SOFTWRAP) || openfile->current_y == openfile->current->lineno - openfile->edittop->lineno);
|
||||||
|
|
|
@ -2030,7 +2030,7 @@ void do_output(char *output, size_t output_len, bool allow_cntrls)
|
||||||
set_modified();
|
set_modified();
|
||||||
|
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
update_undo(ADD);
|
add_undo(ADD);
|
||||||
|
|
||||||
/* Note that current_x has not yet been incremented. */
|
/* Note that current_x has not yet been incremented. */
|
||||||
if (openfile->mark_set && openfile->current ==
|
if (openfile->mark_set && openfile->current ==
|
||||||
|
@ -2041,6 +2041,10 @@ void do_output(char *output, size_t output_len, bool allow_cntrls)
|
||||||
|
|
||||||
openfile->current_x += char_buf_len;
|
openfile->current_x += char_buf_len;
|
||||||
|
|
||||||
|
#ifndef NANO_TINY
|
||||||
|
update_undo(ADD);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef DISABLE_WRAPPING
|
#ifndef DISABLE_WRAPPING
|
||||||
/* If we're wrapping text, we need to call edit_refresh(). */
|
/* If we're wrapping text, we need to call edit_refresh(). */
|
||||||
if (!ISSET(NO_WRAP))
|
if (!ISSET(NO_WRAP))
|
||||||
|
|
|
@ -187,7 +187,7 @@ typedef enum {
|
||||||
} function_type;
|
} function_type;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ADD, DEL, REPLACE, SPLIT, UNSPLIT, CUT, UNCUT, ENTER, INSERT, OTHER
|
ADD, DEL, REPLACE, SPLIT, UNSPLIT, CUT, CUT_EOF, PASTE, ENTER, INSERT, OTHER
|
||||||
} undo_type;
|
} undo_type;
|
||||||
|
|
||||||
typedef struct color_pair {
|
typedef struct color_pair {
|
||||||
|
@ -324,7 +324,7 @@ typedef struct undo {
|
||||||
ssize_t lineno;
|
ssize_t lineno;
|
||||||
undo_type type;
|
undo_type type;
|
||||||
/* What type of undo this was. */
|
/* What type of undo this was. */
|
||||||
int begin;
|
size_t begin;
|
||||||
/* Where did this action begin or end. */
|
/* Where did this action begin or end. */
|
||||||
char *strdata;
|
char *strdata;
|
||||||
/* String type data we will use for copying the affected line back. */
|
/* String type data we will use for copying the affected line back. */
|
||||||
|
@ -344,7 +344,7 @@ typedef struct undo {
|
||||||
/* Was this a cut to end? */
|
/* Was this a cut to end? */
|
||||||
ssize_t mark_begin_lineno;
|
ssize_t mark_begin_lineno;
|
||||||
/* copy copy copy */
|
/* copy copy copy */
|
||||||
ssize_t mark_begin_x;
|
size_t mark_begin_x;
|
||||||
/* Another shadow variable. */
|
/* Another shadow variable. */
|
||||||
struct undo *next;
|
struct undo *next;
|
||||||
} undo;
|
} undo;
|
||||||
|
|
|
@ -604,6 +604,7 @@ void do_gotolinecolumn_void(void);
|
||||||
void do_gotopos(ssize_t pos_line, size_t pos_x, ssize_t pos_y, size_t
|
void do_gotopos(ssize_t pos_line, size_t pos_x, ssize_t pos_y, size_t
|
||||||
pos_pww);
|
pos_pww);
|
||||||
#endif
|
#endif
|
||||||
|
void goto_line_posx(ssize_t line, size_t pos_x);
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
bool find_bracket_match(bool reverse, const char *bracket_set);
|
bool find_bracket_match(bool reverse, const char *bracket_set);
|
||||||
void do_find_bracket(void);
|
void do_find_bracket(void);
|
||||||
|
|
14
src/search.c
14
src/search.c
|
@ -1008,6 +1008,20 @@ void do_replace(void)
|
||||||
search_replace_abort();
|
search_replace_abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Go to the specified line and x position. */
|
||||||
|
void goto_line_posx(ssize_t line, size_t pos_x)
|
||||||
|
{
|
||||||
|
for (openfile->current = openfile->fileage; openfile->current != openfile->filebot &&
|
||||||
|
openfile->current->next != NULL && line > 1; line--)
|
||||||
|
openfile->current = openfile->current->next;
|
||||||
|
|
||||||
|
openfile->current_x = pos_x;
|
||||||
|
openfile->placewewant = xplustabs();
|
||||||
|
|
||||||
|
edit_refresh_needed = TRUE;
|
||||||
|
edit_refresh();
|
||||||
|
}
|
||||||
|
|
||||||
/* Go to the specified line and column, or ask for them if interactive
|
/* Go to the specified line and column, or ask for them if interactive
|
||||||
* is TRUE. Save the x-coordinate and y-coordinate if save_pos is TRUE.
|
* is TRUE. Save the x-coordinate and y-coordinate if save_pos is TRUE.
|
||||||
* Update the screen afterwards if allow_update is TRUE. Note that both
|
* Update the screen afterwards if allow_update is TRUE. Note that both
|
||||||
|
|
205
src/text.c
205
src/text.c
|
@ -112,9 +112,8 @@ void do_delete(void)
|
||||||
edit_refresh_needed = TRUE;
|
edit_refresh_needed = TRUE;
|
||||||
|
|
||||||
openfile->current->data = charealloc(openfile->current->data,
|
openfile->current->data = charealloc(openfile->current->data,
|
||||||
openfile->current_x + strlen(foo->data) + 1);
|
strlen(openfile->current->data) + strlen(foo->data) + 1);
|
||||||
strcpy(openfile->current->data + openfile->current_x,
|
strcat(openfile->current->data, foo->data);
|
||||||
foo->data);
|
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
if (openfile->mark_set && openfile->mark_begin ==
|
if (openfile->mark_set && openfile->mark_begin ==
|
||||||
openfile->current->next) {
|
openfile->current->next) {
|
||||||
|
@ -359,6 +358,9 @@ void do_unindent(void)
|
||||||
do_indent(-tabsize);
|
do_indent(-tabsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define redo_paste undo_cut
|
||||||
|
#define undo_paste redo_cut
|
||||||
|
|
||||||
/* Undo a cut, or redo an uncut. */
|
/* Undo a cut, or redo an uncut. */
|
||||||
void undo_cut(undo *u)
|
void undo_cut(undo *u)
|
||||||
{
|
{
|
||||||
|
@ -373,10 +375,7 @@ void undo_cut(undo *u)
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Get to where we need to uncut from. */
|
/* Get to where we need to uncut from. */
|
||||||
if (u->mark_set && u->mark_begin_lineno < u->lineno)
|
goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
|
||||||
do_gotolinecolumn(u->mark_begin_lineno, u->mark_begin_x+1, FALSE, FALSE, FALSE, FALSE);
|
|
||||||
else
|
|
||||||
do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
|
|
||||||
|
|
||||||
copy_from_filestruct(cutbuffer);
|
copy_from_filestruct(cutbuffer);
|
||||||
free_filestruct(cutbuffer);
|
free_filestruct(cutbuffer);
|
||||||
|
@ -386,39 +385,26 @@ void undo_cut(undo *u)
|
||||||
/* Redo a cut, or undo an uncut. */
|
/* Redo a cut, or undo an uncut. */
|
||||||
void redo_cut(undo *u)
|
void redo_cut(undo *u)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
filestruct *t, *c;
|
|
||||||
|
|
||||||
/* If we cut the magicline, we may as well not crash. :/ */
|
/* If we cut the magicline, we may as well not crash. :/ */
|
||||||
if (!u->cutbuffer)
|
if (!u->cutbuffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
|
goto_line_posx(u->lineno, u->begin);
|
||||||
|
|
||||||
|
if (ISSET(NO_NEWLINES) && openfile->current->lineno != u->lineno) {
|
||||||
|
openfile->current_x = strlen(openfile->current->data);
|
||||||
|
openfile->placewewant = xplustabs();
|
||||||
|
}
|
||||||
|
|
||||||
openfile->mark_set = u->mark_set;
|
openfile->mark_set = u->mark_set;
|
||||||
if (cutbuffer)
|
if (cutbuffer)
|
||||||
free(cutbuffer);
|
free(cutbuffer);
|
||||||
cutbuffer = NULL;
|
cutbuffer = NULL;
|
||||||
|
|
||||||
/* Move ahead the same number of lines we had if a marked cut. */
|
openfile->mark_begin = fsfromline(u->mark_begin_lineno);
|
||||||
if (u->mark_set) {
|
|
||||||
for (i = 1, t = openfile->fileage; i != u->mark_begin_lineno; i++)
|
if (!ISSET(CUT_TO_END))
|
||||||
t = t->next;
|
|
||||||
openfile->mark_begin = t;
|
|
||||||
} else if (!u->to_end) {
|
|
||||||
/* Here we have a regular old potentially multi-line ^K cut.
|
|
||||||
* We'll need to trick nano into thinking it's a marked cut,
|
|
||||||
* to cut more than one line again. */
|
|
||||||
for (c = u->cutbuffer, t = openfile->current; c->next != NULL && t->next != NULL; ) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
fprintf(stderr, "Advancing, lineno = %lu, data = \"%s\"\n", (unsigned long) t->lineno, t->data);
|
|
||||||
#endif
|
|
||||||
c = c->next;
|
|
||||||
t = t->next;
|
|
||||||
}
|
|
||||||
openfile->mark_begin = t;
|
|
||||||
openfile->mark_begin_x = 0;
|
|
||||||
openfile->mark_set = TRUE;
|
openfile->mark_set = TRUE;
|
||||||
}
|
|
||||||
|
|
||||||
openfile->mark_begin_x = u->mark_begin_x;
|
openfile->mark_begin_x = u->mark_begin_x;
|
||||||
do_cut_text(FALSE, u->to_end, TRUE);
|
do_cut_text(FALSE, u->to_end, TRUE);
|
||||||
|
@ -431,8 +417,9 @@ void redo_cut(undo *u)
|
||||||
/* Undo the last thing(s) we did. */
|
/* Undo the last thing(s) we did. */
|
||||||
void do_undo(void)
|
void do_undo(void)
|
||||||
{
|
{
|
||||||
|
bool gotolinecolumn = FALSE;
|
||||||
undo *u = openfile->current_undo;
|
undo *u = openfile->current_undo;
|
||||||
filestruct *f = openfile->current, *t;
|
filestruct *t = 0;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
char *undidmsg, *data;
|
char *undidmsg, *data;
|
||||||
filestruct *oldcutbuffer = cutbuffer, *oldcutbottom = cutbottom;
|
filestruct *oldcutbuffer = cutbuffer, *oldcutbottom = cutbottom;
|
||||||
|
@ -442,14 +429,9 @@ void do_undo(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u->lineno <= f->lineno)
|
filestruct *f = fsfromline(u->mark_begin_lineno);
|
||||||
for (; f->prev != NULL && f->lineno != u->lineno; f = f->prev)
|
if (!f) {
|
||||||
;
|
statusbar(_("Internal error: can't match line %d. Please save your work."), u->mark_begin_lineno);
|
||||||
else
|
|
||||||
for (; f->next != NULL && f->lineno != u->lineno; f = f->next)
|
|
||||||
;
|
|
||||||
if (f->lineno != u->lineno) {
|
|
||||||
statusbar(_("Internal error: can't match line %d. Please save your work."), u->lineno);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -467,6 +449,7 @@ void do_undo(void)
|
||||||
strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
|
strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
|
||||||
free(f->data);
|
free(f->data);
|
||||||
f->data = data;
|
f->data = data;
|
||||||
|
goto_line_posx(u->lineno, u->begin);
|
||||||
break;
|
break;
|
||||||
case DEL:
|
case DEL:
|
||||||
undidmsg = _("text delete");
|
undidmsg = _("text delete");
|
||||||
|
@ -480,6 +463,7 @@ void do_undo(void)
|
||||||
f->data = data;
|
f->data = data;
|
||||||
if (u->xflags == UNdel_backspace)
|
if (u->xflags == UNdel_backspace)
|
||||||
openfile->current_x += strlen(u->strdata);
|
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:
|
||||||
|
@ -494,26 +478,28 @@ void do_undo(void)
|
||||||
delete_node(foo);
|
delete_node(foo);
|
||||||
}
|
}
|
||||||
renumber(f);
|
renumber(f);
|
||||||
|
gotolinecolumn = TRUE;
|
||||||
break;
|
break;
|
||||||
#endif /* !DISABLE_WRAPPING */
|
#endif /* !DISABLE_WRAPPING */
|
||||||
case UNSPLIT:
|
case UNSPLIT:
|
||||||
undidmsg = _("line join");
|
undidmsg = _("line join");
|
||||||
t = make_new_node(f);
|
t = make_new_node(f);
|
||||||
t->data = mallocstrcpy(NULL, u->strdata);
|
t->data = mallocstrcpy(NULL, u->strdata);
|
||||||
data = mallocstrncpy(NULL, f->data, u->begin);
|
data = mallocstrncpy(NULL, f->data, u->begin + 1);
|
||||||
data[u->begin] = '\0';
|
data[u->begin] = '\0';
|
||||||
free(f->data);
|
free(f->data);
|
||||||
f->data = data;
|
f->data = data;
|
||||||
splice_node(f, t, f->next);
|
splice_node(f, t, f->next);
|
||||||
renumber(f);
|
gotolinecolumn = TRUE;
|
||||||
break;
|
break;
|
||||||
|
case CUT_EOF:
|
||||||
case CUT:
|
case CUT:
|
||||||
undidmsg = _("text cut");
|
undidmsg = _("text cut");
|
||||||
undo_cut(u);
|
undo_cut(u);
|
||||||
break;
|
break;
|
||||||
case UNCUT:
|
case PASTE:
|
||||||
undidmsg = _("text uncut");
|
undidmsg = _("text uncut");
|
||||||
redo_cut(u);
|
undo_paste(u);
|
||||||
break;
|
break;
|
||||||
case ENTER:
|
case ENTER:
|
||||||
undidmsg = _("line break");
|
undidmsg = _("line break");
|
||||||
|
@ -524,6 +510,7 @@ void do_undo(void)
|
||||||
unlink_node(foo);
|
unlink_node(foo);
|
||||||
delete_node(foo);
|
delete_node(foo);
|
||||||
}
|
}
|
||||||
|
goto_line_posx(u->lineno, u->begin);
|
||||||
break;
|
break;
|
||||||
case INSERT:
|
case INSERT:
|
||||||
undidmsg = _("text insert");
|
undidmsg = _("text insert");
|
||||||
|
@ -535,7 +522,7 @@ void do_undo(void)
|
||||||
openfile->mark_begin = fsfromline(u->lineno + u->mark_begin_lineno - 1);
|
openfile->mark_begin = fsfromline(u->lineno + u->mark_begin_lineno - 1);
|
||||||
openfile->mark_begin_x = 0;
|
openfile->mark_begin_x = 0;
|
||||||
openfile->mark_set = TRUE;
|
openfile->mark_set = TRUE;
|
||||||
do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
|
goto_line_posx(u->lineno, u->begin);
|
||||||
cut_marked();
|
cut_marked();
|
||||||
u->cutbuffer = cutbuffer;
|
u->cutbuffer = cutbuffer;
|
||||||
u->cutbottom = cutbottom;
|
u->cutbottom = cutbottom;
|
||||||
|
@ -545,6 +532,7 @@ void do_undo(void)
|
||||||
break;
|
break;
|
||||||
case REPLACE:
|
case REPLACE:
|
||||||
undidmsg = _("text replace");
|
undidmsg = _("text replace");
|
||||||
|
goto_line_posx(u->lineno, u->begin);
|
||||||
data = u->strdata;
|
data = u->strdata;
|
||||||
u->strdata = f->data;
|
u->strdata = f->data;
|
||||||
f->data = data;
|
f->data = data;
|
||||||
|
@ -555,17 +543,19 @@ void do_undo(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
renumber(f);
|
renumber(f);
|
||||||
|
if (gotolinecolumn)
|
||||||
do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE);
|
do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE);
|
||||||
statusbar(_("Undid action (%s)"), undidmsg);
|
statusbar(_("Undid action (%s)"), undidmsg);
|
||||||
openfile->current_undo = openfile->current_undo->next;
|
openfile->current_undo = openfile->current_undo->next;
|
||||||
openfile->last_action = OTHER;
|
openfile->last_action = OTHER;
|
||||||
|
set_modified();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Redo the last thing(s) we undid. */
|
/* Redo the last thing(s) we undid. */
|
||||||
void do_redo(void)
|
void do_redo(void)
|
||||||
{
|
{
|
||||||
|
bool gotolinecolumn = FALSE;
|
||||||
undo *u = openfile->undotop;
|
undo *u = openfile->undotop;
|
||||||
filestruct *f = openfile->current;
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
char *undidmsg, *data;
|
char *undidmsg, *data;
|
||||||
|
|
||||||
|
@ -580,14 +570,9 @@ void do_redo(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u->lineno <= f->lineno)
|
filestruct *f = fsfromline(u->mark_begin_lineno);
|
||||||
for (; f->prev != NULL && f->lineno != u->lineno; f = f->prev)
|
if (!f) {
|
||||||
;
|
statusbar(_("Internal error: can't match line %d. Please save your work."), u->mark_begin_lineno);
|
||||||
else
|
|
||||||
for (; f->next != NULL && f->lineno != u->lineno; f = f->next)
|
|
||||||
;
|
|
||||||
if (f->lineno != u->lineno) {
|
|
||||||
statusbar(_("Internal error: can't match line %d. Please save your work."), u->lineno);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -605,6 +590,7 @@ void do_redo(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;
|
||||||
|
goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
|
||||||
break;
|
break;
|
||||||
case DEL:
|
case DEL:
|
||||||
undidmsg = _("text delete");
|
undidmsg = _("text delete");
|
||||||
|
@ -614,10 +600,13 @@ void do_redo(void)
|
||||||
strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
|
strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
|
||||||
free(f->data);
|
free(f->data);
|
||||||
f->data = data;
|
f->data = data;
|
||||||
|
openfile->current_x = u->begin;
|
||||||
|
openfile->placewewant = xplustabs();
|
||||||
|
goto_line_posx(u->lineno, u->begin);
|
||||||
break;
|
break;
|
||||||
case ENTER:
|
case ENTER:
|
||||||
undidmsg = _("line break");
|
undidmsg = _("line break");
|
||||||
do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
|
goto_line_posx(u->lineno, u->begin);
|
||||||
do_enter(TRUE);
|
do_enter(TRUE);
|
||||||
break;
|
break;
|
||||||
#ifndef DISABLE_WRAPPING
|
#ifndef DISABLE_WRAPPING
|
||||||
|
@ -627,53 +616,55 @@ void do_redo(void)
|
||||||
prepend_wrap = TRUE;
|
prepend_wrap = TRUE;
|
||||||
do_wrap(f, TRUE);
|
do_wrap(f, TRUE);
|
||||||
renumber(f);
|
renumber(f);
|
||||||
|
gotolinecolumn = TRUE;
|
||||||
break;
|
break;
|
||||||
#endif /* !DISABLE_WRAPPING */
|
#endif /* !DISABLE_WRAPPING */
|
||||||
case UNSPLIT:
|
case UNSPLIT:
|
||||||
undidmsg = _("line join");
|
undidmsg = _("line join");
|
||||||
len = strlen(f->data) + strlen(u->strdata + 1);
|
len = strlen(f->data) + strlen(u->strdata) + 1;
|
||||||
data = charalloc(len);
|
f->data = charealloc(f->data, len);
|
||||||
strcpy(data, f->data);
|
strcat(f->data, u->strdata);
|
||||||
strcat(data, u->strdata);
|
|
||||||
free(f->data);
|
|
||||||
f->data = data;
|
|
||||||
if (f->next != NULL) {
|
if (f->next != NULL) {
|
||||||
filestruct *tmp = f->next;
|
filestruct *tmp = f->next;
|
||||||
unlink_node(tmp);
|
unlink_node(tmp);
|
||||||
delete_node(tmp);
|
delete_node(tmp);
|
||||||
}
|
}
|
||||||
renumber(f);
|
renumber(f);
|
||||||
|
gotolinecolumn = TRUE;
|
||||||
break;
|
break;
|
||||||
|
case CUT_EOF:
|
||||||
case CUT:
|
case CUT:
|
||||||
undidmsg = _("text cut");
|
undidmsg = _("text cut");
|
||||||
redo_cut(u);
|
redo_cut(u);
|
||||||
break;
|
break;
|
||||||
case UNCUT:
|
case PASTE:
|
||||||
undidmsg = _("text uncut");
|
undidmsg = _("text uncut");
|
||||||
undo_cut(u);
|
redo_paste(u);
|
||||||
break;
|
break;
|
||||||
case REPLACE:
|
case REPLACE:
|
||||||
undidmsg = _("text replace");
|
undidmsg = _("text replace");
|
||||||
data = u->strdata;
|
data = u->strdata;
|
||||||
u->strdata = f->data;
|
u->strdata = f->data;
|
||||||
f->data = data;
|
f->data = data;
|
||||||
|
goto_line_posx(u->lineno, u->begin);
|
||||||
break;
|
break;
|
||||||
case INSERT:
|
case INSERT:
|
||||||
undidmsg = _("text insert");
|
undidmsg = _("text insert");
|
||||||
do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
|
goto_line_posx(u->lineno, u->begin);
|
||||||
copy_from_filestruct(u->cutbuffer);
|
copy_from_filestruct(u->cutbuffer);
|
||||||
openfile->placewewant = xplustabs();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
undidmsg = _("Internal error: unknown type. Please save your work.");
|
undidmsg = _("Internal error: unknown type. Please save your work.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gotolinecolumn)
|
||||||
do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE);
|
do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE);
|
||||||
statusbar(_("Redid action (%s)"), undidmsg);
|
statusbar(_("Redid action (%s)"), undidmsg);
|
||||||
|
|
||||||
openfile->current_undo = u;
|
openfile->current_undo = u;
|
||||||
openfile->last_action = OTHER;
|
openfile->last_action = OTHER;
|
||||||
|
set_modified();
|
||||||
}
|
}
|
||||||
#endif /* !NANO_TINY */
|
#endif /* !NANO_TINY */
|
||||||
|
|
||||||
|
@ -841,7 +832,6 @@ void add_undo(undo_type current_action)
|
||||||
undo *u;
|
undo *u;
|
||||||
char *data;
|
char *data;
|
||||||
openfilestruct *fs = openfile;
|
openfilestruct *fs = openfile;
|
||||||
static undo *last_cutu = NULL;
|
|
||||||
/* Last thing we cut to set up the undo for uncut. */
|
/* Last thing we cut to set up the undo for uncut. */
|
||||||
ssize_t wrap_loc;
|
ssize_t wrap_loc;
|
||||||
/* For calculating split beginning. */
|
/* For calculating split beginning. */
|
||||||
|
@ -852,8 +842,9 @@ void add_undo(undo_type current_action)
|
||||||
/* Ugh, if we were called while cutting not-to-end, non-marked, and
|
/* Ugh, if we were called while cutting not-to-end, non-marked, and
|
||||||
* on the same lineno, we need to abort here. */
|
* on the same lineno, we need to abort here. */
|
||||||
u = fs->current_undo;
|
u = fs->current_undo;
|
||||||
if (current_action == CUT && u && u->type == CUT
|
if (u && u->mark_begin_lineno == fs->current->lineno &&
|
||||||
&& !u->mark_set && u->lineno == fs->current->lineno)
|
((current_action == CUT && u->type == CUT && !u->mark_set) ||
|
||||||
|
(current_action == ADD && u->type == ADD && u->mark_begin_x == fs->current_x)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Blow away the old undo stack if we are starting from the middle. */
|
/* Blow away the old undo stack if we are starting from the middle. */
|
||||||
|
@ -880,8 +871,8 @@ void add_undo(undo_type current_action)
|
||||||
u->cutbuffer = NULL;
|
u->cutbuffer = NULL;
|
||||||
u->cutbottom = NULL;
|
u->cutbottom = NULL;
|
||||||
u->mark_set = 0;
|
u->mark_set = 0;
|
||||||
u->mark_begin_lineno = 0;
|
u->mark_begin_lineno = fs->current->lineno;
|
||||||
u->mark_begin_x = 0;
|
u->mark_begin_x = fs->current_x;
|
||||||
u->xflags = 0;
|
u->xflags = 0;
|
||||||
u->to_end = FALSE;
|
u->to_end = FALSE;
|
||||||
|
|
||||||
|
@ -890,8 +881,7 @@ void add_undo(undo_type current_action)
|
||||||
* 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 = charalloc(2);
|
||||||
data[0] = fs->current->data[fs->current_x];
|
data[0] = '\0';
|
||||||
data[1] = '\0';
|
|
||||||
u->strdata = data;
|
u->strdata = data;
|
||||||
break;
|
break;
|
||||||
case DEL:
|
case DEL:
|
||||||
|
@ -929,21 +919,43 @@ void add_undo(undo_type current_action)
|
||||||
data = mallocstrcpy(NULL, fs->current->data);
|
data = mallocstrcpy(NULL, fs->current->data);
|
||||||
u->strdata = data;
|
u->strdata = data;
|
||||||
break;
|
break;
|
||||||
|
case CUT_EOF:
|
||||||
|
u->to_end = TRUE;
|
||||||
case CUT:
|
case CUT:
|
||||||
u->mark_set = openfile->mark_set;
|
u->mark_set = openfile->mark_set;
|
||||||
if (u->mark_set) {
|
if (u->mark_set) {
|
||||||
u->mark_begin_lineno = openfile->mark_begin->lineno;
|
u->mark_begin_lineno = openfile->mark_begin->lineno;
|
||||||
u->mark_begin_x = openfile->mark_begin_x;
|
u->mark_begin_x = openfile->mark_begin_x;
|
||||||
}
|
}
|
||||||
u->to_end = (ISSET(CUT_TO_END)) ? TRUE : FALSE;
|
else if (!ISSET(CUT_TO_END) && !u->to_end) {
|
||||||
last_cutu = u;
|
/* The entire line is being cut regardless of the cursor position. */
|
||||||
|
u->begin = 0;
|
||||||
|
u->mark_begin_x = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case UNCUT:
|
case PASTE:
|
||||||
if (!last_cutu)
|
if (!cutbuffer)
|
||||||
statusbar(_("Internal error: cannot set up uncut. Please save your work."));
|
statusbar(_("Internal error: cannot set up uncut. Please save your work."));
|
||||||
else if (last_cutu->type == CUT) {
|
else {
|
||||||
u->cutbuffer = last_cutu->cutbuffer;
|
if (u->cutbuffer)
|
||||||
u->cutbottom = last_cutu->cutbottom;
|
free(u->cutbuffer);
|
||||||
|
u->cutbuffer = copy_filestruct(cutbuffer);
|
||||||
|
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;
|
break;
|
||||||
case ENTER:
|
case ENTER:
|
||||||
|
@ -1004,12 +1016,14 @@ void update_undo(undo_type action)
|
||||||
#endif
|
#endif
|
||||||
len = strlen(u->strdata) + 2;
|
len = strlen(u->strdata) + 2;
|
||||||
data = (char *) nrealloc((void *) u->strdata, len * sizeof(char *));
|
data = (char *) nrealloc((void *) u->strdata, len * sizeof(char *));
|
||||||
data[len-2] = fs->current->data[fs->current_x];
|
data[len-2] = fs->current->data[fs->current_x - 1];
|
||||||
data[len-1] = '\0';
|
data[len-1] = '\0';
|
||||||
u->strdata = (char *) data;
|
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_x = fs->current_x;
|
||||||
break;
|
break;
|
||||||
case DEL:
|
case DEL:
|
||||||
len = strlen(u->strdata) + 2;
|
len = strlen(u->strdata) + 2;
|
||||||
|
@ -1051,18 +1065,37 @@ 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:
|
case CUT:
|
||||||
if (!cutbuffer)
|
if (!cutbuffer)
|
||||||
break;
|
break;
|
||||||
if (u->cutbuffer)
|
if (u->cutbuffer)
|
||||||
free(u->cutbuffer);
|
free(u->cutbuffer);
|
||||||
u->cutbuffer = copy_filestruct(cutbuffer);
|
u->cutbuffer = copy_filestruct(cutbuffer);
|
||||||
|
if (u->mark_set) {
|
||||||
|
/* If the "marking" operation was from right-->left or
|
||||||
|
* bottom-->top, then swap the mark points. */
|
||||||
|
if ((u->lineno == u->mark_begin_lineno && u->begin < u->mark_begin_x)
|
||||||
|
|| u->lineno < u->mark_begin_lineno) {
|
||||||
|
size_t x_loc = u->begin;
|
||||||
|
u->begin = u->mark_begin_x;
|
||||||
|
u->mark_begin_x = x_loc;
|
||||||
|
|
||||||
|
ssize_t line = u->lineno;
|
||||||
|
u->lineno = u->mark_begin_lineno;
|
||||||
|
u->mark_begin_lineno = line;
|
||||||
|
}
|
||||||
|
} else if (!ISSET(CUT_TO_END)) {
|
||||||
/* Compute cutbottom for the uncut using our copy. */
|
/* Compute cutbottom for the uncut using our copy. */
|
||||||
for (u->cutbottom = u->cutbuffer; u->cutbottom->next != NULL; u->cutbottom = u->cutbottom->next)
|
u->cutbottom = u->cutbuffer;
|
||||||
;
|
while (u->cutbottom->next != NULL)
|
||||||
|
u->cutbottom = u->cutbottom->next;
|
||||||
|
if (!u->to_end)
|
||||||
|
u->lineno++;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case REPLACE:
|
case REPLACE:
|
||||||
case UNCUT:
|
case PASTE:
|
||||||
add_undo(action);
|
add_undo(action);
|
||||||
break;
|
break;
|
||||||
case INSERT:
|
case INSERT:
|
||||||
|
@ -1085,13 +1118,7 @@ void update_undo(undo_type action)
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf(stderr, "Done in update_undo (type was %d)\n", action);
|
fprintf(stderr, "Done in update_undo (type was %d)\n", action);
|
||||||
#endif
|
#endif
|
||||||
if (fs->last_action != action) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
fprintf(stderr, "Starting add_undo for new action as it does not match last_action\n");
|
|
||||||
#endif
|
|
||||||
add_undo(action);
|
|
||||||
}
|
|
||||||
fs->last_action = action;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !NANO_TINY */
|
#endif /* !NANO_TINY */
|
||||||
|
|
|
@ -476,7 +476,10 @@ size_t get_page_start(size_t column)
|
||||||
* current_x. */
|
* current_x. */
|
||||||
size_t xplustabs(void)
|
size_t xplustabs(void)
|
||||||
{
|
{
|
||||||
|
if (openfile->current)
|
||||||
return strnlenpt(openfile->current->data, openfile->current_x);
|
return strnlenpt(openfile->current->data, openfile->current_x);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the index in s of the character displayed at the given column,
|
/* Return the index in s of the character displayed at the given column,
|
||||||
|
|
Loading…
Reference in New Issue