xref: /NextBSD/contrib/libreadline/undo.c (revision eb1a5f8de9f7ea602c373a710f531abbf81141c4)
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, 2006 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 2, 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    59 Temple Place, Suite 330, Boston, MA 02111 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 <stdio.h>
42 
43 /* System-specific feature definitions and include files. */
44 #include "rldefs.h"
45 
46 /* Some standard library routines. */
47 #include "readline.h"
48 #include "history.h"
49 
50 #include "rlprivate.h"
51 #include "xmalloc.h"
52 
53 extern void replace_history_data PARAMS((int, histdata_t *, histdata_t *));
54 
55 /* Non-zero tells rl_delete_text and rl_insert_text to not add to
56    the undo list. */
57 int _rl_doing_an_undo = 0;
58 
59 /* How many unclosed undo groups we currently have. */
60 int _rl_undo_group_level = 0;
61 
62 /* The current undo list for THE_LINE. */
63 UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
64 
65 /* **************************************************************** */
66 /*								    */
67 /*			Undo, and Undoing			    */
68 /*								    */
69 /* **************************************************************** */
70 
71 static UNDO_LIST *
alloc_undo_entry(what,start,end,text)72 alloc_undo_entry (what, start, end, text)
73      enum undo_code what;
74      int start, end;
75      char *text;
76 {
77   UNDO_LIST *temp;
78 
79   temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
80   temp->what = what;
81   temp->start = start;
82   temp->end = end;
83   temp->text = text;
84 
85   temp->next = (UNDO_LIST *)NULL;
86   return temp;
87 }
88 
89 /* Remember how to undo something.  Concatenate some undos if that
90    seems right. */
91 void
rl_add_undo(what,start,end,text)92 rl_add_undo (what, start, end, text)
93      enum undo_code what;
94      int start, end;
95      char *text;
96 {
97   UNDO_LIST *temp;
98 
99   temp = alloc_undo_entry (what, start, end, text);
100   temp->next = rl_undo_list;
101   rl_undo_list = temp;
102 }
103 
104 /* Free the existing undo list. */
105 void
rl_free_undo_list()106 rl_free_undo_list ()
107 {
108   UNDO_LIST *release, *orig_list;
109 
110   orig_list = rl_undo_list;
111   while (rl_undo_list)
112     {
113       release = rl_undo_list;
114       rl_undo_list = rl_undo_list->next;
115 
116       if (release->what == UNDO_DELETE)
117 	free (release->text);
118 
119       free (release);
120     }
121   rl_undo_list = (UNDO_LIST *)NULL;
122   replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL);
123 }
124 
125 UNDO_LIST *
_rl_copy_undo_entry(entry)126 _rl_copy_undo_entry (entry)
127      UNDO_LIST *entry;
128 {
129   UNDO_LIST *new;
130 
131   new = alloc_undo_entry (entry->what, entry->start, entry->end, (char *)NULL);
132   new->text = entry->text ? savestring (entry->text) : 0;
133   return new;
134 }
135 
136 UNDO_LIST *
_rl_copy_undo_list(head)137 _rl_copy_undo_list (head)
138      UNDO_LIST *head;
139 {
140   UNDO_LIST *list, *new, *roving, *c;
141 
142   list = head;
143   new = 0;
144   while (list)
145     {
146       c = _rl_copy_undo_entry (list);
147       if (new == 0)
148 	roving = new = c;
149       else
150 	{
151 	  roving->next = c;
152 	  roving = roving->next;
153 	}
154       list = list->next;
155     }
156 
157   roving->next = 0;
158   return new;
159 }
160 
161 /* Undo the next thing in the list.  Return 0 if there
162    is nothing to undo, or non-zero if there was. */
163 int
rl_do_undo()164 rl_do_undo ()
165 {
166   UNDO_LIST *release;
167   int waiting_for_begin, start, end;
168 
169 #define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
170 
171   start = end = waiting_for_begin = 0;
172   do
173     {
174       if (!rl_undo_list)
175 	return (0);
176 
177       _rl_doing_an_undo = 1;
178       RL_SETSTATE(RL_STATE_UNDOING);
179 
180       /* To better support vi-mode, a start or end value of -1 means
181 	 rl_point, and a value of -2 means rl_end. */
182       if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
183 	{
184 	  start = TRANS (rl_undo_list->start);
185 	  end = TRANS (rl_undo_list->end);
186 	}
187 
188       switch (rl_undo_list->what)
189 	{
190 	/* Undoing deletes means inserting some text. */
191 	case UNDO_DELETE:
192 	  rl_point = start;
193 	  rl_insert_text (rl_undo_list->text);
194 	  free (rl_undo_list->text);
195 	  break;
196 
197 	/* Undoing inserts means deleting some text. */
198 	case UNDO_INSERT:
199 	  rl_delete_text (start, end);
200 	  rl_point = start;
201 	  break;
202 
203 	/* Undoing an END means undoing everything 'til we get to a BEGIN. */
204 	case UNDO_END:
205 	  waiting_for_begin++;
206 	  break;
207 
208 	/* Undoing a BEGIN means that we are done with this group. */
209 	case UNDO_BEGIN:
210 	  if (waiting_for_begin)
211 	    waiting_for_begin--;
212 	  else
213 	    rl_ding ();
214 	  break;
215 	}
216 
217       _rl_doing_an_undo = 0;
218       RL_UNSETSTATE(RL_STATE_UNDOING);
219 
220       release = rl_undo_list;
221       rl_undo_list = rl_undo_list->next;
222       replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
223 
224       free (release);
225     }
226   while (waiting_for_begin);
227 
228   return (1);
229 }
230 #undef TRANS
231 
232 int
_rl_fix_last_undo_of_type(type,start,end)233 _rl_fix_last_undo_of_type (type, start, end)
234      int type, start, end;
235 {
236   UNDO_LIST *rl;
237 
238   for (rl = rl_undo_list; rl; rl = rl->next)
239     {
240       if (rl->what == type)
241 	{
242 	  rl->start = start;
243 	  rl->end = end;
244 	  return 0;
245 	}
246     }
247   return 1;
248 }
249 
250 /* Begin a group.  Subsequent undos are undone as an atomic operation. */
251 int
rl_begin_undo_group()252 rl_begin_undo_group ()
253 {
254   rl_add_undo (UNDO_BEGIN, 0, 0, 0);
255   _rl_undo_group_level++;
256   return 0;
257 }
258 
259 /* End an undo group started with rl_begin_undo_group (). */
260 int
rl_end_undo_group()261 rl_end_undo_group ()
262 {
263   rl_add_undo (UNDO_END, 0, 0, 0);
264   _rl_undo_group_level--;
265   return 0;
266 }
267 
268 /* Save an undo entry for the text from START to END. */
269 int
rl_modifying(start,end)270 rl_modifying (start, end)
271      int start, end;
272 {
273   if (start > end)
274     {
275       SWAP (start, end);
276     }
277 
278   if (start != end)
279     {
280       char *temp = rl_copy_text (start, end);
281       rl_begin_undo_group ();
282       rl_add_undo (UNDO_DELETE, start, end, temp);
283       rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
284       rl_end_undo_group ();
285     }
286   return 0;
287 }
288 
289 /* Revert the current line to its previous state. */
290 int
rl_revert_line(count,key)291 rl_revert_line (count, key)
292      int count, key;
293 {
294   if (!rl_undo_list)
295     rl_ding ();
296   else
297     {
298       while (rl_undo_list)
299 	rl_do_undo ();
300 #if defined (VI_MODE)
301       if (rl_editing_mode == vi_mode)
302 	rl_point = rl_mark = 0;		/* rl_end should be set correctly */
303 #endif
304     }
305 
306   return 0;
307 }
308 
309 /* Do some undoing of things that were done. */
310 int
rl_undo_command(count,key)311 rl_undo_command (count, key)
312      int count, key;
313 {
314   if (count < 0)
315     return 0;	/* Nothing to do. */
316 
317   while (count)
318     {
319       if (rl_do_undo ())
320 	count--;
321       else
322 	{
323 	  rl_ding ();
324 	  break;
325 	}
326     }
327   return 0;
328 }
329