undo.c revision 75406
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
52#define SWAP(s, e)  do { int t; t = s; s = e; e = t; } while (0)
53
54/* Non-zero tells rl_delete_text and rl_insert_text to not add to
55   the undo list. */
56int _rl_doing_an_undo = 0;
57
58/* How many unclosed undo groups we currently have. */
59int _rl_undo_group_level = 0;
60
61/* The current undo list for THE_LINE. */
62UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
63
64/* **************************************************************** */
65/*								    */
66/*			Undo, and Undoing			    */
67/*								    */
68/* **************************************************************** */
69
70/* Remember how to undo something.  Concatenate some undos if that
71   seems right. */
72void
73rl_add_undo (what, start, end, text)
74     enum undo_code what;
75     int start, end;
76     char *text;
77{
78  UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
79  temp->what = what;
80  temp->start = start;
81  temp->end = end;
82  temp->text = text;
83  temp->next = rl_undo_list;
84  rl_undo_list = temp;
85}
86
87/* Free the existing undo list. */
88void
89rl_free_undo_list ()
90{
91  while (rl_undo_list)
92    {
93      UNDO_LIST *release = rl_undo_list;
94      rl_undo_list = rl_undo_list->next;
95
96      if (release->what == UNDO_DELETE)
97	free (release->text);
98
99      free (release);
100    }
101  rl_undo_list = (UNDO_LIST *)NULL;
102}
103
104/* Undo the next thing in the list.  Return 0 if there
105   is nothing to undo, or non-zero if there was. */
106int
107rl_do_undo ()
108{
109  UNDO_LIST *release;
110  int waiting_for_begin, start, end;
111
112#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
113
114  start = end = waiting_for_begin = 0;
115  do
116    {
117      if (!rl_undo_list)
118	return (0);
119
120      _rl_doing_an_undo = 1;
121      RL_SETSTATE(RL_STATE_UNDOING);
122
123      /* To better support vi-mode, a start or end value of -1 means
124	 rl_point, and a value of -2 means rl_end. */
125      if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
126	{
127	  start = TRANS (rl_undo_list->start);
128	  end = TRANS (rl_undo_list->end);
129	}
130
131      switch (rl_undo_list->what)
132	{
133	/* Undoing deletes means inserting some text. */
134	case UNDO_DELETE:
135	  rl_point = start;
136	  rl_insert_text (rl_undo_list->text);
137	  free (rl_undo_list->text);
138	  break;
139
140	/* Undoing inserts means deleting some text. */
141	case UNDO_INSERT:
142	  rl_delete_text (start, end);
143	  rl_point = start;
144	  break;
145
146	/* Undoing an END means undoing everything 'til we get to a BEGIN. */
147	case UNDO_END:
148	  waiting_for_begin++;
149	  break;
150
151	/* Undoing a BEGIN means that we are done with this group. */
152	case UNDO_BEGIN:
153	  if (waiting_for_begin)
154	    waiting_for_begin--;
155	  else
156	    rl_ding ();
157	  break;
158	}
159
160      _rl_doing_an_undo = 0;
161      RL_UNSETSTATE(RL_STATE_UNDOING);
162
163      release = rl_undo_list;
164      rl_undo_list = rl_undo_list->next;
165      free (release);
166    }
167  while (waiting_for_begin);
168
169  return (1);
170}
171#undef TRANS
172
173int
174_rl_fix_last_undo_of_type (type, start, end)
175     int type, start, end;
176{
177  UNDO_LIST *rl;
178
179  for (rl = rl_undo_list; rl; rl = rl->next)
180    {
181      if (rl->what == type)
182	{
183	  rl->start = start;
184	  rl->end = end;
185	  return 0;
186	}
187    }
188  return 1;
189}
190
191/* Begin a group.  Subsequent undos are undone as an atomic operation. */
192int
193rl_begin_undo_group ()
194{
195  rl_add_undo (UNDO_BEGIN, 0, 0, 0);
196  _rl_undo_group_level++;
197  return 0;
198}
199
200/* End an undo group started with rl_begin_undo_group (). */
201int
202rl_end_undo_group ()
203{
204  rl_add_undo (UNDO_END, 0, 0, 0);
205  _rl_undo_group_level--;
206  return 0;
207}
208
209/* Save an undo entry for the text from START to END. */
210int
211rl_modifying (start, end)
212     int start, end;
213{
214  if (start > end)
215    {
216      SWAP (start, end);
217    }
218
219  if (start != end)
220    {
221      char *temp = rl_copy_text (start, end);
222      rl_begin_undo_group ();
223      rl_add_undo (UNDO_DELETE, start, end, temp);
224      rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
225      rl_end_undo_group ();
226    }
227  return 0;
228}
229
230/* Revert the current line to its previous state. */
231int
232rl_revert_line (count, key)
233     int count, key;
234{
235  if (!rl_undo_list)
236    rl_ding ();
237  else
238    {
239      while (rl_undo_list)
240	rl_do_undo ();
241    }
242  return 0;
243}
244
245/* Do some undoing of things that were done. */
246int
247rl_undo_command (count, key)
248     int count, key;
249{
250  if (count < 0)
251    return 0;	/* Nothing to do. */
252
253  while (count)
254    {
255      if (rl_do_undo ())
256	count--;
257      else
258	{
259	  rl_ding ();
260	  break;
261	}
262    }
263  return 0;
264}
265