undo.c revision 75406
18876Srgrimes/* readline.c -- a general facility for reading lines of input
24Srgrimes   with emacs style editing and completion. */
34Srgrimes
44Srgrimes/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
58876Srgrimes
64Srgrimes   This file is part of the GNU Readline Library, a library for
74Srgrimes   reading lines of text with interactive input and history editing.
84Srgrimes
94Srgrimes   The GNU Readline Library is free software; you can redistribute it
104Srgrimes   and/or modify it under the terms of the GNU General Public License
118876Srgrimes   as published by the Free Software Foundation; either version 2, or
128876Srgrimes   (at your option) any later version.
134Srgrimes
144Srgrimes   The GNU Readline Library is distributed in the hope that it will be
158876Srgrimes   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
164Srgrimes   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
178876Srgrimes   GNU General Public License for more details.
184Srgrimes
194Srgrimes   The GNU General Public License is often shipped with GNU software, and
204Srgrimes   is generally kept in a file called COPYING or LICENSE.  If you do not
214Srgrimes   have a copy of the license, write to the Free Software Foundation,
228876Srgrimes   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
234Srgrimes#define READLINE_LIBRARY
244Srgrimes
254Srgrimes#if defined (HAVE_CONFIG_H)
2612515Sphk#  include <config.h>
274Srgrimes#endif
28623Srgrimes
294Srgrimes#include <sys/types.h>
304Srgrimes
314Srgrimes#if defined (HAVE_UNISTD_H)
324Srgrimes#  include <unistd.h>           /* for _POSIX_VERSION */
334Srgrimes#endif /* HAVE_UNISTD_H */
342056Swollman
352056Swollman#if defined (HAVE_STDLIB_H)
362056Swollman#  include <stdlib.h>
372056Swollman#else
384Srgrimes#  include "ansi_stdlib.h"
394Srgrimes#endif /* HAVE_STDLIB_H */
404Srgrimes
414Srgrimes#include <stdio.h>
4212515Sphk
4312473Sbde/* System-specific feature definitions and include files. */
444Srgrimes#include "rldefs.h"
4512515Sphk
4612515Sphk/* Some standard library routines. */
4712515Sphk#include "readline.h"
4812515Sphk#include "history.h"
4912515Sphk
504Srgrimes#include "rlprivate.h"
514Srgrimes
524Srgrimes#define SWAP(s, e)  do { int t; t = s; s = e; e = t; } while (0)
534Srgrimes
544Srgrimes/* Non-zero tells rl_delete_text and rl_insert_text to not add to
5512515Sphk   the undo list. */
5612515Sphkint _rl_doing_an_undo = 0;
574Srgrimes
5812515Sphk/* How many unclosed undo groups we currently have. */
594Srgrimesint _rl_undo_group_level = 0;
604Srgrimes
614Srgrimes/* The current undo list for THE_LINE. */
624SrgrimesUNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
634Srgrimes
644Srgrimes/* **************************************************************** */
654Srgrimes/*								    */
664Srgrimes/*			Undo, and Undoing			    */
674Srgrimes/*								    */
684Srgrimes/* **************************************************************** */
694Srgrimes
704Srgrimes/* Remember how to undo something.  Concatenate some undos if that
714Srgrimes   seems right. */
724Srgrimesvoid
734Srgrimesrl_add_undo (what, start, end, text)
744Srgrimes     enum undo_code what;
754Srgrimes     int start, end;
764Srgrimes     char *text;
774Srgrimes{
784Srgrimes  UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
794Srgrimes  temp->what = what;
804Srgrimes  temp->start = start;
814Srgrimes  temp->end = end;
824Srgrimes  temp->text = text;
834Srgrimes  temp->next = rl_undo_list;
844Srgrimes  rl_undo_list = temp;
854Srgrimes}
864Srgrimes
874Srgrimes/* Free the existing undo list. */
884Srgrimesvoid
894Srgrimesrl_free_undo_list ()
904Srgrimes{
914Srgrimes  while (rl_undo_list)
924Srgrimes    {
934Srgrimes      UNDO_LIST *release = rl_undo_list;
944Srgrimes      rl_undo_list = rl_undo_list->next;
954Srgrimes
964Srgrimes      if (release->what == UNDO_DELETE)
974Srgrimes	free (release->text);
9812515Sphk
9912515Sphk      free (release);
1004Srgrimes    }
1014Srgrimes  rl_undo_list = (UNDO_LIST *)NULL;
1024Srgrimes}
1034Srgrimes
1044Srgrimes/* Undo the next thing in the list.  Return 0 if there
1054Srgrimes   is nothing to undo, or non-zero if there was. */
1064Srgrimesint
1074Srgrimesrl_do_undo ()
1084Srgrimes{
1094Srgrimes  UNDO_LIST *release;
1104Srgrimes  int waiting_for_begin, start, end;
1114Srgrimes
11212515Sphk#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
1134Srgrimes
114798Swollman  start = end = waiting_for_begin = 0;
1154Srgrimes  do
1164Srgrimes    {
1174Srgrimes      if (!rl_undo_list)
1184Srgrimes	return (0);
11912473Sbde
1204Srgrimes      _rl_doing_an_undo = 1;
1214Srgrimes      RL_SETSTATE(RL_STATE_UNDOING);
1224Srgrimes
1234Srgrimes      /* To better support vi-mode, a start or end value of -1 means
1244Srgrimes	 rl_point, and a value of -2 means rl_end. */
1254Srgrimes      if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
1264Srgrimes	{
127798Swollman	  start = TRANS (rl_undo_list->start);
1284Srgrimes	  end = TRANS (rl_undo_list->end);
1294Srgrimes	}
1304Srgrimes
1314Srgrimes      switch (rl_undo_list->what)
13212473Sbde	{
1334Srgrimes	/* Undoing deletes means inserting some text. */
1344Srgrimes	case UNDO_DELETE:
1354Srgrimes	  rl_point = start;
1364Srgrimes	  rl_insert_text (rl_undo_list->text);
1374Srgrimes	  free (rl_undo_list->text);
1384Srgrimes	  break;
1394Srgrimes
1404Srgrimes	/* Undoing inserts means deleting some text. */
14112473Sbde	case UNDO_INSERT:
14212473Sbde	  rl_delete_text (start, end);
14312473Sbde	  rl_point = start;
14412473Sbde	  break;
14512473Sbde
1464Srgrimes	/* Undoing an END means undoing everything 'til we get to a BEGIN. */
1474Srgrimes	case UNDO_END:
1484Srgrimes	  waiting_for_begin++;
1494Srgrimes	  break;
1504Srgrimes
1514Srgrimes	/* Undoing a BEGIN means that we are done with this group. */
1524Srgrimes	case UNDO_BEGIN:
1534Srgrimes	  if (waiting_for_begin)
1544Srgrimes	    waiting_for_begin--;
1554Srgrimes	  else
1564Srgrimes	    rl_ding ();
1574Srgrimes	  break;
1584Srgrimes	}
1594Srgrimes
1604Srgrimes      _rl_doing_an_undo = 0;
1614Srgrimes      RL_UNSETSTATE(RL_STATE_UNDOING);
1624Srgrimes
1634Srgrimes      release = rl_undo_list;
1644Srgrimes      rl_undo_list = rl_undo_list->next;
1654Srgrimes      free (release);
1664Srgrimes    }
1674Srgrimes  while (waiting_for_begin);
1684Srgrimes
1694Srgrimes  return (1);
1704Srgrimes}
1714Srgrimes#undef TRANS
1724Srgrimes
1734Srgrimesint
1744Srgrimes_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