Add beginning undo feature, since I want to start fixing bugs from savannah and don't want to manager another checking, and the code basically works for some operations.
git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@4271 35c25a1d-7b9e-4130-9fde-d3aeb78583b8master
parent
1347f22c95
commit
07fcc4c973
|
@ -1,7 +1,12 @@
|
||||||
|
2008-07-09 Chris Allegretta <chrisa@asty.org>
|
||||||
|
* nano.c/nano.h/global.c/text.c: New generalized undo code, currently
|
||||||
|
just works for adding and deleting text and splitting and unsplitting lines.
|
||||||
|
|
||||||
2008-06-29 Chris Allegretta <chrisa@asty.org>
|
2008-06-29 Chris Allegretta <chrisa@asty.org>
|
||||||
* global.c: Fix for not having search history when --disable-justify is used
|
* global.c: Fix for not having search history when --disable-justify is used
|
||||||
(Savannah bug 23733)
|
(Savannah bug 23733)
|
||||||
|
|
||||||
|
|
||||||
GNU nano 2.1.2 - 2008.06.24
|
GNU nano 2.1.2 - 2008.06.24
|
||||||
2008-06-24 Chris Allegretta <chrisa@asty.org>
|
2008-06-24 Chris Allegretta <chrisa@asty.org>
|
||||||
* rcfile.c: Added function check_bad_binding() to look for sequences which
|
* rcfile.c: Added function check_bad_binding() to look for sequences which
|
||||||
|
|
|
@ -75,6 +75,8 @@ void initialize_buffer(void)
|
||||||
openfile->fmt = NIX_FILE;
|
openfile->fmt = NIX_FILE;
|
||||||
|
|
||||||
openfile->current_stat = NULL;
|
openfile->current_stat = NULL;
|
||||||
|
openfile->undotop = NULL;
|
||||||
|
openfile->current_undo = NULL;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_COLOR
|
#ifdef ENABLE_COLOR
|
||||||
openfile->colorstrings = NULL;
|
openfile->colorstrings = NULL;
|
||||||
|
|
36
src/global.c
36
src/global.c
|
@ -1,5 +1,4 @@
|
||||||
/* $Id$
|
/* $Id$ */
|
||||||
*/
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* global.c *
|
* global.c *
|
||||||
* *
|
* *
|
||||||
|
@ -150,11 +149,6 @@ const shortcut *currshortcut;
|
||||||
int currmenu;
|
int currmenu;
|
||||||
/* The currently loaded menu */
|
/* The currently loaded menu */
|
||||||
|
|
||||||
#ifndef NANO_TINY
|
|
||||||
toggle *toggles = NULL;
|
|
||||||
/* The global toggle list. */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sc *sclist = NULL;
|
sc *sclist = NULL;
|
||||||
/* New shortcut key struct */
|
/* New shortcut key struct */
|
||||||
subnfunc *allfuncs = NULL;
|
subnfunc *allfuncs = NULL;
|
||||||
|
@ -486,6 +480,8 @@ void shortcut_init(bool unjustify)
|
||||||
const char *refresh_msg = N_("Refresh");
|
const char *refresh_msg = N_("Refresh");
|
||||||
const char *insert_file_msg = N_("Insert File");
|
const char *insert_file_msg = N_("Insert File");
|
||||||
const char *go_to_line_msg = N_("Go To Line");
|
const char *go_to_line_msg = N_("Go To Line");
|
||||||
|
const char *prev_undo_msg = N_("Prev Undo");
|
||||||
|
const char *next_undo_msg = N_("Next Undo");
|
||||||
|
|
||||||
#ifndef DISABLE_HELP
|
#ifndef DISABLE_HELP
|
||||||
/* TRANSLATORS: The next long series of strings are shortcut descriptions;
|
/* TRANSLATORS: The next long series of strings are shortcut descriptions;
|
||||||
|
@ -528,6 +524,8 @@ void shortcut_init(bool unjustify)
|
||||||
N_("Copy the current line and store it in the cutbuffer");
|
N_("Copy the current line and store it in the cutbuffer");
|
||||||
const char *nano_indent_msg = N_("Indent the current line");
|
const char *nano_indent_msg = N_("Indent the current line");
|
||||||
const char *nano_unindent_msg = N_("Unindent the current line");
|
const char *nano_unindent_msg = N_("Unindent the current line");
|
||||||
|
const char *nano_undo_msg = N_("Undo the last operation");
|
||||||
|
const char *nano_redo_msg = N_("Redo the last undone operation");
|
||||||
#endif
|
#endif
|
||||||
const char *nano_forward_msg = N_("Go forward one character");
|
const char *nano_forward_msg = N_("Go forward one character");
|
||||||
const char *nano_back_msg = N_("Go back one character");
|
const char *nano_back_msg = N_("Go back one character");
|
||||||
|
@ -602,6 +600,10 @@ void shortcut_init(bool unjustify)
|
||||||
N_("Recall the previous search/replace string");
|
N_("Recall the previous search/replace string");
|
||||||
const char *nano_next_history_msg =
|
const char *nano_next_history_msg =
|
||||||
N_("Recall the next search/replace string");
|
N_("Recall the next search/replace string");
|
||||||
|
const char *nano_prev_undo_msg =
|
||||||
|
N_("Recall the previous undo action");
|
||||||
|
const char *nano_next_undo_msg =
|
||||||
|
N_("Recall the next undo action");
|
||||||
#endif
|
#endif
|
||||||
#ifndef DISABLE_BROWSER
|
#ifndef DISABLE_BROWSER
|
||||||
const char *nano_tofiles_msg = N_("Go to file browser");
|
const char *nano_tofiles_msg = N_("Go to file browser");
|
||||||
|
@ -698,6 +700,7 @@ void shortcut_init(bool unjustify)
|
||||||
add_to_funcs(do_page_down, MMAIN|MHELP,
|
add_to_funcs(do_page_down, MMAIN|MHELP,
|
||||||
next_page_msg, IFSCHELP(nano_nextpage_msg), TRUE, VIEW);
|
next_page_msg, IFSCHELP(nano_nextpage_msg), TRUE, VIEW);
|
||||||
|
|
||||||
|
|
||||||
/* TRANSLATORS: Try to keep this at most 10 characters. */
|
/* TRANSLATORS: Try to keep this at most 10 characters. */
|
||||||
add_to_funcs(do_cut_text_void, MMAIN, N_("Cut Text"), IFSCHELP(nano_cut_msg),
|
add_to_funcs(do_cut_text_void, MMAIN, N_("Cut Text"), IFSCHELP(nano_cut_msg),
|
||||||
FALSE, NOVIEW);
|
FALSE, NOVIEW);
|
||||||
|
@ -771,7 +774,13 @@ void shortcut_init(bool unjustify)
|
||||||
nano_indent_msg, FALSE, NOVIEW);
|
nano_indent_msg, FALSE, NOVIEW);
|
||||||
|
|
||||||
add_to_funcs(do_unindent, MMAIN, N_("Unindent Text"),
|
add_to_funcs(do_unindent, MMAIN, N_("Unindent Text"),
|
||||||
nano_unindent_msg, TRUE, NOVIEW);
|
nano_unindent_msg, FALSE, NOVIEW);
|
||||||
|
|
||||||
|
add_to_funcs(do_undo, MMAIN, N_("Undo"),
|
||||||
|
nano_undo_msg, FALSE, NOVIEW);
|
||||||
|
|
||||||
|
add_to_funcs(do_redo, MMAIN, N_("Redo"),
|
||||||
|
nano_redo_msg, TRUE, NOVIEW);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1055,6 +1064,8 @@ void shortcut_init(bool unjustify)
|
||||||
add_to_sclist(MMAIN, "M-6", do_copy_text, 0, TRUE);
|
add_to_sclist(MMAIN, "M-6", do_copy_text, 0, TRUE);
|
||||||
add_to_sclist(MMAIN, "M-}", do_indent_void, 0, TRUE);
|
add_to_sclist(MMAIN, "M-}", do_indent_void, 0, TRUE);
|
||||||
add_to_sclist(MMAIN, "M-{", do_unindent, 0, TRUE);
|
add_to_sclist(MMAIN, "M-{", do_unindent, 0, TRUE);
|
||||||
|
add_to_sclist(MMAIN, "M-U", do_undo, 0, TRUE);
|
||||||
|
add_to_sclist(MMAIN, "M-E", do_redo, 0, TRUE);
|
||||||
add_to_sclist(MALL, "^F", do_right, 0, TRUE);
|
add_to_sclist(MALL, "^F", do_right, 0, TRUE);
|
||||||
add_to_sclist(MALL, "^B", do_left, 0, TRUE);
|
add_to_sclist(MALL, "^B", do_left, 0, TRUE);
|
||||||
add_to_sclist(MMAIN, "^Space", do_next_word_void, 0, TRUE);
|
add_to_sclist(MMAIN, "^Space", do_next_word_void, 0, TRUE);
|
||||||
|
@ -1576,15 +1587,6 @@ void thanks_for_all_the_fish(void)
|
||||||
#ifndef DISABLE_JUSTIFY
|
#ifndef DISABLE_JUSTIFY
|
||||||
if (jusbuffer != NULL)
|
if (jusbuffer != NULL)
|
||||||
free_filestruct(jusbuffer);
|
free_filestruct(jusbuffer);
|
||||||
#endif
|
|
||||||
#ifndef NANO_TINY
|
|
||||||
/* Free the memory associated with each toggle. */
|
|
||||||
while (toggles != NULL) {
|
|
||||||
toggle *t = toggles;
|
|
||||||
|
|
||||||
toggles = toggles->next;
|
|
||||||
free(t);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
/* Free the memory associated with each open file buffer. */
|
/* Free the memory associated with each open file buffer. */
|
||||||
if (openfile != NULL)
|
if (openfile != NULL)
|
||||||
|
|
|
@ -502,6 +502,7 @@ openfilestruct *make_new_opennode(void)
|
||||||
newnode->filebot = NULL;
|
newnode->filebot = NULL;
|
||||||
newnode->edittop = NULL;
|
newnode->edittop = NULL;
|
||||||
newnode->current = NULL;
|
newnode->current = NULL;
|
||||||
|
newnode->last_action = OTHER;
|
||||||
|
|
||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
@ -1642,6 +1643,9 @@ 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, openfile);
|
||||||
|
|
||||||
|
|
||||||
/* 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 ==
|
||||||
openfile->mark_begin && openfile->current_x <
|
openfile->mark_begin && openfile->current_x <
|
||||||
|
|
43
src/nano.h
43
src/nano.h
|
@ -169,6 +169,10 @@ typedef enum {
|
||||||
CONTROL, META, FKEY, RAW
|
CONTROL, META, FKEY, RAW
|
||||||
} function_type;
|
} function_type;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ADD, DEL, REPLACE, SPLIT, UNSPLIT, CUT, UNCUT, OTHER
|
||||||
|
} undo_type;
|
||||||
|
|
||||||
/* Structure types. */
|
/* Structure types. */
|
||||||
typedef struct filestruct {
|
typedef struct filestruct {
|
||||||
char *data;
|
char *data;
|
||||||
|
@ -245,6 +249,21 @@ typedef struct syntaxtype {
|
||||||
} syntaxtype;
|
} syntaxtype;
|
||||||
#endif /* ENABLE_COLOR */
|
#endif /* ENABLE_COLOR */
|
||||||
|
|
||||||
|
#ifndef NANO_TINY
|
||||||
|
typedef struct undo {
|
||||||
|
undo_type type;
|
||||||
|
filestruct *fs;
|
||||||
|
int begin;
|
||||||
|
/* Where did this action begin or end */
|
||||||
|
char *strdata;
|
||||||
|
/* Generic pointer for data regardless of what type it is */
|
||||||
|
filestruct *fsdata;
|
||||||
|
/* Generic pointer for data regardless of what type it is */
|
||||||
|
struct undo *next;
|
||||||
|
ssize_t lineno;
|
||||||
|
} undo;
|
||||||
|
#endif /* NANO_TINY */
|
||||||
|
|
||||||
typedef struct openfilestruct {
|
typedef struct openfilestruct {
|
||||||
char *filename;
|
char *filename;
|
||||||
/* The current file's name. */
|
/* The current file's name. */
|
||||||
|
@ -278,6 +297,11 @@ typedef struct openfilestruct {
|
||||||
/* The current file's format. */
|
/* The current file's format. */
|
||||||
struct stat *current_stat;
|
struct stat *current_stat;
|
||||||
/* The current file's stat. */
|
/* The current file's stat. */
|
||||||
|
undo *undotop;
|
||||||
|
/* Top of the undo list */
|
||||||
|
undo *current_undo;
|
||||||
|
/* The current (i.e. n ext) level of undo */
|
||||||
|
undo_type last_action;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_COLOR
|
#ifdef ENABLE_COLOR
|
||||||
colortype *colorstrings;
|
colortype *colorstrings;
|
||||||
|
@ -318,25 +342,6 @@ typedef struct shortcut {
|
||||||
/* Next shortcut. */
|
/* Next shortcut. */
|
||||||
} shortcut;
|
} shortcut;
|
||||||
|
|
||||||
#ifndef NANO_TINY
|
|
||||||
typedef struct toggle {
|
|
||||||
int val;
|
|
||||||
/* The sequence to toggle the key. We should only need one. */
|
|
||||||
const char *desc;
|
|
||||||
/* The description of the toggle, e.g. "Cut to end"; we'll
|
|
||||||
* append Enabled or Disabled to it. */
|
|
||||||
#ifndef DISABLE_HELP
|
|
||||||
bool blank_after;
|
|
||||||
/* Whether there should be a blank line after the description of
|
|
||||||
* the toggle. */
|
|
||||||
#endif
|
|
||||||
long flag;
|
|
||||||
/* Which flag actually gets toggled. */
|
|
||||||
struct toggle *next;
|
|
||||||
/* Next toggle. */
|
|
||||||
} toggle;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ENABLE_NANORC
|
#ifdef ENABLE_NANORC
|
||||||
typedef struct rcoption {
|
typedef struct rcoption {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
11
src/proto.h
11
src/proto.h
|
@ -60,6 +60,7 @@ extern char *matchbrackets;
|
||||||
#if !defined(NANO_TINY) && defined(ENABLE_NANORC)
|
#if !defined(NANO_TINY) && defined(ENABLE_NANORC)
|
||||||
extern char *whitespace;
|
extern char *whitespace;
|
||||||
extern int whitespace_len[2];
|
extern int whitespace_len[2];
|
||||||
|
extern undo_type last_action;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DISABLE_JUSTIFY
|
#ifndef DISABLE_JUSTIFY
|
||||||
|
@ -100,9 +101,6 @@ extern char *syntaxstr;
|
||||||
|
|
||||||
extern const shortcut *currshortcut;
|
extern const shortcut *currshortcut;
|
||||||
extern int currmenu;
|
extern int currmenu;
|
||||||
#ifndef NANO_TINY
|
|
||||||
extern toggle *toggles;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
extern filestruct *search_history;
|
extern filestruct *search_history;
|
||||||
|
@ -619,6 +617,8 @@ void do_tab(void);
|
||||||
void do_indent(ssize_t cols);
|
void do_indent(ssize_t cols);
|
||||||
void do_indent_void(void);
|
void do_indent_void(void);
|
||||||
void do_unindent(void);
|
void do_unindent(void);
|
||||||
|
void do_undo(void);
|
||||||
|
void do_redo(void);
|
||||||
#endif
|
#endif
|
||||||
void do_enter(void);
|
void do_enter(void);
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
|
@ -706,6 +706,8 @@ void new_magicline(void);
|
||||||
void remove_magicline(void);
|
void remove_magicline(void);
|
||||||
void mark_order(const filestruct **top, size_t *top_x, const filestruct
|
void mark_order(const filestruct **top, size_t *top_x, const filestruct
|
||||||
**bot, size_t *bot_x, bool *right_side_up);
|
**bot, size_t *bot_x, bool *right_side_up);
|
||||||
|
void add_undo(undo_type current_action, openfilestruct *fs);
|
||||||
|
void update_undo(undo_type action, openfilestruct *fs);
|
||||||
#endif
|
#endif
|
||||||
size_t get_totsize(const filestruct *begin, const filestruct *end);
|
size_t get_totsize(const filestruct *begin, const filestruct *end);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -739,9 +741,6 @@ int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts);
|
||||||
const sc *get_shortcut(int menu, int *kbinput, bool
|
const sc *get_shortcut(int menu, int *kbinput, bool
|
||||||
*meta_key, bool *func_key);
|
*meta_key, bool *func_key);
|
||||||
const sc *first_sc_for(int menu, void *func);
|
const sc *first_sc_for(int menu, void *func);
|
||||||
#ifndef NANO_TINY
|
|
||||||
const toggle *get_toggle(int kbinput, bool meta_key);
|
|
||||||
#endif
|
|
||||||
void blank_line(WINDOW *win, int y, int x, int n);
|
void blank_line(WINDOW *win, int y, int x, int n);
|
||||||
void blank_titlebar(void);
|
void blank_titlebar(void);
|
||||||
void blank_topbar(void);
|
void blank_topbar(void);
|
||||||
|
|
|
@ -423,7 +423,7 @@ void parse_keybinding(char *ptr)
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf(stderr, "newsc now address %d, menu func assigned = %d, menu = %d\n",
|
fprintf(stderr, "newsc now address %d, menu func assigned = %d, menu = %d\n",
|
||||||
(int) newsc, (int) newsc->scfunc, menu);
|
&newsc, &newsc->scfunc, menu);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
330
src/text.c
330
src/text.c
|
@ -70,6 +70,10 @@ void do_delete(void)
|
||||||
/* Do we have to call edit_refresh(), or can we get away with
|
/* Do we have to call edit_refresh(), or can we get away with
|
||||||
* just update_line()? */
|
* just update_line()? */
|
||||||
|
|
||||||
|
#ifndef NANO_TINY
|
||||||
|
update_undo(DEL, openfile);
|
||||||
|
#endif
|
||||||
|
|
||||||
assert(openfile->current != NULL && openfile->current->data != NULL && openfile->current_x <= strlen(openfile->current->data));
|
assert(openfile->current != NULL && openfile->current->data != NULL && openfile->current_x <= strlen(openfile->current->data));
|
||||||
|
|
||||||
openfile->placewewant = xplustabs();
|
openfile->placewewant = xplustabs();
|
||||||
|
@ -359,6 +363,179 @@ void do_unindent(void)
|
||||||
{
|
{
|
||||||
do_indent(-tabsize);
|
do_indent(-tabsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Undo the last thing(s) we did */
|
||||||
|
void do_undo(void)
|
||||||
|
{
|
||||||
|
undo *u = openfile->current_undo;
|
||||||
|
filestruct *f = openfile->current, *t;
|
||||||
|
int len = 0;
|
||||||
|
char *action, *data, *uu;
|
||||||
|
|
||||||
|
if (!u) {
|
||||||
|
statusbar(_("Nothing in undo buffer!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (u->lineno <= f->lineno)
|
||||||
|
for (; f->prev != NULL && f->lineno != u->lineno; f = f->prev)
|
||||||
|
;
|
||||||
|
else
|
||||||
|
for (; f->next != NULL && f->lineno != u->lineno; f = f->next)
|
||||||
|
;
|
||||||
|
if (f->lineno != u->lineno) {
|
||||||
|
statusbar(_("Couldnt match current undo line"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "data we're about to undo = \"%s\"\n", f->data);
|
||||||
|
fprintf(stderr, "Undo running for type %d\n", u->type);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch(u->type) {
|
||||||
|
case ADD:
|
||||||
|
action = _("text add");
|
||||||
|
len = strlen(f->data) - strlen(u->strdata) + 1;
|
||||||
|
data = charalloc(len);
|
||||||
|
strncpy(data, f->data, u->begin);
|
||||||
|
strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
|
||||||
|
free(f->data);
|
||||||
|
f->data = data;
|
||||||
|
break;
|
||||||
|
case DEL:
|
||||||
|
action = _("text delete");
|
||||||
|
len = strlen(f->data) + strlen(u->strdata) + 1;
|
||||||
|
data = charalloc(len);
|
||||||
|
|
||||||
|
strncpy(data, f->data, u->begin);
|
||||||
|
strcpy(&data[u->begin], u->strdata);
|
||||||
|
strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]);
|
||||||
|
free(f->data);
|
||||||
|
f->data = data;
|
||||||
|
break;
|
||||||
|
case SPLIT:
|
||||||
|
action = _("line split");
|
||||||
|
free(f->data);
|
||||||
|
f->data = mallocstrcpy(NULL, u->strdata);
|
||||||
|
if (f->next != NULL) {
|
||||||
|
filestruct *tmp = f->next;
|
||||||
|
unlink_node(tmp);
|
||||||
|
delete_node(tmp);
|
||||||
|
}
|
||||||
|
renumber(openfile->current->prev);
|
||||||
|
break;
|
||||||
|
case UNSPLIT:
|
||||||
|
action = _("line join");
|
||||||
|
t = make_new_node(f);
|
||||||
|
t->data = mallocstrcpy(NULL, u->strdata);
|
||||||
|
data = mallocstrncpy(NULL, f->data, u->begin);
|
||||||
|
data[u->begin] = '\0';
|
||||||
|
free(f->data);
|
||||||
|
f->data = data;
|
||||||
|
splice_node(f, t, f->next);
|
||||||
|
renumber(openfile->current->prev);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
action = _("wtf?");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
openfile->current = f;
|
||||||
|
openfile->current_x = u->begin;
|
||||||
|
edit_refresh();
|
||||||
|
statusbar(_("Undid action (%s)"), action);
|
||||||
|
openfile->current_undo = openfile->current_undo->next;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_redo(void)
|
||||||
|
{
|
||||||
|
undo *u = openfile->undotop;
|
||||||
|
filestruct *f = openfile->current, *t;
|
||||||
|
int len = 0;
|
||||||
|
char *action, *data, *uu;
|
||||||
|
|
||||||
|
for (; u != NULL && u->next != openfile->current_undo; u = u->next)
|
||||||
|
;
|
||||||
|
if (!u) {
|
||||||
|
statusbar(_("Nothing to re-do!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (u->next != openfile->current_undo) {
|
||||||
|
statusbar(_("Can't find previous undo to re-do, argh"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u->lineno <= f->lineno)
|
||||||
|
for (; f->prev != NULL && f->lineno != u->lineno; f = f->prev)
|
||||||
|
;
|
||||||
|
else
|
||||||
|
for (; f->next != NULL && f->lineno != u->lineno; f = f->next)
|
||||||
|
;
|
||||||
|
if (f->lineno != u->lineno) {
|
||||||
|
statusbar(_("Couldnt match current undo line"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "data we're about to redo = \"%s\"\n", f->data);
|
||||||
|
fprintf(stderr, "Redo running for type %d\n", u->type);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch(u->type) {
|
||||||
|
case ADD:
|
||||||
|
action = _("text add");
|
||||||
|
len = strlen(f->data) + strlen(u->strdata) + 1;
|
||||||
|
data = charalloc(len);
|
||||||
|
strcpy(&data[u->begin], u->strdata);
|
||||||
|
strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]);
|
||||||
|
free(f->data);
|
||||||
|
f->data = data;
|
||||||
|
break;
|
||||||
|
case DEL:
|
||||||
|
action = _("text delete");
|
||||||
|
len = strlen(f->data) + strlen(u->strdata) + 1;
|
||||||
|
data = charalloc(len);
|
||||||
|
strncpy(data, f->data, u->begin);
|
||||||
|
strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
|
||||||
|
free(f->data);
|
||||||
|
f->data = data;
|
||||||
|
break;
|
||||||
|
case SPLIT:
|
||||||
|
action = _("line split");
|
||||||
|
t = make_new_node(f);
|
||||||
|
t->data = mallocstrcpy(NULL, u->strdata);
|
||||||
|
data = mallocstrncpy(NULL, f->data, u->begin);
|
||||||
|
data[u->begin] = '\0';
|
||||||
|
free(f->data);
|
||||||
|
f->data = data;
|
||||||
|
splice_node(f, t, f->next);
|
||||||
|
renumber(openfile->current->prev);
|
||||||
|
break;
|
||||||
|
case UNSPLIT:
|
||||||
|
action = _("line join");
|
||||||
|
free(f->data);
|
||||||
|
f->data = mallocstrcpy(NULL, u->strdata);
|
||||||
|
if (f->next != NULL) {
|
||||||
|
filestruct *tmp = f->next;
|
||||||
|
unlink_node(tmp);
|
||||||
|
delete_node(tmp);
|
||||||
|
}
|
||||||
|
renumber(openfile->current->prev);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
action = _("wtf?");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
openfile->current = f;
|
||||||
|
openfile->current_x = u->begin;
|
||||||
|
edit_refresh();
|
||||||
|
statusbar(_("Redid action (%s)"), action);
|
||||||
|
|
||||||
|
openfile->current_undo = u;
|
||||||
|
|
||||||
|
}
|
||||||
#endif /* !NANO_TINY */
|
#endif /* !NANO_TINY */
|
||||||
|
|
||||||
/* Someone hits Enter *gasp!* */
|
/* Someone hits Enter *gasp!* */
|
||||||
|
@ -367,9 +544,12 @@ void do_enter(void)
|
||||||
filestruct *newnode = make_new_node(openfile->current);
|
filestruct *newnode = make_new_node(openfile->current);
|
||||||
size_t extra = 0;
|
size_t extra = 0;
|
||||||
|
|
||||||
assert(openfile->current != NULL && openfile->current->data != NULL);
|
assert(openfile->current != NULL && xopenfile->current->data != NULL);
|
||||||
|
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
|
update_undo(SPLIT, openfile);
|
||||||
|
|
||||||
|
|
||||||
/* Do auto-indenting, like the neolithic Turbo Pascal editor. */
|
/* Do auto-indenting, like the neolithic Turbo Pascal editor. */
|
||||||
if (ISSET(AUTOINDENT)) {
|
if (ISSET(AUTOINDENT)) {
|
||||||
/* If we are breaking the line in the indentation, the new
|
/* If we are breaking the line in the indentation, the new
|
||||||
|
@ -510,6 +690,153 @@ bool execute_command(const char *command)
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_undo(undo_type current_action, openfilestruct *fs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
undo *u = nmalloc(sizeof(undo));
|
||||||
|
char *data;
|
||||||
|
|
||||||
|
/* Blow away the old undo stack if we are starting from the middle */
|
||||||
|
while (fs->undotop != fs->current_undo) {
|
||||||
|
undo *tmp = fs->undotop;
|
||||||
|
fs->undotop = fs->undotop->next;
|
||||||
|
free(tmp->strdata);
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
u->type = current_action;
|
||||||
|
u->lineno = fs->current->lineno;
|
||||||
|
u->begin = fs->current_x;
|
||||||
|
u->fs = fs->current;
|
||||||
|
u->next = fs->undotop;
|
||||||
|
fs->undotop = u;
|
||||||
|
fs->current_undo = u;
|
||||||
|
|
||||||
|
switch (u->type) {
|
||||||
|
/* We need to start copying data into the undo buffer or we wont be able
|
||||||
|
to restore it later */
|
||||||
|
case ADD:
|
||||||
|
data = charalloc(2);
|
||||||
|
data[0] = fs->current->data[fs->current_x];
|
||||||
|
data[1] = '\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;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Else purposely fall into unsplit code */
|
||||||
|
current_action = u->type = UNSPLIT;
|
||||||
|
case UNSPLIT:
|
||||||
|
if (fs->current->next) {
|
||||||
|
data = mallocstrcpy(NULL, fs->current->next->data);
|
||||||
|
u->strdata = data;
|
||||||
|
}
|
||||||
|
u->begin = fs->current_x;
|
||||||
|
break;
|
||||||
|
case SPLIT:
|
||||||
|
data = mallocstrcpy(NULL, fs->current->data);
|
||||||
|
u->strdata = data;
|
||||||
|
u->begin = fs->current_x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "fs->current->data = \"%s\", current_x = %d, u->begin = %d, type = %d\n",
|
||||||
|
fs->current->data, fs->current_x, u->begin, current_action);
|
||||||
|
fprintf(stderr, "u->strdata = \"%s\"\n", u->strdata);
|
||||||
|
fprintf(stderr, "left update_add...\n");
|
||||||
|
#endif
|
||||||
|
fs->last_action = current_action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_undo(undo_type action, openfilestruct *fs)
|
||||||
|
{
|
||||||
|
undo *u;
|
||||||
|
char *data;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (action != fs->last_action) {
|
||||||
|
add_undo(action, fs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(fs->undotop != NULL);
|
||||||
|
u = fs->undotop;
|
||||||
|
|
||||||
|
if (u->fs->data != openfile->current->data) {
|
||||||
|
add_undo(action, fs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
switch (u->type) {
|
||||||
|
case ADD:
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "fs->current->data = \"%s\", current_x = %d, u->begin = %d\n",
|
||||||
|
fs->current->data, fs->current_x, u->begin);
|
||||||
|
#endif
|
||||||
|
len = strlen(u->strdata) + 2;
|
||||||
|
data = nrealloc((void *) u->strdata, len * sizeof(char *));
|
||||||
|
data[len-2] = fs->current->data[fs->current_x];
|
||||||
|
data[len-1] = '\0';
|
||||||
|
u->strdata = (char *) data;
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "current undo data now \"%s\"\n", u->strdata);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case DEL:
|
||||||
|
len = strlen(u->strdata) + 2;
|
||||||
|
assert(len > 2);
|
||||||
|
if (fs->current_x == u->begin) {
|
||||||
|
/* They're deleting */
|
||||||
|
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 */
|
||||||
|
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 {
|
||||||
|
/* They deleted something else on the line */
|
||||||
|
add_undo(DEL, fs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "current undo data now \"%s\"\n", u->strdata);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case SPLIT:
|
||||||
|
case UNSPLIT:
|
||||||
|
/* We don't really ever update an enter key press, treat it as a new */
|
||||||
|
// add_undo(action, fs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "Done in udpate_undo (type was %d)\n", action);
|
||||||
|
#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, openfile);
|
||||||
|
}
|
||||||
|
fs->last_action = action;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* !NANO_TINY */
|
#endif /* !NANO_TINY */
|
||||||
|
|
||||||
#ifndef DISABLE_WRAPPING
|
#ifndef DISABLE_WRAPPING
|
||||||
|
@ -2464,3 +2791,4 @@ void do_verbatim_input(void)
|
||||||
|
|
||||||
free(output);
|
free(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue