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