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