undo.c revision 58310
121308Sache/* readline.c -- a general facility for reading lines of input 221308Sache with emacs style editing and completion. */ 321308Sache 421308Sache/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. 521308Sache 621308Sache This file is part of the GNU Readline Library, a library for 721308Sache reading lines of text with interactive input and history editing. 821308Sache 921308Sache The GNU Readline Library is free software; you can redistribute it 1021308Sache and/or modify it under the terms of the GNU General Public License 1158310Sache as published by the Free Software Foundation; either version 2, or 1221308Sache (at your option) any later version. 1321308Sache 1421308Sache The GNU Readline Library is distributed in the hope that it will be 1521308Sache useful, but WITHOUT ANY WARRANTY; without even the implied warranty 1621308Sache of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1721308Sache GNU General Public License for more details. 1821308Sache 1921308Sache The GNU General Public License is often shipped with GNU software, and 2021308Sache is generally kept in a file called COPYING or LICENSE. If you do not 2121308Sache have a copy of the license, write to the Free Software Foundation, 2258310Sache 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 2321308Sache#define READLINE_LIBRARY 2421308Sache 2521308Sache#if defined (HAVE_CONFIG_H) 2621308Sache# include <config.h> 2721308Sache#endif 2821308Sache 2921308Sache#include <sys/types.h> 3021308Sache 3121308Sache#if defined (HAVE_UNISTD_H) 3221308Sache# include <unistd.h> /* for _POSIX_VERSION */ 3321308Sache#endif /* HAVE_UNISTD_H */ 3421308Sache 3521308Sache#if defined (HAVE_STDLIB_H) 3621308Sache# include <stdlib.h> 3721308Sache#else 3821308Sache# include "ansi_stdlib.h" 3921308Sache#endif /* HAVE_STDLIB_H */ 4021308Sache 4121308Sache#include <stdio.h> 4221308Sache 4321308Sache/* System-specific feature definitions and include files. */ 4421308Sache#include "rldefs.h" 4521308Sache 4621308Sache/* Some standard library routines. */ 4721308Sache#include "readline.h" 4821308Sache#include "history.h" 4921308Sache 5058310Sache#include "rlprivate.h" 5158310Sache 5221308Sache#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) 5321308Sache 5421308Sache/* Non-zero tells rl_delete_text and rl_insert_text to not add to 5521308Sache the undo list. */ 5621308Sacheint _rl_doing_an_undo = 0; 5721308Sache 5821308Sache/* How many unclosed undo groups we currently have. */ 5921308Sacheint _rl_undo_group_level = 0; 6021308Sache 6121308Sache/* The current undo list for THE_LINE. */ 6221308SacheUNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL; 6321308Sache 6421308Sache/* **************************************************************** */ 6521308Sache/* */ 6621308Sache/* Undo, and Undoing */ 6721308Sache/* */ 6821308Sache/* **************************************************************** */ 6921308Sache 7021308Sache/* Remember how to undo something. Concatenate some undos if that 7121308Sache seems right. */ 7221308Sachevoid 7321308Sacherl_add_undo (what, start, end, text) 7421308Sache enum undo_code what; 7521308Sache int start, end; 7621308Sache char *text; 7721308Sache{ 7821308Sache UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST)); 7921308Sache temp->what = what; 8021308Sache temp->start = start; 8121308Sache temp->end = end; 8221308Sache temp->text = text; 8321308Sache temp->next = rl_undo_list; 8421308Sache rl_undo_list = temp; 8521308Sache} 8621308Sache 8721308Sache/* Free the existing undo list. */ 8821308Sachevoid 8921308Sachefree_undo_list () 9021308Sache{ 9121308Sache while (rl_undo_list) 9221308Sache { 9321308Sache UNDO_LIST *release = rl_undo_list; 9421308Sache rl_undo_list = rl_undo_list->next; 9521308Sache 9621308Sache if (release->what == UNDO_DELETE) 9721308Sache free (release->text); 9821308Sache 9921308Sache free (release); 10021308Sache } 10121308Sache rl_undo_list = (UNDO_LIST *)NULL; 10221308Sache} 10321308Sache 10421308Sache/* Undo the next thing in the list. Return 0 if there 10521308Sache is nothing to undo, or non-zero if there was. */ 10621308Sacheint 10721308Sacherl_do_undo () 10821308Sache{ 10921308Sache UNDO_LIST *release; 11021308Sache int waiting_for_begin = 0; 11121308Sache int start, end; 11221308Sache 11321308Sache#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i))) 11421308Sache 11521308Sache do 11621308Sache { 11721308Sache if (!rl_undo_list) 11821308Sache return (0); 11921308Sache 12021308Sache _rl_doing_an_undo = 1; 12121308Sache 12221308Sache /* To better support vi-mode, a start or end value of -1 means 12321308Sache rl_point, and a value of -2 means rl_end. */ 12421308Sache if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT) 12521308Sache { 12621308Sache start = TRANS (rl_undo_list->start); 12721308Sache end = TRANS (rl_undo_list->end); 12821308Sache } 12921308Sache 13021308Sache switch (rl_undo_list->what) 13121308Sache { 13221308Sache /* Undoing deletes means inserting some text. */ 13321308Sache case UNDO_DELETE: 13421308Sache rl_point = start; 13521308Sache rl_insert_text (rl_undo_list->text); 13621308Sache free (rl_undo_list->text); 13721308Sache break; 13821308Sache 13921308Sache /* Undoing inserts means deleting some text. */ 14021308Sache case UNDO_INSERT: 14121308Sache rl_delete_text (start, end); 14221308Sache rl_point = start; 14321308Sache break; 14421308Sache 14521308Sache /* Undoing an END means undoing everything 'til we get to a BEGIN. */ 14621308Sache case UNDO_END: 14721308Sache waiting_for_begin++; 14821308Sache break; 14921308Sache 15021308Sache /* Undoing a BEGIN means that we are done with this group. */ 15121308Sache case UNDO_BEGIN: 15221308Sache if (waiting_for_begin) 15321308Sache waiting_for_begin--; 15421308Sache else 15521308Sache ding (); 15621308Sache break; 15721308Sache } 15821308Sache 15921308Sache _rl_doing_an_undo = 0; 16021308Sache 16121308Sache release = rl_undo_list; 16221308Sache rl_undo_list = rl_undo_list->next; 16321308Sache free (release); 16421308Sache } 16521308Sache while (waiting_for_begin); 16621308Sache 16721308Sache return (1); 16821308Sache} 16921308Sache#undef TRANS 17021308Sache 17121308Sacheint 17221308Sache_rl_fix_last_undo_of_type (type, start, end) 17321308Sache int type, start, end; 17421308Sache{ 17521308Sache UNDO_LIST *rl; 17621308Sache 17721308Sache for (rl = rl_undo_list; rl; rl = rl->next) 17821308Sache { 17921308Sache if (rl->what == type) 18021308Sache { 18121308Sache rl->start = start; 18221308Sache rl->end = end; 18321308Sache return 0; 18421308Sache } 18521308Sache } 18621308Sache return 1; 18721308Sache} 18821308Sache 18921308Sache/* Begin a group. Subsequent undos are undone as an atomic operation. */ 19021308Sacheint 19121308Sacherl_begin_undo_group () 19221308Sache{ 19321308Sache rl_add_undo (UNDO_BEGIN, 0, 0, 0); 19421308Sache _rl_undo_group_level++; 19521308Sache return 0; 19621308Sache} 19721308Sache 19821308Sache/* End an undo group started with rl_begin_undo_group (). */ 19921308Sacheint 20021308Sacherl_end_undo_group () 20121308Sache{ 20221308Sache rl_add_undo (UNDO_END, 0, 0, 0); 20321308Sache _rl_undo_group_level--; 20421308Sache return 0; 20521308Sache} 20621308Sache 20721308Sache/* Save an undo entry for the text from START to END. */ 20821308Sacheint 20921308Sacherl_modifying (start, end) 21021308Sache int start, end; 21121308Sache{ 21221308Sache if (start > end) 21321308Sache { 21421308Sache SWAP (start, end); 21521308Sache } 21621308Sache 21721308Sache if (start != end) 21821308Sache { 21921308Sache char *temp = rl_copy_text (start, end); 22021308Sache rl_begin_undo_group (); 22121308Sache rl_add_undo (UNDO_DELETE, start, end, temp); 22221308Sache rl_add_undo (UNDO_INSERT, start, end, (char *)NULL); 22321308Sache rl_end_undo_group (); 22421308Sache } 22521308Sache return 0; 22621308Sache} 22721308Sache 22821308Sache/* Revert the current line to its previous state. */ 22921308Sacheint 23021308Sacherl_revert_line (count, key) 23121308Sache int count, key; 23221308Sache{ 23321308Sache if (!rl_undo_list) 23421308Sache ding (); 23521308Sache else 23621308Sache { 23721308Sache while (rl_undo_list) 23821308Sache rl_do_undo (); 23921308Sache } 24021308Sache return 0; 24121308Sache} 24221308Sache 24321308Sache/* Do some undoing of things that were done. */ 24421308Sacheint 24521308Sacherl_undo_command (count, key) 24621308Sache int count, key; 24721308Sache{ 24821308Sache if (count < 0) 24921308Sache return 0; /* Nothing to do. */ 25021308Sache 25121308Sache while (count) 25221308Sache { 25321308Sache if (rl_do_undo ()) 25421308Sache count--; 25521308Sache else 25621308Sache { 25721308Sache ding (); 25821308Sache break; 25921308Sache } 26021308Sache } 26121308Sache return 0; 26221308Sache} 263