Annotation of embedaddon/readline/undo.c, revision 1.1.1.2
1.1.1.2 ! misho 1: /* undo.c - manage list of changes to lines, offering opportunity to undo them */
1.1 misho 2:
1.1.1.2 ! misho 3: /* Copyright (C) 1987-2017 Free Software Foundation, Inc.
1.1 misho 4:
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.
7:
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
11: (at your option) any later version.
12:
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
16: GNU General Public License for more details.
17:
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:
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:
49: #include "rlprivate.h"
50: #include "xmalloc.h"
51:
1.1.1.2 ! misho 52: extern void _hs_replace_history_data PARAMS((int, histdata_t *, histdata_t *));
! 53:
! 54: extern HIST_ENTRY *_rl_saved_line_for_history;
1.1 misho 55:
56: /* Non-zero tells rl_delete_text and rl_insert_text to not add to
57: the undo list. */
58: int _rl_doing_an_undo = 0;
59:
60: /* How many unclosed undo groups we currently have. */
61: int _rl_undo_group_level = 0;
62:
63: /* The current undo list for THE_LINE. */
64: UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
65:
66: /* **************************************************************** */
67: /* */
68: /* Undo, and Undoing */
69: /* */
70: /* **************************************************************** */
71:
72: static UNDO_LIST *
1.1.1.2 ! misho 73: alloc_undo_entry (enum undo_code what, int start, int end, char *text)
1.1 misho 74: {
75: UNDO_LIST *temp;
76:
77: temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
78: temp->what = what;
79: temp->start = start;
80: temp->end = end;
81: temp->text = text;
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. */
89: void
1.1.1.2 ! misho 90: rl_add_undo (enum undo_code what, int start, int end, char *text)
1.1 misho 91: {
92: UNDO_LIST *temp;
93:
94: temp = alloc_undo_entry (what, start, end, text);
95: temp->next = rl_undo_list;
96: rl_undo_list = temp;
97: }
98:
99: /* Free an UNDO_LIST */
100: void
1.1.1.2 ! misho 101: _rl_free_undo_list (UNDO_LIST *ul)
1.1 misho 102: {
103: UNDO_LIST *release;
104:
105: while (ul)
106: {
107: release = ul;
108: ul = ul->next;
109:
110: if (release->what == UNDO_DELETE)
111: xfree (release->text);
112:
113: xfree (release);
114: }
115: }
116:
117: /* Free the existing undo list. */
118: void
1.1.1.2 ! misho 119: rl_free_undo_list (void)
1.1 misho 120: {
121: UNDO_LIST *release, *orig_list;
122:
123: orig_list = rl_undo_list;
124: _rl_free_undo_list (rl_undo_list);
125: rl_undo_list = (UNDO_LIST *)NULL;
1.1.1.2 ! misho 126: _hs_replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL);
1.1 misho 127: }
128:
129: UNDO_LIST *
1.1.1.2 ! misho 130: _rl_copy_undo_entry (UNDO_LIST *entry)
1.1 misho 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:
139: UNDO_LIST *
1.1.1.2 ! misho 140: _rl_copy_undo_list (UNDO_LIST *head)
1.1 misho 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;
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. */
168: int
1.1.1.2 ! misho 169: rl_do_undo (void)
1.1 misho 170: {
1.1.1.2 ! misho 171: UNDO_LIST *release, *search;
1.1 misho 172: int waiting_for_begin, start, end;
173: HIST_ENTRY *cur, *temp;
174:
175: #define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
176:
177: start = end = waiting_for_begin = 0;
178: do
179: {
180: if (rl_undo_list == 0)
181: return (0);
182:
183: _rl_doing_an_undo = 1;
184: RL_SETSTATE(RL_STATE_UNDOING);
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;
1.1.1.2 ! misho 199: _rl_fix_point (1);
1.1 misho 200: rl_insert_text (rl_undo_list->text);
201: xfree (rl_undo_list->text);
202: break;
203:
204: /* Undoing inserts means deleting some text. */
205: case UNDO_INSERT:
206: rl_delete_text (start, end);
207: rl_point = start;
1.1.1.2 ! misho 208: _rl_fix_point (1);
1.1 misho 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
221: rl_ding ();
222: break;
223: }
224:
225: _rl_doing_an_undo = 0;
226: RL_UNSETSTATE(RL_STATE_UNDOING);
227:
228: release = rl_undo_list;
229: rl_undo_list = rl_undo_list->next;
1.1.1.2 ! misho 230: release->next = 0; /* XXX */
1.1 misho 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:
1.1.1.2 ! misho 243: /* Make sure there aren't any history entries with that undo list */
! 244: _hs_replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
! 245:
! 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: }
1.1 misho 266:
267: xfree (release);
268: }
269: while (waiting_for_begin);
270:
271: return (1);
272: }
273: #undef TRANS
274:
275: int
1.1.1.2 ! misho 276: _rl_fix_last_undo_of_type (int type, int start, int end)
1.1 misho 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. */
293: int
1.1.1.2 ! misho 294: rl_begin_undo_group (void)
1.1 misho 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 (). */
302: int
1.1.1.2 ! misho 303: rl_end_undo_group (void)
1.1 misho 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. */
311: int
1.1.1.2 ! misho 312: rl_modifying (int start, int end)
1.1 misho 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. */
331: int
1.1.1.2 ! misho 332: rl_revert_line (int count, int key)
1.1 misho 333: {
334: if (rl_undo_list == 0)
335: rl_ding ();
336: else
337: {
338: while (rl_undo_list)
339: rl_do_undo ();
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
344: }
345:
346: return 0;
347: }
348:
349: /* Do some undoing of things that were done. */
350: int
1.1.1.2 ! misho 351: rl_undo_command (int count, int key)
1.1 misho 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: {
362: rl_ding ();
363: break;
364: }
365: }
366: return 0;
367: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>