undo.c revision 21308
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 1, 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   675 Mass Ave, Cambridge, MA 02139, 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 <setjmp.h>
42#include <stdio.h>
43
44/* System-specific feature definitions and include files. */
45#include "rldefs.h"
46
47/* Some standard library routines. */
48#include "readline.h"
49#include "history.h"
50
51#define SWAP(s, e)  do { int t; t = s; s = e; e = t; } while (0)
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
88free_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 = 0;
110  int start, end;
111
112#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
113
114  do
115    {
116      if (!rl_undo_list)
117	return (0);
118
119      _rl_doing_an_undo = 1;
120
121      /* To better support vi-mode, a start or end value of -1 means
122	 rl_point, and a value of -2 means rl_end. */
123      if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
124	{
125	  start = TRANS (rl_undo_list->start);
126	  end = TRANS (rl_undo_list->end);
127	}
128
129      switch (rl_undo_list->what)
130	{
131	/* Undoing deletes means inserting some text. */
132	case UNDO_DELETE:
133	  rl_point = start;
134	  rl_insert_text (rl_undo_list->text);
135	  free (rl_undo_list->text);
136	  break;
137
138	/* Undoing inserts means deleting some text. */
139	case UNDO_INSERT:
140	  rl_delete_text (start, end);
141	  rl_point = start;
142	  break;
143
144	/* Undoing an END means undoing everything 'til we get to a BEGIN. */
145	case UNDO_END:
146	  waiting_for_begin++;
147	  break;
148
149	/* Undoing a BEGIN means that we are done with this group. */
150	case UNDO_BEGIN:
151	  if (waiting_for_begin)
152	    waiting_for_begin--;
153	  else
154	    ding ();
155	  break;
156	}
157
158      _rl_doing_an_undo = 0;
159
160      release = rl_undo_list;
161      rl_undo_list = rl_undo_list->next;
162      free (release);
163    }
164  while (waiting_for_begin);
165
166  return (1);
167}
168#undef TRANS
169
170int
171_rl_fix_last_undo_of_type (type, start, end)
172     int type, start, end;
173{
174  UNDO_LIST *rl;
175
176  for (rl = rl_undo_list; rl; rl = rl->next)
177    {
178      if (rl->what == type)
179	{
180	  rl->start = start;
181	  rl->end = end;
182	  return 0;
183	}
184    }
185  return 1;
186}
187
188/* Begin a group.  Subsequent undos are undone as an atomic operation. */
189int
190rl_begin_undo_group ()
191{
192  rl_add_undo (UNDO_BEGIN, 0, 0, 0);
193  _rl_undo_group_level++;
194  return 0;
195}
196
197/* End an undo group started with rl_begin_undo_group (). */
198int
199rl_end_undo_group ()
200{
201  rl_add_undo (UNDO_END, 0, 0, 0);
202  _rl_undo_group_level--;
203  return 0;
204}
205
206/* Save an undo entry for the text from START to END. */
207int
208rl_modifying (start, end)
209     int start, end;
210{
211  if (start > end)
212    {
213      SWAP (start, end);
214    }
215
216  if (start != end)
217    {
218      char *temp = rl_copy_text (start, end);
219      rl_begin_undo_group ();
220      rl_add_undo (UNDO_DELETE, start, end, temp);
221      rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
222      rl_end_undo_group ();
223    }
224  return 0;
225}
226
227/* Revert the current line to its previous state. */
228int
229rl_revert_line (count, key)
230     int count, key;
231{
232  if (!rl_undo_list)
233    ding ();
234  else
235    {
236      while (rl_undo_list)
237	rl_do_undo ();
238    }
239  return 0;
240}
241
242/* Do some undoing of things that were done. */
243int
244rl_undo_command (count, key)
245     int count, key;
246{
247  if (count < 0)
248    return 0;	/* Nothing to do. */
249
250  while (count)
251    {
252      if (rl_do_undo ())
253	count--;
254      else
255	{
256	  ding ();
257	  break;
258	}
259    }
260  return 0;
261}
262