undo.c revision 157184
1/* readline.c -- a general facility for reading lines of input
2   with emacs style editing and completion. */
3
4/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
5
6   This file is part of the GNU Readline Library, a library for
7   reading lines of text with interactive input and history editing.
8
9   The GNU Readline Library is free software; you can redistribute it
10   and/or modify it under the terms of the GNU General Public License
11   as published by the Free Software Foundation; either version 2, or
12   (at your option) any later version.
13
14   The GNU Readline Library is distributed in the hope that it will be
15   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   The GNU General Public License is often shipped with GNU software, and
20   is generally kept in a file called COPYING or LICENSE.  If you do not
21   have a copy of the license, write to the Free Software Foundation,
22   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23#define READLINE_LIBRARY
24
25#if defined (HAVE_CONFIG_H)
26#  include <config.h>
27#endif
28
29#include <sys/types.h>
30
31#if defined (HAVE_UNISTD_H)
32#  include <unistd.h>           /* for _POSIX_VERSION */
33#endif /* HAVE_UNISTD_H */
34
35#if defined (HAVE_STDLIB_H)
36#  include <stdlib.h>
37#else
38#  include "ansi_stdlib.h"
39#endif /* HAVE_STDLIB_H */
40
41#include <stdio.h>
42
43/* System-specific feature definitions and include files. */
44#include "rldefs.h"
45
46/* Some standard library routines. */
47#include "readline.h"
48#include "history.h"
49
50#include "rlprivate.h"
51#include "xmalloc.h"
52
53/* Non-zero tells rl_delete_text and rl_insert_text to not add to
54   the undo list. */
55int _rl_doing_an_undo = 0;
56
57/* How many unclosed undo groups we currently have. */
58int _rl_undo_group_level = 0;
59
60/* The current undo list for THE_LINE. */
61UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
62
63/* **************************************************************** */
64/*								    */
65/*			Undo, and Undoing			    */
66/*								    */
67/* **************************************************************** */
68
69/* Remember how to undo something.  Concatenate some undos if that
70   seems right. */
71void
72rl_add_undo (what, start, end, text)
73     enum undo_code what;
74     int start, end;
75     char *text;
76{
77  UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
78  temp->what = what;
79  temp->start = start;
80  temp->end = end;
81  temp->text = text;
82  temp->next = rl_undo_list;
83  rl_undo_list = temp;
84}
85
86/* Free the existing undo list. */
87void
88rl_free_undo_list ()
89{
90  while (rl_undo_list)
91    {
92      UNDO_LIST *release = rl_undo_list;
93      rl_undo_list = rl_undo_list->next;
94
95      if (release->what == UNDO_DELETE)
96	free (release->text);
97
98      free (release);
99    }
100  rl_undo_list = (UNDO_LIST *)NULL;
101}
102
103/* Undo the next thing in the list.  Return 0 if there
104   is nothing to undo, or non-zero if there was. */
105int
106rl_do_undo ()
107{
108  UNDO_LIST *release;
109  int waiting_for_begin, start, end;
110
111#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
112
113  start = end = waiting_for_begin = 0;
114  do
115    {
116      if (!rl_undo_list)
117	return (0);
118
119      _rl_doing_an_undo = 1;
120      RL_SETSTATE(RL_STATE_UNDOING);
121
122      /* To better support vi-mode, a start or end value of -1 means
123	 rl_point, and a value of -2 means rl_end. */
124      if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
125	{
126	  start = TRANS (rl_undo_list->start);
127	  end = TRANS (rl_undo_list->end);
128	}
129
130      switch (rl_undo_list->what)
131	{
132	/* Undoing deletes means inserting some text. */
133	case UNDO_DELETE:
134	  rl_point = start;
135	  rl_insert_text (rl_undo_list->text);
136	  free (rl_undo_list->text);
137	  break;
138
139	/* Undoing inserts means deleting some text. */
140	case UNDO_INSERT:
141	  rl_delete_text (start, end);
142	  rl_point = start;
143	  break;
144
145	/* Undoing an END means undoing everything 'til we get to a BEGIN. */
146	case UNDO_END:
147	  waiting_for_begin++;
148	  break;
149
150	/* Undoing a BEGIN means that we are done with this group. */
151	case UNDO_BEGIN:
152	  if (waiting_for_begin)
153	    waiting_for_begin--;
154	  else
155	    rl_ding ();
156	  break;
157	}
158
159      _rl_doing_an_undo = 0;
160      RL_UNSETSTATE(RL_STATE_UNDOING);
161
162      release = rl_undo_list;
163      rl_undo_list = rl_undo_list->next;
164      free (release);
165    }
166  while (waiting_for_begin);
167
168  return (1);
169}
170#undef TRANS
171
172int
173_rl_fix_last_undo_of_type (type, start, end)
174     int type, start, end;
175{
176  UNDO_LIST *rl;
177
178  for (rl = rl_undo_list; rl; rl = rl->next)
179    {
180      if (rl->what == type)
181	{
182	  rl->start = start;
183	  rl->end = end;
184	  return 0;
185	}
186    }
187  return 1;
188}
189
190/* Begin a group.  Subsequent undos are undone as an atomic operation. */
191int
192rl_begin_undo_group ()
193{
194  rl_add_undo (UNDO_BEGIN, 0, 0, 0);
195  _rl_undo_group_level++;
196  return 0;
197}
198
199/* End an undo group started with rl_begin_undo_group (). */
200int
201rl_end_undo_group ()
202{
203  rl_add_undo (UNDO_END, 0, 0, 0);
204  _rl_undo_group_level--;
205  return 0;
206}
207
208/* Save an undo entry for the text from START to END. */
209int
210rl_modifying (start, end)
211     int start, end;
212{
213  if (start > end)
214    {
215      SWAP (start, end);
216    }
217
218  if (start != end)
219    {
220      char *temp = rl_copy_text (start, end);
221      rl_begin_undo_group ();
222      rl_add_undo (UNDO_DELETE, start, end, temp);
223      rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
224      rl_end_undo_group ();
225    }
226  return 0;
227}
228
229/* Revert the current line to its previous state. */
230int
231rl_revert_line (count, key)
232     int count, key;
233{
234  if (!rl_undo_list)
235    rl_ding ();
236  else
237    {
238      while (rl_undo_list)
239	rl_do_undo ();
240#if defined (VI_MODE)
241      if (rl_editing_mode == vi_mode)
242	rl_point = rl_mark = 0;		/* rl_end should be set correctly */
243#endif
244    }
245
246  return 0;
247}
248
249/* Do some undoing of things that were done. */
250int
251rl_undo_command (count, key)
252     int count, key;
253{
254  if (count < 0)
255    return 0;	/* Nothing to do. */
256
257  while (count)
258    {
259      if (rl_do_undo ())
260	count--;
261      else
262	{
263	  rl_ding ();
264	  break;
265	}
266    }
267  return 0;
268}
269