undo.c revision 58310
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
89free_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 = 0;
111  int start, end;
112
113#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
114
115  do
116    {
117      if (!rl_undo_list)
118	return (0);
119
120      _rl_doing_an_undo = 1;
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	    ding ();
156	  break;
157	}
158
159      _rl_doing_an_undo = 0;
160
161      release = rl_undo_list;
162      rl_undo_list = rl_undo_list->next;
163      free (release);
164    }
165  while (waiting_for_begin);
166
167  return (1);
168}
169#undef TRANS
170
171int
172_rl_fix_last_undo_of_type (type, start, end)
173     int type, start, end;
174{
175  UNDO_LIST *rl;
176
177  for (rl = rl_undo_list; rl; rl = rl->next)
178    {
179      if (rl->what == type)
180	{
181	  rl->start = start;
182	  rl->end = end;
183	  return 0;
184	}
185    }
186  return 1;
187}
188
189/* Begin a group.  Subsequent undos are undone as an atomic operation. */
190int
191rl_begin_undo_group ()
192{
193  rl_add_undo (UNDO_BEGIN, 0, 0, 0);
194  _rl_undo_group_level++;
195  return 0;
196}
197
198/* End an undo group started with rl_begin_undo_group (). */
199int
200rl_end_undo_group ()
201{
202  rl_add_undo (UNDO_END, 0, 0, 0);
203  _rl_undo_group_level--;
204  return 0;
205}
206
207/* Save an undo entry for the text from START to END. */
208int
209rl_modifying (start, end)
210     int start, end;
211{
212  if (start > end)
213    {
214      SWAP (start, end);
215    }
216
217  if (start != end)
218    {
219      char *temp = rl_copy_text (start, end);
220      rl_begin_undo_group ();
221      rl_add_undo (UNDO_DELETE, start, end, temp);
222      rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
223      rl_end_undo_group ();
224    }
225  return 0;
226}
227
228/* Revert the current line to its previous state. */
229int
230rl_revert_line (count, key)
231     int count, key;
232{
233  if (!rl_undo_list)
234    ding ();
235  else
236    {
237      while (rl_undo_list)
238	rl_do_undo ();
239    }
240  return 0;
241}
242
243/* Do some undoing of things that were done. */
244int
245rl_undo_command (count, key)
246     int count, key;
247{
248  if (count < 0)
249    return 0;	/* Nothing to do. */
250
251  while (count)
252    {
253      if (rl_do_undo ())
254	count--;
255      else
256	{
257	  ding ();
258	  break;
259	}
260    }
261  return 0;
262}
263