undo.c revision 75406
1147359Simp/* readline.c -- a general facility for reading lines of input
2147595Sru   with emacs style editing and completion. */
3147359Simp
4147359Simp/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
5147359Simp
6147359Simp   This file is part of the GNU Readline Library, a library for
7147359Simp   reading lines of text with interactive input and history editing.
8147359Simp
9147359Simp   The GNU Readline Library is free software; you can redistribute it
10147359Simp   and/or modify it under the terms of the GNU General Public License
11147359Simp   as published by the Free Software Foundation; either version 2, or
12147359Simp   (at your option) any later version.
13147359Simp
14147359Simp   The GNU Readline Library is distributed in the hope that it will be
15147359Simp   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16147359Simp   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17147359Simp   GNU General Public License for more details.
18147359Simp
19147359Simp   The GNU General Public License is often shipped with GNU software, and
20147359Simp   is generally kept in a file called COPYING or LICENSE.  If you do not
21147359Simp   have a copy of the license, write to the Free Software Foundation,
22147359Simp   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23147359Simp#define READLINE_LIBRARY
24147359Simp
25147359Simp#if defined (HAVE_CONFIG_H)
26147359Simp#  include <config.h>
27147595Sru#endif
28147359Simp
29147359Simp#include <sys/types.h>
30147595Sru
31147359Simp#if defined (HAVE_UNISTD_H)
32147359Simp#  include <unistd.h>           /* for _POSIX_VERSION */
33147359Simp#endif /* HAVE_UNISTD_H */
34147359Simp
35147359Simp#if defined (HAVE_STDLIB_H)
36147359Simp#  include <stdlib.h>
37147359Simp#else
38147359Simp#  include "ansi_stdlib.h"
39147595Sru#endif /* HAVE_STDLIB_H */
40147359Simp
41147359Simp#include <stdio.h>
42147359Simp
43147359Simp/* System-specific feature definitions and include files. */
44147359Simp#include "rldefs.h"
45147359Simp
46147359Simp/* Some standard library routines. */
47147359Simp#include "readline.h"
48147359Simp#include "history.h"
49147359Simp
50147359Simp#include "rlprivate.h"
51147359Simp
52147595Sru#define SWAP(s, e)  do { int t; t = s; s = e; e = t; } while (0)
53147595Sru
54147359Simp/* Non-zero tells rl_delete_text and rl_insert_text to not add to
55147359Simp   the undo list. */
56147359Simpint _rl_doing_an_undo = 0;
57147359Simp
58147359Simp/* How many unclosed undo groups we currently have. */
59147359Simpint _rl_undo_group_level = 0;
60147359Simp
61147359Simp/* The current undo list for THE_LINE. */
62147359SimpUNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
63147359Simp
64157954Sjmg/* **************************************************************** */
65157954Sjmg/*								    */
66157954Sjmg/*			Undo, and Undoing			    */
67157954Sjmg/*								    */
68147359Simp/* **************************************************************** */
69147359Simp
70147359Simp/* Remember how to undo something.  Concatenate some undos if that
71147359Simp   seems right. */
72147359Simpvoid
73147359Simprl_add_undo (what, start, end, text)
74147359Simp     enum undo_code what;
75147359Simp     int start, end;
76147359Simp     char *text;
77147359Simp{
78157954Sjmg  UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
79157954Sjmg  temp->what = what;
80157954Sjmg  temp->start = start;
81157954Sjmg  temp->end = end;
82147359Simp  temp->text = text;
83147359Simp  temp->next = rl_undo_list;
84147359Simp  rl_undo_list = temp;
85147359Simp}
86157954Sjmg
87157954Sjmg/* Free the existing undo list. */
88157954Sjmgvoid
89157954Sjmgrl_free_undo_list ()
90157954Sjmg{
91157954Sjmg  while (rl_undo_list)
92157954Sjmg    {
93157954Sjmg      UNDO_LIST *release = rl_undo_list;
94157954Sjmg      rl_undo_list = rl_undo_list->next;
95157954Sjmg
96157954Sjmg      if (release->what == UNDO_DELETE)
97157954Sjmg	free (release->text);
98157954Sjmg
99157954Sjmg      free (release);
100157954Sjmg    }
101157954Sjmg  rl_undo_list = (UNDO_LIST *)NULL;
102147359Simp}
103147359Simp
104147359Simp/* Undo the next thing in the list.  Return 0 if there
105147359Simp   is nothing to undo, or non-zero if there was. */
106157954Sjmgint
107157954Sjmgrl_do_undo ()
108157954Sjmg{
109157954Sjmg  UNDO_LIST *release;
110147359Simp  int waiting_for_begin, start, end;
111147359Simp
112147359Simp#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
113147359Simp
114147359Simp  start = end = waiting_for_begin = 0;
115147359Simp  do
116147359Simp    {
117147359Simp      if (!rl_undo_list)
118147359Simp	return (0);
119147359Simp
120157954Sjmg      _rl_doing_an_undo = 1;
121157954Sjmg      RL_SETSTATE(RL_STATE_UNDOING);
122157954Sjmg
123157954Sjmg      /* To better support vi-mode, a start or end value of -1 means
124147359Simp	 rl_point, and a value of -2 means rl_end. */
125147359Simp      if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
126147359Simp	{
127157954Sjmg	  start = TRANS (rl_undo_list->start);
128157954Sjmg	  end = TRANS (rl_undo_list->end);
129157954Sjmg	}
130157954Sjmg
131157954Sjmg      switch (rl_undo_list->what)
132157954Sjmg	{
133157954Sjmg	/* Undoing deletes means inserting some text. */
134157954Sjmg	case UNDO_DELETE:
135157954Sjmg	  rl_point = start;
136147595Sru	  rl_insert_text (rl_undo_list->text);
137147359Simp	  free (rl_undo_list->text);
138147595Sru	  break;
139147359Simp
140147595Sru	/* Undoing inserts means deleting some text. */
141147595Sru	case UNDO_INSERT:
142147595Sru	  rl_delete_text (start, end);
143147595Sru	  rl_point = start;
144147359Simp	  break;
145147595Sru
146147595Sru	/* Undoing an END means undoing everything 'til we get to a BEGIN. */
147147595Sru	case UNDO_END:
148147359Simp	  waiting_for_begin++;
149147595Sru	  break;
150147595Sru
151147595Sru	/* Undoing a BEGIN means that we are done with this group. */
152147595Sru	case UNDO_BEGIN:
153147359Simp	  if (waiting_for_begin)
154147359Simp	    waiting_for_begin--;
155147359Simp	  else
156147359Simp	    rl_ding ();
157147359Simp	  break;
158147359Simp	}
159147359Simp
160147595Sru      _rl_doing_an_undo = 0;
161147595Sru      RL_UNSETSTATE(RL_STATE_UNDOING);
162147595Sru
163231564Sed      release = rl_undo_list;
164147595Sru      rl_undo_list = rl_undo_list->next;
165147595Sru      free (release);
166147595Sru    }
167231564Sed  while (waiting_for_begin);
168147595Sru
169147595Sru  return (1);
170147595Sru}
171231564Sed#undef TRANS
172147595Sru
173147595Sruint
174147595Sru_rl_fix_last_undo_of_type (type, start, end)
175231564Sed     int type, start, end;
176147595Sru{
177147595Sru  UNDO_LIST *rl;
178147595Sru
179231564Sed  for (rl = rl_undo_list; rl; rl = rl->next)
180157954Sjmg    {
181157954Sjmg      if (rl->what == type)
182157954Sjmg	{
183231564Sed	  rl->start = start;
184157954Sjmg	  rl->end = end;
185157954Sjmg	  return 0;
186157954Sjmg	}
187231564Sed    }
188157954Sjmg  return 1;
189157954Sjmg}
190157954Sjmg
191231564Sed/* Begin a group.  Subsequent undos are undone as an atomic operation. */
192157954Sjmgint
193157954Sjmgrl_begin_undo_group ()
194157954Sjmg{
195147359Simp  rl_add_undo (UNDO_BEGIN, 0, 0, 0);
196147595Sru  _rl_undo_group_level++;
197147595Sru  return 0;
198231564Sed}
199147595Sru
200147359Simp/* End an undo group started with rl_begin_undo_group (). */
201147595Sruint
202147595Srurl_end_undo_group ()
203231564Sed{
204147595Sru  rl_add_undo (UNDO_END, 0, 0, 0);
205147359Simp  _rl_undo_group_level--;
206147595Sru  return 0;
207147595Sru}
208231564Sed
209147595Sru/* Save an undo entry for the text from START to END. */
210147359Simpint
211147595Srurl_modifying (start, end)
212147595Sru     int start, end;
213231564Sed{
214147595Sru  if (start > end)
215147359Simp    {
216157954Sjmg      SWAP (start, end);
217157954Sjmg    }
218231564Sed
219157954Sjmg  if (start != end)
220157954Sjmg    {
221157954Sjmg      char *temp = rl_copy_text (start, end);
222157954Sjmg      rl_begin_undo_group ();
223231564Sed      rl_add_undo (UNDO_DELETE, start, end, temp);
224157954Sjmg      rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
225157954Sjmg      rl_end_undo_group ();
226157954Sjmg    }
227157954Sjmg  return 0;
228231564Sed}
229157954Sjmg
230157954Sjmg/* Revert the current line to its previous state. */
231157954Sjmgint
232157954Sjmgrl_revert_line (count, key)
233231564Sed     int count, key;
234157954Sjmg{
235157954Sjmg  if (!rl_undo_list)
236147595Sru    rl_ding ();
237147595Sru  else
238147595Sru    {
239147595Sru      while (rl_undo_list)
240147359Simp	rl_do_undo ();
241147595Sru    }
242147595Sru  return 0;
243231564Sed}
244147595Sru
245147595Sru/* Do some undoing of things that were done. */
246147359Simpint
247147595Srurl_undo_command (count, key)
248147595Sru     int count, key;
249231564Sed{
250147595Sru  if (count < 0)
251147595Sru    return 0;	/* Nothing to do. */
252147359Simp
253147595Sru  while (count)
254147595Sru    {
255231564Sed      if (rl_do_undo ())
256147595Sru	count--;
257147595Sru      else
258147359Simp	{
259147595Sru	  rl_ding ();
260147595Sru	  break;
261231564Sed	}
262147595Sru    }
263147595Sru  return 0;
264147359Simp}
265157954Sjmg