undo.c revision 157184
1652Sjkh/* readline.c -- a general facility for reading lines of input
233473Sscrappy   with emacs style editing and completion. */
333473Sscrappy
4652Sjkh/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
533473Sscrappy
6652Sjkh   This file is part of the GNU Readline Library, a library for
7652Sjkh   reading lines of text with interactive input and history editing.
8652Sjkh
9652Sjkh   The GNU Readline Library is free software; you can redistribute it
10652Sjkh   and/or modify it under the terms of the GNU General Public License
11652Sjkh   as published by the Free Software Foundation; either version 2, or
1233473Sscrappy   (at your option) any later version.
1333473Sscrappy
1433473Sscrappy   The GNU Readline Library is distributed in the hope that it will be
1533473Sscrappy   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16652Sjkh   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1733473Sscrappy   GNU General Public License for more details.
1833473Sscrappy
1933473Sscrappy   The GNU General Public License is often shipped with GNU software, and
2033473Sscrappy   is generally kept in a file called COPYING or LICENSE.  If you do not
2133473Sscrappy   have a copy of the license, write to the Free Software Foundation,
2233473Sscrappy   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
2333473Sscrappy#define READLINE_LIBRARY
2433473Sscrappy
2533473Sscrappy#if defined (HAVE_CONFIG_H)
2633473Sscrappy#  include <config.h>
2733473Sscrappy#endif
2833473Sscrappy
2950734Speter#include <sys/types.h>
3050734Speter
31652Sjkh#if defined (HAVE_UNISTD_H)
32652Sjkh#  include <unistd.h>           /* for _POSIX_VERSION */
3350906Sdfr#endif /* HAVE_UNISTD_H */
3450906Sdfr
359750Sjkh#if defined (HAVE_STDLIB_H)
36652Sjkh#  include <stdlib.h>
379750Sjkh#else
3813765Smpp#  include "ansi_stdlib.h"
39652Sjkh#endif /* HAVE_STDLIB_H */
40652Sjkh
41652Sjkh#include <stdio.h>
423256Sswallace
4330866Smarkm/* System-specific feature definitions and include files. */
4430866Smarkm#include "rldefs.h"
4530866Smarkm
4630866Smarkm/* Some standard library routines. */
4730866Smarkm#include "readline.h"
4830866Smarkm#include "history.h"
4930866Smarkm
5030866Smarkm#include "rlprivate.h"
5130866Smarkm#include "xmalloc.h"
52652Sjkh
53652Sjkh/* Non-zero tells rl_delete_text and rl_insert_text to not add to
5433530Sscrappy   the undo list. */
5533530Sscrappyint _rl_doing_an_undo = 0;
5633530Sscrappy
5733530Sscrappy/* How many unclosed undo groups we currently have. */
5833530Sscrappyint _rl_undo_group_level = 0;
5933530Sscrappy
6033530Sscrappy/* The current undo list for THE_LINE. */
6133530SscrappyUNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
6233530Sscrappy
6333530Sscrappy/* **************************************************************** */
6433530Sscrappy/*								    */
6533530Sscrappy/*			Undo, and Undoing			    */
6633530Sscrappy/*								    */
6733530Sscrappy/* **************************************************************** */
6833530Sscrappy
6933530Sscrappy/* Remember how to undo something.  Concatenate some undos if that
7033530Sscrappy   seems right. */
7133530Sscrappyvoid
7233530Sscrappyrl_add_undo (what, start, end, text)
7333530Sscrappy     enum undo_code what;
7433530Sscrappy     int start, end;
7533530Sscrappy     char *text;
7633530Sscrappy{
7733530Sscrappy  UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
7833530Sscrappy  temp->what = what;
7933530Sscrappy  temp->start = start;
8033530Sscrappy  temp->end = end;
8133530Sscrappy  temp->text = text;
8233530Sscrappy  temp->next = rl_undo_list;
8333530Sscrappy  rl_undo_list = temp;
8433530Sscrappy}
8533530Sscrappy
8633530Sscrappy/* Free the existing undo list. */
8733530Sscrappyvoid
8833530Sscrappyrl_free_undo_list ()
8933530Sscrappy{
9033530Sscrappy  while (rl_undo_list)
9133530Sscrappy    {
9233530Sscrappy      UNDO_LIST *release = rl_undo_list;
9345240Skato      rl_undo_list = rl_undo_list->next;
9462947Stanimura
9562947Stanimura      if (release->what == UNDO_DELETE)
9633530Sscrappy	free (release->text);
9733473Sscrappy
9833473Sscrappy      free (release);
9933473Sscrappy    }
10033473Sscrappy  rl_undo_list = (UNDO_LIST *)NULL;
101652Sjkh}
102652Sjkh
10333473Sscrappy/* Undo the next thing in the list.  Return 0 if there
10433473Sscrappy   is nothing to undo, or non-zero if there was. */
10533473Sscrappyint
10633473Sscrappyrl_do_undo ()
10733473Sscrappy{
108652Sjkh  UNDO_LIST *release;
109652Sjkh  int waiting_for_begin, start, end;
11033473Sscrappy
11133473Sscrappy#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
11233473Sscrappy
11333473Sscrappy  start = end = waiting_for_begin = 0;
11433473Sscrappy  do
11533473Sscrappy    {
11633473Sscrappy      if (!rl_undo_list)
11733473Sscrappy	return (0);
11833473Sscrappy
11933473Sscrappy      _rl_doing_an_undo = 1;
12033473Sscrappy      RL_SETSTATE(RL_STATE_UNDOING);
12133473Sscrappy
12233473Sscrappy      /* To better support vi-mode, a start or end value of -1 means
12333473Sscrappy	 rl_point, and a value of -2 means rl_end. */
12433473Sscrappy      if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
12533473Sscrappy	{
12633473Sscrappy	  start = TRANS (rl_undo_list->start);
12733473Sscrappy	  end = TRANS (rl_undo_list->end);
12833473Sscrappy	}
12933473Sscrappy
13033473Sscrappy      switch (rl_undo_list->what)
13133473Sscrappy	{
13233473Sscrappy	/* Undoing deletes means inserting some text. */
133652Sjkh	case UNDO_DELETE:
13430866Smarkm	  rl_point = start;
13533473Sscrappy	  rl_insert_text (rl_undo_list->text);
13633473Sscrappy	  free (rl_undo_list->text);
13733473Sscrappy	  break;
13833473Sscrappy
13933473Sscrappy	/* Undoing inserts means deleting some text. */
14033473Sscrappy	case UNDO_INSERT:
14133473Sscrappy	  rl_delete_text (start, end);
14233473Sscrappy	  rl_point = start;
14333473Sscrappy	  break;
14433473Sscrappy
14533473Sscrappy	/* Undoing an END means undoing everything 'til we get to a BEGIN. */
14633473Sscrappy	case UNDO_END:
14733473Sscrappy	  waiting_for_begin++;
14833473Sscrappy	  break;
14933473Sscrappy
15033473Sscrappy	/* Undoing a BEGIN means that we are done with this group. */
15133473Sscrappy	case UNDO_BEGIN:
15233473Sscrappy	  if (waiting_for_begin)
15333473Sscrappy	    waiting_for_begin--;
15433473Sscrappy	  else
15533473Sscrappy	    rl_ding ();
15633473Sscrappy	  break;
15733473Sscrappy	}
15833473Sscrappy
15933473Sscrappy      _rl_doing_an_undo = 0;
16033473Sscrappy      RL_UNSETSTATE(RL_STATE_UNDOING);
16133473Sscrappy
16233473Sscrappy      release = rl_undo_list;
16333473Sscrappy      rl_undo_list = rl_undo_list->next;
16433473Sscrappy      free (release);
16533473Sscrappy    }
16633473Sscrappy  while (waiting_for_begin);
16733473Sscrappy
16833473Sscrappy  return (1);
16933473Sscrappy}
17033473Sscrappy#undef TRANS
17133473Sscrappy
17233473Sscrappyint
17333473Sscrappy_rl_fix_last_undo_of_type (type, start, end)
17433473Sscrappy     int type, start, end;
17533473Sscrappy{
17633473Sscrappy  UNDO_LIST *rl;
17733473Sscrappy
17833473Sscrappy  for (rl = rl_undo_list; rl; rl = rl->next)
17933473Sscrappy    {
18033473Sscrappy      if (rl->what == type)
18133473Sscrappy	{
18233473Sscrappy	  rl->start = start;
18333473Sscrappy	  rl->end = end;
18433473Sscrappy	  return 0;
18533473Sscrappy	}
18633473Sscrappy    }
18733473Sscrappy  return 1;
18833473Sscrappy}
18933473Sscrappy
19033473Sscrappy/* Begin a group.  Subsequent undos are undone as an atomic operation. */
19133473Sscrappyint
19233473Sscrappyrl_begin_undo_group ()
19333473Sscrappy{
19433473Sscrappy  rl_add_undo (UNDO_BEGIN, 0, 0, 0);
19533473Sscrappy  _rl_undo_group_level++;
19633473Sscrappy  return 0;
19733473Sscrappy}
19833473Sscrappy
19933473Sscrappy/* End an undo group started with rl_begin_undo_group (). */
20033473Sscrappyint
20133473Sscrappyrl_end_undo_group ()
20233473Sscrappy{
20333473Sscrappy  rl_add_undo (UNDO_END, 0, 0, 0);
20433473Sscrappy  _rl_undo_group_level--;
20533473Sscrappy  return 0;
20633473Sscrappy}
20733473Sscrappy
20833473Sscrappy/* Save an undo entry for the text from START to END. */
20933473Sscrappyint
21033473Sscrappyrl_modifying (start, end)
21133473Sscrappy     int start, end;
21233473Sscrappy{
21333473Sscrappy  if (start > end)
21433473Sscrappy    {
21533473Sscrappy      SWAP (start, end);
21633473Sscrappy    }
21733473Sscrappy
21833473Sscrappy  if (start != end)
21933473Sscrappy    {
22033473Sscrappy      char *temp = rl_copy_text (start, end);
22133473Sscrappy      rl_begin_undo_group ();
22233473Sscrappy      rl_add_undo (UNDO_DELETE, start, end, temp);
22333473Sscrappy      rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
22433473Sscrappy      rl_end_undo_group ();
22533473Sscrappy    }
22633473Sscrappy  return 0;
22733473Sscrappy}
22833473Sscrappy
22933473Sscrappy/* Revert the current line to its previous state. */
23033473Sscrappyint
23133473Sscrappyrl_revert_line (count, key)
23233473Sscrappy     int count, key;
23333473Sscrappy{
23433473Sscrappy  if (!rl_undo_list)
23533473Sscrappy    rl_ding ();
23633473Sscrappy  else
23733473Sscrappy    {
23833473Sscrappy      while (rl_undo_list)
23933473Sscrappy	rl_do_undo ();
24033473Sscrappy#if defined (VI_MODE)
24133473Sscrappy      if (rl_editing_mode == vi_mode)
24233473Sscrappy	rl_point = rl_mark = 0;		/* rl_end should be set correctly */
24333473Sscrappy#endif
24433473Sscrappy    }
24533473Sscrappy
24633473Sscrappy  return 0;
24733473Sscrappy}
24833473Sscrappy
249652Sjkh/* Do some undoing of things that were done. */
250652Sjkhint
251652Sjkhrl_undo_command (count, key)
25233473Sscrappy     int count, key;
25333473Sscrappy{
25433473Sscrappy  if (count < 0)
25533473Sscrappy    return 0;	/* Nothing to do. */
25633473Sscrappy
25733473Sscrappy  while (count)
25833473Sscrappy    {
25933473Sscrappy      if (rl_do_undo ())
26033473Sscrappy	count--;
26133473Sscrappy      else
26233473Sscrappy	{
26333473Sscrappy	  rl_ding ();
26433473Sscrappy	  break;
26533473Sscrappy	}
26633473Sscrappy    }
26733473Sscrappy  return 0;
26833473Sscrappy}
26933473Sscrappy