Import GNU Readline 8.1
[deliverable/binutils-gdb.git] / readline / readline / undo.c
CommitLineData
775e241e 1/* undo.c - manage list of changes to lines, offering opportunity to undo them */
d60d9f65 2
cb41b9e7 3/* Copyright (C) 1987-2017 Free Software Foundation, Inc.
d60d9f65 4
cc88a640
JK
5 This file is part of the GNU Readline Library (Readline), a library
6 for reading lines of text with interactive input and history editing.
d60d9f65 7
cc88a640
JK
8 Readline is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
d60d9f65
SS
11 (at your option) any later version.
12
cc88a640
JK
13 Readline is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
d60d9f65
SS
16 GNU General Public License for more details.
17
cc88a640
JK
18 You should have received a copy of the GNU General Public License
19 along with Readline. If not, see <http://www.gnu.org/licenses/>.
20*/
21
d60d9f65
SS
22#define READLINE_LIBRARY
23
24#if defined (HAVE_CONFIG_H)
25# include <config.h>
26#endif
27
28#include <sys/types.h>
29
30#if defined (HAVE_UNISTD_H)
31# include <unistd.h> /* for _POSIX_VERSION */
32#endif /* HAVE_UNISTD_H */
33
34#if defined (HAVE_STDLIB_H)
35# include <stdlib.h>
36#else
37# include "ansi_stdlib.h"
38#endif /* HAVE_STDLIB_H */
39
40#include <stdio.h>
41
42/* System-specific feature definitions and include files. */
43#include "rldefs.h"
44
45/* Some standard library routines. */
46#include "readline.h"
47#include "history.h"
48
1b17e766 49#include "rlprivate.h"
9255ee31 50#include "xmalloc.h"
d60d9f65 51
775e241e 52extern void _hs_replace_history_data PARAMS((int, histdata_t *, histdata_t *));
cc88a640 53
cb41b9e7
TT
54extern HIST_ENTRY *_rl_saved_line_for_history;
55
d60d9f65
SS
56/* Non-zero tells rl_delete_text and rl_insert_text to not add to
57 the undo list. */
58int _rl_doing_an_undo = 0;
59
60/* How many unclosed undo groups we currently have. */
61int _rl_undo_group_level = 0;
62
63/* The current undo list for THE_LINE. */
64UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
65
66/* **************************************************************** */
67/* */
68/* Undo, and Undoing */
69/* */
70/* **************************************************************** */
71
cc88a640 72static UNDO_LIST *
cb41b9e7 73alloc_undo_entry (enum undo_code what, int start, int end, char *text)
d60d9f65 74{
cc88a640
JK
75 UNDO_LIST *temp;
76
77 temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
d60d9f65
SS
78 temp->what = what;
79 temp->start = start;
80 temp->end = end;
81 temp->text = text;
cc88a640
JK
82
83 temp->next = (UNDO_LIST *)NULL;
84 return temp;
85}
86
87/* Remember how to undo something. Concatenate some undos if that
88 seems right. */
89void
cb41b9e7 90rl_add_undo (enum undo_code what, int start, int end, char *text)
cc88a640
JK
91{
92 UNDO_LIST *temp;
93
94 temp = alloc_undo_entry (what, start, end, text);
d60d9f65
SS
95 temp->next = rl_undo_list;
96 rl_undo_list = temp;
97}
98
775e241e 99/* Free an UNDO_LIST */
d60d9f65 100void
cb41b9e7 101_rl_free_undo_list (UNDO_LIST *ul)
d60d9f65 102{
775e241e 103 UNDO_LIST *release;
cc88a640 104
775e241e 105 while (ul)
d60d9f65 106 {
775e241e
TT
107 release = ul;
108 ul = ul->next;
d60d9f65
SS
109
110 if (release->what == UNDO_DELETE)
cc88a640 111 xfree (release->text);
d60d9f65 112
cc88a640 113 xfree (release);
d60d9f65 114 }
775e241e
TT
115}
116
117/* Free the existing undo list. */
118void
cb41b9e7 119rl_free_undo_list (void)
775e241e
TT
120{
121 UNDO_LIST *release, *orig_list;
122
123 orig_list = rl_undo_list;
124 _rl_free_undo_list (rl_undo_list);
d60d9f65 125 rl_undo_list = (UNDO_LIST *)NULL;
775e241e 126 _hs_replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL);
cc88a640
JK
127}
128
129UNDO_LIST *
cb41b9e7 130_rl_copy_undo_entry (UNDO_LIST *entry)
cc88a640
JK
131{
132 UNDO_LIST *new;
133
134 new = alloc_undo_entry (entry->what, entry->start, entry->end, (char *)NULL);
135 new->text = entry->text ? savestring (entry->text) : 0;
136 return new;
137}
138
139UNDO_LIST *
cb41b9e7 140_rl_copy_undo_list (UNDO_LIST *head)
cc88a640
JK
141{
142 UNDO_LIST *list, *new, *roving, *c;
143
144 if (head == 0)
145 return head;
146
147 list = head;
148 new = 0;
149 while (list)
150 {
151 c = _rl_copy_undo_entry (list);
152 if (new == 0)
153 roving = new = c;
154 else
155 {
156 roving->next = c;
157 roving = roving->next;
158 }
159 list = list->next;
160 }
161
162 roving->next = 0;
163 return new;
d60d9f65
SS
164}
165
166/* Undo the next thing in the list. Return 0 if there
167 is nothing to undo, or non-zero if there was. */
168int
cb41b9e7 169rl_do_undo (void)
d60d9f65 170{
cb41b9e7 171 UNDO_LIST *release, *search;
9255ee31 172 int waiting_for_begin, start, end;
775e241e 173 HIST_ENTRY *cur, *temp;
d60d9f65
SS
174
175#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
176
9255ee31 177 start = end = waiting_for_begin = 0;
d60d9f65
SS
178 do
179 {
cc88a640 180 if (rl_undo_list == 0)
d60d9f65
SS
181 return (0);
182
183 _rl_doing_an_undo = 1;
9255ee31 184 RL_SETSTATE(RL_STATE_UNDOING);
d60d9f65
SS
185
186 /* To better support vi-mode, a start or end value of -1 means
187 rl_point, and a value of -2 means rl_end. */
188 if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
189 {
190 start = TRANS (rl_undo_list->start);
191 end = TRANS (rl_undo_list->end);
192 }
193
194 switch (rl_undo_list->what)
195 {
196 /* Undoing deletes means inserting some text. */
197 case UNDO_DELETE:
198 rl_point = start;
b4f26d54 199 _rl_fix_point (1);
d60d9f65 200 rl_insert_text (rl_undo_list->text);
cc88a640 201 xfree (rl_undo_list->text);
d60d9f65
SS
202 break;
203
204 /* Undoing inserts means deleting some text. */
205 case UNDO_INSERT:
206 rl_delete_text (start, end);
207 rl_point = start;
b4f26d54 208 _rl_fix_point (1);
d60d9f65
SS
209 break;
210
211 /* Undoing an END means undoing everything 'til we get to a BEGIN. */
212 case UNDO_END:
213 waiting_for_begin++;
214 break;
215
216 /* Undoing a BEGIN means that we are done with this group. */
217 case UNDO_BEGIN:
218 if (waiting_for_begin)
219 waiting_for_begin--;
220 else
9255ee31 221 rl_ding ();
d60d9f65
SS
222 break;
223 }
224
225 _rl_doing_an_undo = 0;
9255ee31 226 RL_UNSETSTATE(RL_STATE_UNDOING);
d60d9f65
SS
227
228 release = rl_undo_list;
229 rl_undo_list = rl_undo_list->next;
cb41b9e7 230 release->next = 0; /* XXX */
775e241e
TT
231
232 /* If we are editing a history entry, make sure the change is replicated
233 in the history entry's line */
234 cur = current_history ();
235 if (cur && cur->data && (UNDO_LIST *)cur->data == release)
236 {
237 temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list);
238 xfree (temp->line);
239 FREE (temp->timestamp);
240 xfree (temp);
241 }
242
cb41b9e7 243 /* Make sure there aren't any history entries with that undo list */
775e241e 244 _hs_replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
cc88a640 245
cb41b9e7
TT
246 /* And make sure this list isn't anywhere in the saved line for history */
247 if (_rl_saved_line_for_history && _rl_saved_line_for_history->data)
248 {
249 /* Brute force; no finesse here */
250 search = (UNDO_LIST *)_rl_saved_line_for_history->data;
251 if (search == release)
252 _rl_saved_line_for_history->data = rl_undo_list;
253 else
254 {
255 while (search->next)
256 {
257 if (search->next == release)
258 {
259 search->next = rl_undo_list;
260 break;
261 }
262 search = search->next;
263 }
264 }
265 }
266
cc88a640 267 xfree (release);
d60d9f65
SS
268 }
269 while (waiting_for_begin);
270
271 return (1);
272}
273#undef TRANS
274
275int
cb41b9e7 276_rl_fix_last_undo_of_type (int type, int start, int end)
d60d9f65
SS
277{
278 UNDO_LIST *rl;
279
280 for (rl = rl_undo_list; rl; rl = rl->next)
281 {
282 if (rl->what == type)
283 {
284 rl->start = start;
285 rl->end = end;
286 return 0;
287 }
288 }
289 return 1;
290}
291
292/* Begin a group. Subsequent undos are undone as an atomic operation. */
293int
cb41b9e7 294rl_begin_undo_group (void)
d60d9f65
SS
295{
296 rl_add_undo (UNDO_BEGIN, 0, 0, 0);
297 _rl_undo_group_level++;
298 return 0;
299}
300
301/* End an undo group started with rl_begin_undo_group (). */
302int
cb41b9e7 303rl_end_undo_group (void)
d60d9f65
SS
304{
305 rl_add_undo (UNDO_END, 0, 0, 0);
306 _rl_undo_group_level--;
307 return 0;
308}
309
310/* Save an undo entry for the text from START to END. */
311int
cb41b9e7 312rl_modifying (int start, int end)
d60d9f65
SS
313{
314 if (start > end)
315 {
316 SWAP (start, end);
317 }
318
319 if (start != end)
320 {
321 char *temp = rl_copy_text (start, end);
322 rl_begin_undo_group ();
323 rl_add_undo (UNDO_DELETE, start, end, temp);
324 rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
325 rl_end_undo_group ();
326 }
327 return 0;
328}
329
330/* Revert the current line to its previous state. */
331int
cb41b9e7 332rl_revert_line (int count, int key)
d60d9f65 333{
cc88a640 334 if (rl_undo_list == 0)
9255ee31 335 rl_ding ();
d60d9f65
SS
336 else
337 {
338 while (rl_undo_list)
339 rl_do_undo ();
5bdf8622
DJ
340#if defined (VI_MODE)
341 if (rl_editing_mode == vi_mode)
342 rl_point = rl_mark = 0; /* rl_end should be set correctly */
343#endif
d60d9f65 344 }
5bdf8622 345
d60d9f65
SS
346 return 0;
347}
348
349/* Do some undoing of things that were done. */
350int
cb41b9e7 351rl_undo_command (int count, int key)
d60d9f65
SS
352{
353 if (count < 0)
354 return 0; /* Nothing to do. */
355
356 while (count)
357 {
358 if (rl_do_undo ())
359 count--;
360 else
361 {
9255ee31 362 rl_ding ();
d60d9f65
SS
363 break;
364 }
365 }
366 return 0;
367}
This page took 1.321284 seconds and 4 git commands to generate.