]> git.ipfire.org Git - thirdparty/bash.git/blame - lib/readline/undo.c
final set of ANSI C changes
[thirdparty/bash.git] / lib / readline / undo.c
CommitLineData
d345f817 1/* undo.c - manage list of changes to lines, offering opportunity to undo them */
ccc6cda3 2
38881450 3/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
ccc6cda3 4
2e4498b3
CR
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.
ccc6cda3 7
2e4498b3
CR
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
ccc6cda3
JA
11 (at your option) any later version.
12
2e4498b3
CR
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
ccc6cda3
JA
16 GNU General Public License for more details.
17
2e4498b3
CR
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
ccc6cda3
JA
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
ccc6cda3
JA
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
bb70624e 49#include "rlprivate.h"
f73dda09 50#include "xmalloc.h"
bb70624e 51
38881450 52#include "histlib.h"
9282e182 53
ccc6cda3
JA
54/* Non-zero tells rl_delete_text and rl_insert_text to not add to
55 the undo list. */
56int _rl_doing_an_undo = 0;
57
58/* How many unclosed undo groups we currently have. */
59int _rl_undo_group_level = 0;
60
61/* The current undo list for THE_LINE. */
62UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
63
64/* **************************************************************** */
65/* */
66/* Undo, and Undoing */
67/* */
68/* **************************************************************** */
69
d3ad40de 70static UNDO_LIST *
514049fa 71alloc_undo_entry (enum undo_code what, int start, int end, char *text)
ccb43410 72{
d3ad40de
CR
73 UNDO_LIST *temp;
74
75 temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
28157acd
CR
76 temp->what = what;
77 temp->start = start;
78 temp->end = end;
79 temp->text = text;
d3ad40de
CR
80
81 temp->next = (UNDO_LIST *)NULL;
82 return temp;
83}
84
85/* Remember how to undo something. Concatenate some undos if that
86 seems right. */
87void
514049fa 88rl_add_undo (enum undo_code what, int start, int end, char *text)
d3ad40de
CR
89{
90 UNDO_LIST *temp;
91
92 temp = alloc_undo_entry (what, start, end, text);
ccc6cda3
JA
93 temp->next = rl_undo_list;
94 rl_undo_list = temp;
95}
96
abe2eb5b 97/* Free an UNDO_LIST */
ccc6cda3 98void
514049fa 99_rl_free_undo_list (UNDO_LIST *ul)
ccc6cda3 100{
abe2eb5b 101 UNDO_LIST *release;
d3ad40de 102
abe2eb5b 103 while (ul)
ccc6cda3 104 {
abe2eb5b
CR
105 release = ul;
106 ul = ul->next;
ccc6cda3
JA
107
108 if (release->what == UNDO_DELETE)
a927e029 109 xfree (release->text);
ccc6cda3 110
d3ad40de 111 xfree (release);
ccc6cda3 112 }
abe2eb5b
CR
113}
114
115/* Free the existing undo list. */
116void
514049fa 117rl_free_undo_list (void)
abe2eb5b 118{
2e725f73 119 UNDO_LIST *orig_list;
abe2eb5b
CR
120
121 orig_list = rl_undo_list;
122 _rl_free_undo_list (rl_undo_list);
ccc6cda3 123 rl_undo_list = (UNDO_LIST *)NULL;
58a975cb 124 _hs_replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL);
d3ad40de
CR
125}
126
127UNDO_LIST *
514049fa 128_rl_copy_undo_entry (UNDO_LIST *entry)
d3ad40de
CR
129{
130 UNDO_LIST *new;
131
132 new = alloc_undo_entry (entry->what, entry->start, entry->end, (char *)NULL);
133 new->text = entry->text ? savestring (entry->text) : 0;
134 return new;
135}
136
137UNDO_LIST *
514049fa 138_rl_copy_undo_list (UNDO_LIST *head)
d3ad40de
CR
139{
140 UNDO_LIST *list, *new, *roving, *c;
141
824dfe68
CR
142 if (head == 0)
143 return head;
144
d3ad40de
CR
145 list = head;
146 new = 0;
147 while (list)
148 {
149 c = _rl_copy_undo_entry (list);
150 if (new == 0)
151 roving = new = c;
152 else
153 {
154 roving->next = c;
155 roving = roving->next;
156 }
157 list = list->next;
158 }
159
160 roving->next = 0;
161 return new;
ccc6cda3
JA
162}
163
164/* Undo the next thing in the list. Return 0 if there
165 is nothing to undo, or non-zero if there was. */
166int
514049fa 167rl_do_undo (void)
ccc6cda3 168{
9282e182 169 UNDO_LIST *release, *search;
28ef6c31 170 int waiting_for_begin, start, end;
6e51e0d0 171 HIST_ENTRY *cur, *temp;
ccc6cda3
JA
172
173#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
174
28ef6c31 175 start = end = waiting_for_begin = 0;
ccc6cda3
JA
176 do
177 {
d3ad40de 178 if (rl_undo_list == 0)
ccc6cda3
JA
179 return (0);
180
181 _rl_doing_an_undo = 1;
28ef6c31 182 RL_SETSTATE(RL_STATE_UNDOING);
ccc6cda3
JA
183
184 /* To better support vi-mode, a start or end value of -1 means
185 rl_point, and a value of -2 means rl_end. */
186 if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
187 {
188 start = TRANS (rl_undo_list->start);
189 end = TRANS (rl_undo_list->end);
190 }
191
192 switch (rl_undo_list->what)
193 {
194 /* Undoing deletes means inserting some text. */
195 case UNDO_DELETE:
196 rl_point = start;
8a9718cf 197 _rl_fix_point (1);
ccc6cda3 198 rl_insert_text (rl_undo_list->text);
a927e029 199 xfree (rl_undo_list->text);
ccc6cda3
JA
200 break;
201
202 /* Undoing inserts means deleting some text. */
203 case UNDO_INSERT:
204 rl_delete_text (start, end);
205 rl_point = start;
8a9718cf 206 _rl_fix_point (1);
ccc6cda3
JA
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
28ef6c31 219 rl_ding ();
ccc6cda3
JA
220 break;
221 }
222
223 _rl_doing_an_undo = 0;
28ef6c31 224 RL_UNSETSTATE(RL_STATE_UNDOING);
ccc6cda3
JA
225
226 release = rl_undo_list;
227 rl_undo_list = rl_undo_list->next;
9282e182 228 release->next = 0; /* XXX */
6e51e0d0
CR
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 ();
5f0df7f9 233 if (cur && cur->data && (UNDO_LIST *)cur->data == release)
6e51e0d0
CR
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
9282e182 241 /* Make sure there aren't any history entries with that undo list */
58a975cb 242 _hs_replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
d3ad40de 243
9282e182
CR
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
d3ad40de 265 xfree (release);
ccc6cda3
JA
266 }
267 while (waiting_for_begin);
268
269 return (1);
270}
271#undef TRANS
272
273int
514049fa 274_rl_fix_last_undo_of_type (int type, int start, int end)
ccc6cda3
JA
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
514049fa 292rl_begin_undo_group (void)
ccc6cda3
JA
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
514049fa 301rl_end_undo_group (void)
ccc6cda3
JA
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
514049fa 310rl_modifying (int start, int end)
ccc6cda3
JA
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
514049fa 330rl_revert_line (int count, int key)
ccc6cda3 331{
d3ad40de 332 if (rl_undo_list == 0)
28ef6c31 333 rl_ding ();
ccc6cda3
JA
334 else
335 {
336 while (rl_undo_list)
337 rl_do_undo ();
e225d5a9
CR
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
ccc6cda3 342 }
e225d5a9 343
ccc6cda3
JA
344 return 0;
345}
346
347/* Do some undoing of things that were done. */
348int
514049fa 349rl_undo_command (int count, int key)
ccc6cda3
JA
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 {
28ef6c31 360 rl_ding ();
ccc6cda3
JA
361 break;
362 }
363 }
364 return 0;
365}