undo.c revision 75406
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 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 52#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) 53 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 70/* Remember how to undo something. Concatenate some undos if that 71 seems right. */ 72void 73rl_add_undo (what, start, end, text) 74 enum undo_code what; 75 int start, end; 76 char *text; 77{ 78 UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST)); 79 temp->what = what; 80 temp->start = start; 81 temp->end = end; 82 temp->text = text; 83 temp->next = rl_undo_list; 84 rl_undo_list = temp; 85} 86 87/* Free the existing undo list. */ 88void 89rl_free_undo_list () 90{ 91 while (rl_undo_list) 92 { 93 UNDO_LIST *release = rl_undo_list; 94 rl_undo_list = rl_undo_list->next; 95 96 if (release->what == UNDO_DELETE) 97 free (release->text); 98 99 free (release); 100 } 101 rl_undo_list = (UNDO_LIST *)NULL; 102} 103 104/* Undo the next thing in the list. Return 0 if there 105 is nothing to undo, or non-zero if there was. */ 106int 107rl_do_undo () 108{ 109 UNDO_LIST *release; 110 int waiting_for_begin, start, end; 111 112#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i))) 113 114 start = end = waiting_for_begin = 0; 115 do 116 { 117 if (!rl_undo_list) 118 return (0); 119 120 _rl_doing_an_undo = 1; 121 RL_SETSTATE(RL_STATE_UNDOING); 122 123 /* To better support vi-mode, a start or end value of -1 means 124 rl_point, and a value of -2 means rl_end. */ 125 if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT) 126 { 127 start = TRANS (rl_undo_list->start); 128 end = TRANS (rl_undo_list->end); 129 } 130 131 switch (rl_undo_list->what) 132 { 133 /* Undoing deletes means inserting some text. */ 134 case UNDO_DELETE: 135 rl_point = start; 136 rl_insert_text (rl_undo_list->text); 137 free (rl_undo_list->text); 138 break; 139 140 /* Undoing inserts means deleting some text. */ 141 case UNDO_INSERT: 142 rl_delete_text (start, end); 143 rl_point = start; 144 break; 145 146 /* Undoing an END means undoing everything 'til we get to a BEGIN. */ 147 case UNDO_END: 148 waiting_for_begin++; 149 break; 150 151 /* Undoing a BEGIN means that we are done with this group. */ 152 case UNDO_BEGIN: 153 if (waiting_for_begin) 154 waiting_for_begin--; 155 else 156 rl_ding (); 157 break; 158 } 159 160 _rl_doing_an_undo = 0; 161 RL_UNSETSTATE(RL_STATE_UNDOING); 162 163 release = rl_undo_list; 164 rl_undo_list = rl_undo_list->next; 165 free (release); 166 } 167 while (waiting_for_begin); 168 169 return (1); 170} 171#undef TRANS 172 173int 174_rl_fix_last_undo_of_type (type, start, end) 175 int type, start, end; 176{ 177 UNDO_LIST *rl; 178 179 for (rl = rl_undo_list; rl; rl = rl->next) 180 { 181 if (rl->what == type) 182 { 183 rl->start = start; 184 rl->end = end; 185 return 0; 186 } 187 } 188 return 1; 189} 190 191/* Begin a group. Subsequent undos are undone as an atomic operation. */ 192int 193rl_begin_undo_group () 194{ 195 rl_add_undo (UNDO_BEGIN, 0, 0, 0); 196 _rl_undo_group_level++; 197 return 0; 198} 199 200/* End an undo group started with rl_begin_undo_group (). */ 201int 202rl_end_undo_group () 203{ 204 rl_add_undo (UNDO_END, 0, 0, 0); 205 _rl_undo_group_level--; 206 return 0; 207} 208 209/* Save an undo entry for the text from START to END. */ 210int 211rl_modifying (start, end) 212 int start, end; 213{ 214 if (start > end) 215 { 216 SWAP (start, end); 217 } 218 219 if (start != end) 220 { 221 char *temp = rl_copy_text (start, end); 222 rl_begin_undo_group (); 223 rl_add_undo (UNDO_DELETE, start, end, temp); 224 rl_add_undo (UNDO_INSERT, start, end, (char *)NULL); 225 rl_end_undo_group (); 226 } 227 return 0; 228} 229 230/* Revert the current line to its previous state. */ 231int 232rl_revert_line (count, key) 233 int count, key; 234{ 235 if (!rl_undo_list) 236 rl_ding (); 237 else 238 { 239 while (rl_undo_list) 240 rl_do_undo (); 241 } 242 return 0; 243} 244 245/* Do some undoing of things that were done. */ 246int 247rl_undo_command (count, key) 248 int count, key; 249{ 250 if (count < 0) 251 return 0; /* Nothing to do. */ 252 253 while (count) 254 { 255 if (rl_do_undo ()) 256 count--; 257 else 258 { 259 rl_ding (); 260 break; 261 } 262 } 263 return 0; 264} 265