undo.c revision 157184
1652Sjkh/* readline.c -- a general facility for reading lines of input 233473Sscrappy with emacs style editing and completion. */ 333473Sscrappy 4652Sjkh/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. 533473Sscrappy 6652Sjkh This file is part of the GNU Readline Library, a library for 7652Sjkh reading lines of text with interactive input and history editing. 8652Sjkh 9652Sjkh The GNU Readline Library is free software; you can redistribute it 10652Sjkh and/or modify it under the terms of the GNU General Public License 11652Sjkh as published by the Free Software Foundation; either version 2, or 1233473Sscrappy (at your option) any later version. 1333473Sscrappy 1433473Sscrappy The GNU Readline Library is distributed in the hope that it will be 1533473Sscrappy useful, but WITHOUT ANY WARRANTY; without even the implied warranty 16652Sjkh of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1733473Sscrappy GNU General Public License for more details. 1833473Sscrappy 1933473Sscrappy The GNU General Public License is often shipped with GNU software, and 2033473Sscrappy is generally kept in a file called COPYING or LICENSE. If you do not 2133473Sscrappy have a copy of the license, write to the Free Software Foundation, 2233473Sscrappy 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 2333473Sscrappy#define READLINE_LIBRARY 2433473Sscrappy 2533473Sscrappy#if defined (HAVE_CONFIG_H) 2633473Sscrappy# include <config.h> 2733473Sscrappy#endif 2833473Sscrappy 2950734Speter#include <sys/types.h> 3050734Speter 31652Sjkh#if defined (HAVE_UNISTD_H) 32652Sjkh# include <unistd.h> /* for _POSIX_VERSION */ 3350906Sdfr#endif /* HAVE_UNISTD_H */ 3450906Sdfr 359750Sjkh#if defined (HAVE_STDLIB_H) 36652Sjkh# include <stdlib.h> 379750Sjkh#else 3813765Smpp# include "ansi_stdlib.h" 39652Sjkh#endif /* HAVE_STDLIB_H */ 40652Sjkh 41652Sjkh#include <stdio.h> 423256Sswallace 4330866Smarkm/* System-specific feature definitions and include files. */ 4430866Smarkm#include "rldefs.h" 4530866Smarkm 4630866Smarkm/* Some standard library routines. */ 4730866Smarkm#include "readline.h" 4830866Smarkm#include "history.h" 4930866Smarkm 5030866Smarkm#include "rlprivate.h" 5130866Smarkm#include "xmalloc.h" 52652Sjkh 53652Sjkh/* Non-zero tells rl_delete_text and rl_insert_text to not add to 5433530Sscrappy the undo list. */ 5533530Sscrappyint _rl_doing_an_undo = 0; 5633530Sscrappy 5733530Sscrappy/* How many unclosed undo groups we currently have. */ 5833530Sscrappyint _rl_undo_group_level = 0; 5933530Sscrappy 6033530Sscrappy/* The current undo list for THE_LINE. */ 6133530SscrappyUNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL; 6233530Sscrappy 6333530Sscrappy/* **************************************************************** */ 6433530Sscrappy/* */ 6533530Sscrappy/* Undo, and Undoing */ 6633530Sscrappy/* */ 6733530Sscrappy/* **************************************************************** */ 6833530Sscrappy 6933530Sscrappy/* Remember how to undo something. Concatenate some undos if that 7033530Sscrappy seems right. */ 7133530Sscrappyvoid 7233530Sscrappyrl_add_undo (what, start, end, text) 7333530Sscrappy enum undo_code what; 7433530Sscrappy int start, end; 7533530Sscrappy char *text; 7633530Sscrappy{ 7733530Sscrappy UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST)); 7833530Sscrappy temp->what = what; 7933530Sscrappy temp->start = start; 8033530Sscrappy temp->end = end; 8133530Sscrappy temp->text = text; 8233530Sscrappy temp->next = rl_undo_list; 8333530Sscrappy rl_undo_list = temp; 8433530Sscrappy} 8533530Sscrappy 8633530Sscrappy/* Free the existing undo list. */ 8733530Sscrappyvoid 8833530Sscrappyrl_free_undo_list () 8933530Sscrappy{ 9033530Sscrappy while (rl_undo_list) 9133530Sscrappy { 9233530Sscrappy UNDO_LIST *release = rl_undo_list; 9345240Skato rl_undo_list = rl_undo_list->next; 9462947Stanimura 9562947Stanimura if (release->what == UNDO_DELETE) 9633530Sscrappy free (release->text); 9733473Sscrappy 9833473Sscrappy free (release); 9933473Sscrappy } 10033473Sscrappy rl_undo_list = (UNDO_LIST *)NULL; 101652Sjkh} 102652Sjkh 10333473Sscrappy/* Undo the next thing in the list. Return 0 if there 10433473Sscrappy is nothing to undo, or non-zero if there was. */ 10533473Sscrappyint 10633473Sscrappyrl_do_undo () 10733473Sscrappy{ 108652Sjkh UNDO_LIST *release; 109652Sjkh int waiting_for_begin, start, end; 11033473Sscrappy 11133473Sscrappy#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i))) 11233473Sscrappy 11333473Sscrappy start = end = waiting_for_begin = 0; 11433473Sscrappy do 11533473Sscrappy { 11633473Sscrappy if (!rl_undo_list) 11733473Sscrappy return (0); 11833473Sscrappy 11933473Sscrappy _rl_doing_an_undo = 1; 12033473Sscrappy RL_SETSTATE(RL_STATE_UNDOING); 12133473Sscrappy 12233473Sscrappy /* To better support vi-mode, a start or end value of -1 means 12333473Sscrappy rl_point, and a value of -2 means rl_end. */ 12433473Sscrappy if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT) 12533473Sscrappy { 12633473Sscrappy start = TRANS (rl_undo_list->start); 12733473Sscrappy end = TRANS (rl_undo_list->end); 12833473Sscrappy } 12933473Sscrappy 13033473Sscrappy switch (rl_undo_list->what) 13133473Sscrappy { 13233473Sscrappy /* Undoing deletes means inserting some text. */ 133652Sjkh case UNDO_DELETE: 13430866Smarkm rl_point = start; 13533473Sscrappy rl_insert_text (rl_undo_list->text); 13633473Sscrappy free (rl_undo_list->text); 13733473Sscrappy break; 13833473Sscrappy 13933473Sscrappy /* Undoing inserts means deleting some text. */ 14033473Sscrappy case UNDO_INSERT: 14133473Sscrappy rl_delete_text (start, end); 14233473Sscrappy rl_point = start; 14333473Sscrappy break; 14433473Sscrappy 14533473Sscrappy /* Undoing an END means undoing everything 'til we get to a BEGIN. */ 14633473Sscrappy case UNDO_END: 14733473Sscrappy waiting_for_begin++; 14833473Sscrappy break; 14933473Sscrappy 15033473Sscrappy /* Undoing a BEGIN means that we are done with this group. */ 15133473Sscrappy case UNDO_BEGIN: 15233473Sscrappy if (waiting_for_begin) 15333473Sscrappy waiting_for_begin--; 15433473Sscrappy else 15533473Sscrappy rl_ding (); 15633473Sscrappy break; 15733473Sscrappy } 15833473Sscrappy 15933473Sscrappy _rl_doing_an_undo = 0; 16033473Sscrappy RL_UNSETSTATE(RL_STATE_UNDOING); 16133473Sscrappy 16233473Sscrappy release = rl_undo_list; 16333473Sscrappy rl_undo_list = rl_undo_list->next; 16433473Sscrappy free (release); 16533473Sscrappy } 16633473Sscrappy while (waiting_for_begin); 16733473Sscrappy 16833473Sscrappy return (1); 16933473Sscrappy} 17033473Sscrappy#undef TRANS 17133473Sscrappy 17233473Sscrappyint 17333473Sscrappy_rl_fix_last_undo_of_type (type, start, end) 17433473Sscrappy int type, start, end; 17533473Sscrappy{ 17633473Sscrappy UNDO_LIST *rl; 17733473Sscrappy 17833473Sscrappy for (rl = rl_undo_list; rl; rl = rl->next) 17933473Sscrappy { 18033473Sscrappy if (rl->what == type) 18133473Sscrappy { 18233473Sscrappy rl->start = start; 18333473Sscrappy rl->end = end; 18433473Sscrappy return 0; 18533473Sscrappy } 18633473Sscrappy } 18733473Sscrappy return 1; 18833473Sscrappy} 18933473Sscrappy 19033473Sscrappy/* Begin a group. Subsequent undos are undone as an atomic operation. */ 19133473Sscrappyint 19233473Sscrappyrl_begin_undo_group () 19333473Sscrappy{ 19433473Sscrappy rl_add_undo (UNDO_BEGIN, 0, 0, 0); 19533473Sscrappy _rl_undo_group_level++; 19633473Sscrappy return 0; 19733473Sscrappy} 19833473Sscrappy 19933473Sscrappy/* End an undo group started with rl_begin_undo_group (). */ 20033473Sscrappyint 20133473Sscrappyrl_end_undo_group () 20233473Sscrappy{ 20333473Sscrappy rl_add_undo (UNDO_END, 0, 0, 0); 20433473Sscrappy _rl_undo_group_level--; 20533473Sscrappy return 0; 20633473Sscrappy} 20733473Sscrappy 20833473Sscrappy/* Save an undo entry for the text from START to END. */ 20933473Sscrappyint 21033473Sscrappyrl_modifying (start, end) 21133473Sscrappy int start, end; 21233473Sscrappy{ 21333473Sscrappy if (start > end) 21433473Sscrappy { 21533473Sscrappy SWAP (start, end); 21633473Sscrappy } 21733473Sscrappy 21833473Sscrappy if (start != end) 21933473Sscrappy { 22033473Sscrappy char *temp = rl_copy_text (start, end); 22133473Sscrappy rl_begin_undo_group (); 22233473Sscrappy rl_add_undo (UNDO_DELETE, start, end, temp); 22333473Sscrappy rl_add_undo (UNDO_INSERT, start, end, (char *)NULL); 22433473Sscrappy rl_end_undo_group (); 22533473Sscrappy } 22633473Sscrappy return 0; 22733473Sscrappy} 22833473Sscrappy 22933473Sscrappy/* Revert the current line to its previous state. */ 23033473Sscrappyint 23133473Sscrappyrl_revert_line (count, key) 23233473Sscrappy int count, key; 23333473Sscrappy{ 23433473Sscrappy if (!rl_undo_list) 23533473Sscrappy rl_ding (); 23633473Sscrappy else 23733473Sscrappy { 23833473Sscrappy while (rl_undo_list) 23933473Sscrappy rl_do_undo (); 24033473Sscrappy#if defined (VI_MODE) 24133473Sscrappy if (rl_editing_mode == vi_mode) 24233473Sscrappy rl_point = rl_mark = 0; /* rl_end should be set correctly */ 24333473Sscrappy#endif 24433473Sscrappy } 24533473Sscrappy 24633473Sscrappy return 0; 24733473Sscrappy} 24833473Sscrappy 249652Sjkh/* Do some undoing of things that were done. */ 250652Sjkhint 251652Sjkhrl_undo_command (count, key) 25233473Sscrappy int count, key; 25333473Sscrappy{ 25433473Sscrappy if (count < 0) 25533473Sscrappy return 0; /* Nothing to do. */ 25633473Sscrappy 25733473Sscrappy while (count) 25833473Sscrappy { 25933473Sscrappy if (rl_do_undo ()) 26033473Sscrappy count--; 26133473Sscrappy else 26233473Sscrappy { 26333473Sscrappy rl_ding (); 26433473Sscrappy break; 26533473Sscrappy } 26633473Sscrappy } 26733473Sscrappy return 0; 26833473Sscrappy} 26933473Sscrappy