Move readline to the readline/readline subdirectory
[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;
199 rl_insert_text (rl_undo_list->text);
cc88a640 200 xfree (rl_undo_list->text);
d60d9f65
SS
201 break;
202
203 /* Undoing inserts means deleting some text. */
204 case UNDO_INSERT:
205 rl_delete_text (start, end);
206 rl_point = start;
207 break;
208
209 /* Undoing an END means undoing everything 'til we get to a BEGIN. */
210 case UNDO_END:
211 waiting_for_begin++;
212 break;
213
214 /* Undoing a BEGIN means that we are done with this group. */
215 case UNDO_BEGIN:
216 if (waiting_for_begin)
217 waiting_for_begin--;
218 else
9255ee31 219 rl_ding ();
d60d9f65
SS
220 break;
221 }
222
223 _rl_doing_an_undo = 0;
9255ee31 224 RL_UNSETSTATE(RL_STATE_UNDOING);
d60d9f65
SS
225
226 release = rl_undo_list;
227 rl_undo_list = rl_undo_list->next;
cb41b9e7 228 release->next = 0; /* XXX */
775e241e
TT
229
230 /* If we are editing a history entry, make sure the change is replicated
231 in the history entry's line */
232 cur = current_history ();
233 if (cur && cur->data && (UNDO_LIST *)cur->data == release)
234 {
235 temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list);
236 xfree (temp->line);
237 FREE (temp->timestamp);
238 xfree (temp);
239 }
240
cb41b9e7 241 /* Make sure there aren't any history entries with that undo list */
775e241e 242 _hs_replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
cc88a640 243
cb41b9e7
TT
244 /* And make sure this list isn't anywhere in the saved line for history */
245 if (_rl_saved_line_for_history && _rl_saved_line_for_history->data)
246 {
247 /* Brute force; no finesse here */
248 search = (UNDO_LIST *)_rl_saved_line_for_history->data;
249 if (search == release)
250 _rl_saved_line_for_history->data = rl_undo_list;
251 else
252 {
253 while (search->next)
254 {
255 if (search->next == release)
256 {
257 search->next = rl_undo_list;
258 break;
259 }
260 search = search->next;
261 }
262 }
263 }
264
cc88a640 265 xfree (release);
d60d9f65
SS
266 }
267 while (waiting_for_begin);
268
269 return (1);
270}
271#undef TRANS
272
273int
cb41b9e7 274_rl_fix_last_undo_of_type (int type, int start, int end)
d60d9f65
SS
275{
276 UNDO_LIST *rl;
277
278 for (rl = rl_undo_list; rl; rl = rl->next)
279 {
280 if (rl->what == type)
281 {
282 rl->start = start;
283 rl->end = end;
284 return 0;
285 }
286 }
287 return 1;
288}
289
290/* Begin a group. Subsequent undos are undone as an atomic operation. */
291int
cb41b9e7 292rl_begin_undo_group (void)
d60d9f65
SS
293{
294 rl_add_undo (UNDO_BEGIN, 0, 0, 0);
295 _rl_undo_group_level++;
296 return 0;
297}
298
299/* End an undo group started with rl_begin_undo_group (). */
300int
cb41b9e7 301rl_end_undo_group (void)
d60d9f65
SS
302{
303 rl_add_undo (UNDO_END, 0, 0, 0);
304 _rl_undo_group_level--;
305 return 0;
306}
307
308/* Save an undo entry for the text from START to END. */
309int
cb41b9e7 310rl_modifying (int start, int end)
d60d9f65
SS
311{
312 if (start > end)
313 {
314 SWAP (start, end);
315 }
316
317 if (start != end)
318 {
319 char *temp = rl_copy_text (start, end);
320 rl_begin_undo_group ();
321 rl_add_undo (UNDO_DELETE, start, end, temp);
322 rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
323 rl_end_undo_group ();
324 }
325 return 0;
326}
327
328/* Revert the current line to its previous state. */
329int
cb41b9e7 330rl_revert_line (int count, int key)
d60d9f65 331{
cc88a640 332 if (rl_undo_list == 0)
9255ee31 333 rl_ding ();
d60d9f65
SS
334 else
335 {
336 while (rl_undo_list)
337 rl_do_undo ();
5bdf8622
DJ
338#if defined (VI_MODE)
339 if (rl_editing_mode == vi_mode)
340 rl_point = rl_mark = 0; /* rl_end should be set correctly */
341#endif
d60d9f65 342 }
5bdf8622 343
d60d9f65
SS
344 return 0;
345}
346
347/* Do some undoing of things that were done. */
348int
cb41b9e7 349rl_undo_command (int count, int key)
d60d9f65
SS
350{
351 if (count < 0)
352 return 0; /* Nothing to do. */
353
354 while (count)
355 {
356 if (rl_do_undo ())
357 count--;
358 else
359 {
9255ee31 360 rl_ding ();
d60d9f65
SS
361 break;
362 }
363 }
364 return 0;
365}
This page took 0.912163 seconds and 4 git commands to generate.