undo.c revision 58310
121308Sache/* readline.c -- a general facility for reading lines of input
221308Sache   with emacs style editing and completion. */
321308Sache
421308Sache/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
521308Sache
621308Sache   This file is part of the GNU Readline Library, a library for
721308Sache   reading lines of text with interactive input and history editing.
821308Sache
921308Sache   The GNU Readline Library is free software; you can redistribute it
1021308Sache   and/or modify it under the terms of the GNU General Public License
1158310Sache   as published by the Free Software Foundation; either version 2, or
1221308Sache   (at your option) any later version.
1321308Sache
1421308Sache   The GNU Readline Library is distributed in the hope that it will be
1521308Sache   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
1621308Sache   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1721308Sache   GNU General Public License for more details.
1821308Sache
1921308Sache   The GNU General Public License is often shipped with GNU software, and
2021308Sache   is generally kept in a file called COPYING or LICENSE.  If you do not
2121308Sache   have a copy of the license, write to the Free Software Foundation,
2258310Sache   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
2321308Sache#define READLINE_LIBRARY
2421308Sache
2521308Sache#if defined (HAVE_CONFIG_H)
2621308Sache#  include <config.h>
2721308Sache#endif
2821308Sache
2921308Sache#include <sys/types.h>
3021308Sache
3121308Sache#if defined (HAVE_UNISTD_H)
3221308Sache#  include <unistd.h>           /* for _POSIX_VERSION */
3321308Sache#endif /* HAVE_UNISTD_H */
3421308Sache
3521308Sache#if defined (HAVE_STDLIB_H)
3621308Sache#  include <stdlib.h>
3721308Sache#else
3821308Sache#  include "ansi_stdlib.h"
3921308Sache#endif /* HAVE_STDLIB_H */
4021308Sache
4121308Sache#include <stdio.h>
4221308Sache
4321308Sache/* System-specific feature definitions and include files. */
4421308Sache#include "rldefs.h"
4521308Sache
4621308Sache/* Some standard library routines. */
4721308Sache#include "readline.h"
4821308Sache#include "history.h"
4921308Sache
5058310Sache#include "rlprivate.h"
5158310Sache
5221308Sache#define SWAP(s, e)  do { int t; t = s; s = e; e = t; } while (0)
5321308Sache
5421308Sache/* Non-zero tells rl_delete_text and rl_insert_text to not add to
5521308Sache   the undo list. */
5621308Sacheint _rl_doing_an_undo = 0;
5721308Sache
5821308Sache/* How many unclosed undo groups we currently have. */
5921308Sacheint _rl_undo_group_level = 0;
6021308Sache
6121308Sache/* The current undo list for THE_LINE. */
6221308SacheUNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
6321308Sache
6421308Sache/* **************************************************************** */
6521308Sache/*								    */
6621308Sache/*			Undo, and Undoing			    */
6721308Sache/*								    */
6821308Sache/* **************************************************************** */
6921308Sache
7021308Sache/* Remember how to undo something.  Concatenate some undos if that
7121308Sache   seems right. */
7221308Sachevoid
7321308Sacherl_add_undo (what, start, end, text)
7421308Sache     enum undo_code what;
7521308Sache     int start, end;
7621308Sache     char *text;
7721308Sache{
7821308Sache  UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
7921308Sache  temp->what = what;
8021308Sache  temp->start = start;
8121308Sache  temp->end = end;
8221308Sache  temp->text = text;
8321308Sache  temp->next = rl_undo_list;
8421308Sache  rl_undo_list = temp;
8521308Sache}
8621308Sache
8721308Sache/* Free the existing undo list. */
8821308Sachevoid
8921308Sachefree_undo_list ()
9021308Sache{
9121308Sache  while (rl_undo_list)
9221308Sache    {
9321308Sache      UNDO_LIST *release = rl_undo_list;
9421308Sache      rl_undo_list = rl_undo_list->next;
9521308Sache
9621308Sache      if (release->what == UNDO_DELETE)
9721308Sache	free (release->text);
9821308Sache
9921308Sache      free (release);
10021308Sache    }
10121308Sache  rl_undo_list = (UNDO_LIST *)NULL;
10221308Sache}
10321308Sache
10421308Sache/* Undo the next thing in the list.  Return 0 if there
10521308Sache   is nothing to undo, or non-zero if there was. */
10621308Sacheint
10721308Sacherl_do_undo ()
10821308Sache{
10921308Sache  UNDO_LIST *release;
11021308Sache  int waiting_for_begin = 0;
11121308Sache  int start, end;
11221308Sache
11321308Sache#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
11421308Sache
11521308Sache  do
11621308Sache    {
11721308Sache      if (!rl_undo_list)
11821308Sache	return (0);
11921308Sache
12021308Sache      _rl_doing_an_undo = 1;
12121308Sache
12221308Sache      /* To better support vi-mode, a start or end value of -1 means
12321308Sache	 rl_point, and a value of -2 means rl_end. */
12421308Sache      if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
12521308Sache	{
12621308Sache	  start = TRANS (rl_undo_list->start);
12721308Sache	  end = TRANS (rl_undo_list->end);
12821308Sache	}
12921308Sache
13021308Sache      switch (rl_undo_list->what)
13121308Sache	{
13221308Sache	/* Undoing deletes means inserting some text. */
13321308Sache	case UNDO_DELETE:
13421308Sache	  rl_point = start;
13521308Sache	  rl_insert_text (rl_undo_list->text);
13621308Sache	  free (rl_undo_list->text);
13721308Sache	  break;
13821308Sache
13921308Sache	/* Undoing inserts means deleting some text. */
14021308Sache	case UNDO_INSERT:
14121308Sache	  rl_delete_text (start, end);
14221308Sache	  rl_point = start;
14321308Sache	  break;
14421308Sache
14521308Sache	/* Undoing an END means undoing everything 'til we get to a BEGIN. */
14621308Sache	case UNDO_END:
14721308Sache	  waiting_for_begin++;
14821308Sache	  break;
14921308Sache
15021308Sache	/* Undoing a BEGIN means that we are done with this group. */
15121308Sache	case UNDO_BEGIN:
15221308Sache	  if (waiting_for_begin)
15321308Sache	    waiting_for_begin--;
15421308Sache	  else
15521308Sache	    ding ();
15621308Sache	  break;
15721308Sache	}
15821308Sache
15921308Sache      _rl_doing_an_undo = 0;
16021308Sache
16121308Sache      release = rl_undo_list;
16221308Sache      rl_undo_list = rl_undo_list->next;
16321308Sache      free (release);
16421308Sache    }
16521308Sache  while (waiting_for_begin);
16621308Sache
16721308Sache  return (1);
16821308Sache}
16921308Sache#undef TRANS
17021308Sache
17121308Sacheint
17221308Sache_rl_fix_last_undo_of_type (type, start, end)
17321308Sache     int type, start, end;
17421308Sache{
17521308Sache  UNDO_LIST *rl;
17621308Sache
17721308Sache  for (rl = rl_undo_list; rl; rl = rl->next)
17821308Sache    {
17921308Sache      if (rl->what == type)
18021308Sache	{
18121308Sache	  rl->start = start;
18221308Sache	  rl->end = end;
18321308Sache	  return 0;
18421308Sache	}
18521308Sache    }
18621308Sache  return 1;
18721308Sache}
18821308Sache
18921308Sache/* Begin a group.  Subsequent undos are undone as an atomic operation. */
19021308Sacheint
19121308Sacherl_begin_undo_group ()
19221308Sache{
19321308Sache  rl_add_undo (UNDO_BEGIN, 0, 0, 0);
19421308Sache  _rl_undo_group_level++;
19521308Sache  return 0;
19621308Sache}
19721308Sache
19821308Sache/* End an undo group started with rl_begin_undo_group (). */
19921308Sacheint
20021308Sacherl_end_undo_group ()
20121308Sache{
20221308Sache  rl_add_undo (UNDO_END, 0, 0, 0);
20321308Sache  _rl_undo_group_level--;
20421308Sache  return 0;
20521308Sache}
20621308Sache
20721308Sache/* Save an undo entry for the text from START to END. */
20821308Sacheint
20921308Sacherl_modifying (start, end)
21021308Sache     int start, end;
21121308Sache{
21221308Sache  if (start > end)
21321308Sache    {
21421308Sache      SWAP (start, end);
21521308Sache    }
21621308Sache
21721308Sache  if (start != end)
21821308Sache    {
21921308Sache      char *temp = rl_copy_text (start, end);
22021308Sache      rl_begin_undo_group ();
22121308Sache      rl_add_undo (UNDO_DELETE, start, end, temp);
22221308Sache      rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
22321308Sache      rl_end_undo_group ();
22421308Sache    }
22521308Sache  return 0;
22621308Sache}
22721308Sache
22821308Sache/* Revert the current line to its previous state. */
22921308Sacheint
23021308Sacherl_revert_line (count, key)
23121308Sache     int count, key;
23221308Sache{
23321308Sache  if (!rl_undo_list)
23421308Sache    ding ();
23521308Sache  else
23621308Sache    {
23721308Sache      while (rl_undo_list)
23821308Sache	rl_do_undo ();
23921308Sache    }
24021308Sache  return 0;
24121308Sache}
24221308Sache
24321308Sache/* Do some undoing of things that were done. */
24421308Sacheint
24521308Sacherl_undo_command (count, key)
24621308Sache     int count, key;
24721308Sache{
24821308Sache  if (count < 0)
24921308Sache    return 0;	/* Nothing to do. */
25021308Sache
25121308Sache  while (count)
25221308Sache    {
25321308Sache      if (rl_do_undo ())
25421308Sache	count--;
25521308Sache      else
25621308Sache	{
25721308Sache	  ding ();
25821308Sache	  break;
25921308Sache	}
26021308Sache    }
26121308Sache  return 0;
26221308Sache}
263