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