Annotation of embedaddon/readline/undo.c, revision 1.1
1.1 ! misho 1: /* readline.c -- a general facility for reading lines of input
! 2: with emacs style editing and completion. */
! 3:
! 4: /* Copyright (C) 1987-2012 Free Software Foundation, Inc.
! 5:
! 6: This file is part of the GNU Readline Library (Readline), a library
! 7: for reading lines of text with interactive input and history editing.
! 8:
! 9: Readline is free software: you can redistribute it and/or modify
! 10: it under the terms of the GNU General Public License as published by
! 11: the Free Software Foundation, either version 3 of the License, or
! 12: (at your option) any later version.
! 13:
! 14: Readline is distributed in the hope that it will be useful,
! 15: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 16: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 17: GNU General Public License for more details.
! 18:
! 19: You should have received a copy of the GNU General Public License
! 20: along with Readline. If not, see <http://www.gnu.org/licenses/>.
! 21: */
! 22:
! 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 *
! 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
! 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 an UNDO_LIST */
! 105: void
! 106: _rl_free_undo_list (ul)
! 107: UNDO_LIST *ul;
! 108: {
! 109: UNDO_LIST *release;
! 110:
! 111: while (ul)
! 112: {
! 113: release = ul;
! 114: ul = ul->next;
! 115:
! 116: if (release->what == UNDO_DELETE)
! 117: xfree (release->text);
! 118:
! 119: xfree (release);
! 120: }
! 121: }
! 122:
! 123: /* Free the existing undo list. */
! 124: void
! 125: rl_free_undo_list ()
! 126: {
! 127: UNDO_LIST *release, *orig_list;
! 128:
! 129: orig_list = rl_undo_list;
! 130: _rl_free_undo_list (rl_undo_list);
! 131: rl_undo_list = (UNDO_LIST *)NULL;
! 132: replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL);
! 133: }
! 134:
! 135: UNDO_LIST *
! 136: _rl_copy_undo_entry (entry)
! 137: UNDO_LIST *entry;
! 138: {
! 139: UNDO_LIST *new;
! 140:
! 141: new = alloc_undo_entry (entry->what, entry->start, entry->end, (char *)NULL);
! 142: new->text = entry->text ? savestring (entry->text) : 0;
! 143: return new;
! 144: }
! 145:
! 146: UNDO_LIST *
! 147: _rl_copy_undo_list (head)
! 148: UNDO_LIST *head;
! 149: {
! 150: UNDO_LIST *list, *new, *roving, *c;
! 151:
! 152: if (head == 0)
! 153: return head;
! 154:
! 155: list = head;
! 156: new = 0;
! 157: while (list)
! 158: {
! 159: c = _rl_copy_undo_entry (list);
! 160: if (new == 0)
! 161: roving = new = c;
! 162: else
! 163: {
! 164: roving->next = c;
! 165: roving = roving->next;
! 166: }
! 167: list = list->next;
! 168: }
! 169:
! 170: roving->next = 0;
! 171: return new;
! 172: }
! 173:
! 174: /* Undo the next thing in the list. Return 0 if there
! 175: is nothing to undo, or non-zero if there was. */
! 176: int
! 177: rl_do_undo ()
! 178: {
! 179: UNDO_LIST *release;
! 180: int waiting_for_begin, start, end;
! 181: HIST_ENTRY *cur, *temp;
! 182:
! 183: #define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
! 184:
! 185: start = end = waiting_for_begin = 0;
! 186: do
! 187: {
! 188: if (rl_undo_list == 0)
! 189: return (0);
! 190:
! 191: _rl_doing_an_undo = 1;
! 192: RL_SETSTATE(RL_STATE_UNDOING);
! 193:
! 194: /* To better support vi-mode, a start or end value of -1 means
! 195: rl_point, and a value of -2 means rl_end. */
! 196: if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
! 197: {
! 198: start = TRANS (rl_undo_list->start);
! 199: end = TRANS (rl_undo_list->end);
! 200: }
! 201:
! 202: switch (rl_undo_list->what)
! 203: {
! 204: /* Undoing deletes means inserting some text. */
! 205: case UNDO_DELETE:
! 206: rl_point = start;
! 207: rl_insert_text (rl_undo_list->text);
! 208: xfree (rl_undo_list->text);
! 209: break;
! 210:
! 211: /* Undoing inserts means deleting some text. */
! 212: case UNDO_INSERT:
! 213: rl_delete_text (start, end);
! 214: rl_point = start;
! 215: break;
! 216:
! 217: /* Undoing an END means undoing everything 'til we get to a BEGIN. */
! 218: case UNDO_END:
! 219: waiting_for_begin++;
! 220: break;
! 221:
! 222: /* Undoing a BEGIN means that we are done with this group. */
! 223: case UNDO_BEGIN:
! 224: if (waiting_for_begin)
! 225: waiting_for_begin--;
! 226: else
! 227: rl_ding ();
! 228: break;
! 229: }
! 230:
! 231: _rl_doing_an_undo = 0;
! 232: RL_UNSETSTATE(RL_STATE_UNDOING);
! 233:
! 234: release = rl_undo_list;
! 235: rl_undo_list = rl_undo_list->next;
! 236:
! 237: /* If we are editing a history entry, make sure the change is replicated
! 238: in the history entry's line */
! 239: cur = current_history ();
! 240: if (cur && cur->data && (UNDO_LIST *)cur->data == release)
! 241: {
! 242: temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list);
! 243: xfree (temp->line);
! 244: FREE (temp->timestamp);
! 245: xfree (temp);
! 246: }
! 247:
! 248: replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
! 249:
! 250: xfree (release);
! 251: }
! 252: while (waiting_for_begin);
! 253:
! 254: return (1);
! 255: }
! 256: #undef TRANS
! 257:
! 258: int
! 259: _rl_fix_last_undo_of_type (type, start, end)
! 260: int type, start, end;
! 261: {
! 262: UNDO_LIST *rl;
! 263:
! 264: for (rl = rl_undo_list; rl; rl = rl->next)
! 265: {
! 266: if (rl->what == type)
! 267: {
! 268: rl->start = start;
! 269: rl->end = end;
! 270: return 0;
! 271: }
! 272: }
! 273: return 1;
! 274: }
! 275:
! 276: /* Begin a group. Subsequent undos are undone as an atomic operation. */
! 277: int
! 278: rl_begin_undo_group ()
! 279: {
! 280: rl_add_undo (UNDO_BEGIN, 0, 0, 0);
! 281: _rl_undo_group_level++;
! 282: return 0;
! 283: }
! 284:
! 285: /* End an undo group started with rl_begin_undo_group (). */
! 286: int
! 287: rl_end_undo_group ()
! 288: {
! 289: rl_add_undo (UNDO_END, 0, 0, 0);
! 290: _rl_undo_group_level--;
! 291: return 0;
! 292: }
! 293:
! 294: /* Save an undo entry for the text from START to END. */
! 295: int
! 296: rl_modifying (start, end)
! 297: int start, end;
! 298: {
! 299: if (start > end)
! 300: {
! 301: SWAP (start, end);
! 302: }
! 303:
! 304: if (start != end)
! 305: {
! 306: char *temp = rl_copy_text (start, end);
! 307: rl_begin_undo_group ();
! 308: rl_add_undo (UNDO_DELETE, start, end, temp);
! 309: rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
! 310: rl_end_undo_group ();
! 311: }
! 312: return 0;
! 313: }
! 314:
! 315: /* Revert the current line to its previous state. */
! 316: int
! 317: rl_revert_line (count, key)
! 318: int count, key;
! 319: {
! 320: if (rl_undo_list == 0)
! 321: rl_ding ();
! 322: else
! 323: {
! 324: while (rl_undo_list)
! 325: rl_do_undo ();
! 326: #if defined (VI_MODE)
! 327: if (rl_editing_mode == vi_mode)
! 328: rl_point = rl_mark = 0; /* rl_end should be set correctly */
! 329: #endif
! 330: }
! 331:
! 332: return 0;
! 333: }
! 334:
! 335: /* Do some undoing of things that were done. */
! 336: int
! 337: rl_undo_command (count, key)
! 338: int count, key;
! 339: {
! 340: if (count < 0)
! 341: return 0; /* Nothing to do. */
! 342:
! 343: while (count)
! 344: {
! 345: if (rl_do_undo ())
! 346: count--;
! 347: else
! 348: {
! 349: rl_ding ();
! 350: break;
! 351: }
! 352: }
! 353: return 0;
! 354: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>