File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / readline / undo.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 01:01:01 2021 UTC (3 years, 3 months ago) by misho
Branches: readline, MAIN
CVS tags: v8_2p0, v8_1p0, HEAD
readline 8.1

    1: /* undo.c - manage list of changes to lines, offering opportunity to undo them */
    2: 
    3: /* Copyright (C) 1987-2017 Free Software Foundation, Inc.
    4: 
    5:    This file is part of the GNU Readline Library (Readline), a library
    6:    for reading lines of text with interactive input and history editing.      
    7: 
    8:    Readline is free software: you can redistribute it and/or modify
    9:    it under the terms of the GNU General Public License as published by
   10:    the Free Software Foundation, either version 3 of the License, or
   11:    (at your option) any later version.
   12: 
   13:    Readline is distributed in the hope that it will be useful,
   14:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   15:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16:    GNU General Public License for more details.
   17: 
   18:    You should have received a copy of the GNU General Public License
   19:    along with Readline.  If not, see <http://www.gnu.org/licenses/>.
   20: */
   21: 
   22: #define READLINE_LIBRARY
   23: 
   24: #if defined (HAVE_CONFIG_H)
   25: #  include <config.h>
   26: #endif
   27: 
   28: #include <sys/types.h>
   29: 
   30: #if defined (HAVE_UNISTD_H)
   31: #  include <unistd.h>           /* for _POSIX_VERSION */
   32: #endif /* HAVE_UNISTD_H */
   33: 
   34: #if defined (HAVE_STDLIB_H)
   35: #  include <stdlib.h>
   36: #else
   37: #  include "ansi_stdlib.h"
   38: #endif /* HAVE_STDLIB_H */
   39: 
   40: #include <stdio.h>
   41: 
   42: /* System-specific feature definitions and include files. */
   43: #include "rldefs.h"
   44: 
   45: /* Some standard library routines. */
   46: #include "readline.h"
   47: #include "history.h"
   48: 
   49: #include "rlprivate.h"
   50: #include "xmalloc.h"
   51: 
   52: extern void _hs_replace_history_data PARAMS((int, histdata_t *, histdata_t *));
   53: 
   54: extern HIST_ENTRY *_rl_saved_line_for_history;
   55: 
   56: /* Non-zero tells rl_delete_text and rl_insert_text to not add to
   57:    the undo list. */
   58: int _rl_doing_an_undo = 0;
   59: 
   60: /* How many unclosed undo groups we currently have. */
   61: int _rl_undo_group_level = 0;
   62: 
   63: /* The current undo list for THE_LINE. */
   64: UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
   65: 
   66: /* **************************************************************** */
   67: /*								    */
   68: /*			Undo, and Undoing			    */
   69: /*								    */
   70: /* **************************************************************** */
   71: 
   72: static UNDO_LIST *
   73: alloc_undo_entry (enum undo_code what, int start, int end, char *text)
   74: {
   75:   UNDO_LIST *temp;
   76: 
   77:   temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
   78:   temp->what = what;
   79:   temp->start = start;
   80:   temp->end = end;
   81:   temp->text = text;
   82: 
   83:   temp->next = (UNDO_LIST *)NULL;
   84:   return temp;
   85: }
   86: 
   87: /* Remember how to undo something.  Concatenate some undos if that
   88:    seems right. */
   89: void
   90: rl_add_undo (enum undo_code what, int start, int end, char *text)
   91: {
   92:   UNDO_LIST *temp;
   93: 
   94:   temp = alloc_undo_entry (what, start, end, text);
   95:   temp->next = rl_undo_list;
   96:   rl_undo_list = temp;
   97: }
   98: 
   99: /* Free an UNDO_LIST */
  100: void
  101: _rl_free_undo_list (UNDO_LIST *ul)
  102: {
  103:   UNDO_LIST *release;
  104: 
  105:   while (ul)
  106:     {
  107:       release = ul;
  108:       ul = ul->next;
  109: 
  110:       if (release->what == UNDO_DELETE)
  111: 	xfree (release->text);
  112: 
  113:       xfree (release);
  114:     }
  115: }
  116: 
  117: /* Free the existing undo list. */
  118: void
  119: rl_free_undo_list (void)
  120: {
  121:   UNDO_LIST *release, *orig_list;
  122: 
  123:   orig_list = rl_undo_list;
  124:   _rl_free_undo_list (rl_undo_list);
  125:   rl_undo_list = (UNDO_LIST *)NULL;
  126:   _hs_replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL);
  127: }
  128: 
  129: UNDO_LIST *
  130: _rl_copy_undo_entry (UNDO_LIST *entry)
  131: {
  132:   UNDO_LIST *new;
  133: 
  134:   new = alloc_undo_entry (entry->what, entry->start, entry->end, (char *)NULL);
  135:   new->text = entry->text ? savestring (entry->text) : 0;
  136:   return new;
  137: }
  138: 
  139: UNDO_LIST *
  140: _rl_copy_undo_list (UNDO_LIST *head)
  141: {
  142:   UNDO_LIST *list, *new, *roving, *c;
  143: 
  144:   if (head == 0)
  145:     return head;
  146: 
  147:   list = head;
  148:   new = 0;
  149:   while (list)
  150:     {
  151:       c = _rl_copy_undo_entry (list);
  152:       if (new == 0)
  153: 	roving = new = c;
  154:       else
  155: 	{
  156: 	  roving->next = c;
  157: 	  roving = roving->next;
  158: 	}
  159:       list = list->next;
  160:     }
  161: 
  162:   roving->next = 0;
  163:   return new;
  164: }
  165: 
  166: /* Undo the next thing in the list.  Return 0 if there
  167:    is nothing to undo, or non-zero if there was. */
  168: int
  169: rl_do_undo (void)
  170: {
  171:   UNDO_LIST *release, *search;
  172:   int waiting_for_begin, start, end;
  173:   HIST_ENTRY *cur, *temp;
  174: 
  175: #define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
  176: 
  177:   start = end = waiting_for_begin = 0;
  178:   do
  179:     {
  180:       if (rl_undo_list == 0)
  181: 	return (0);
  182: 
  183:       _rl_doing_an_undo = 1;
  184:       RL_SETSTATE(RL_STATE_UNDOING);
  185: 
  186:       /* To better support vi-mode, a start or end value of -1 means
  187: 	 rl_point, and a value of -2 means rl_end. */
  188:       if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
  189: 	{
  190: 	  start = TRANS (rl_undo_list->start);
  191: 	  end = TRANS (rl_undo_list->end);
  192: 	}
  193: 
  194:       switch (rl_undo_list->what)
  195: 	{
  196: 	/* Undoing deletes means inserting some text. */
  197: 	case UNDO_DELETE:
  198: 	  rl_point = start;
  199: 	  _rl_fix_point (1);
  200: 	  rl_insert_text (rl_undo_list->text);
  201: 	  xfree (rl_undo_list->text);
  202: 	  break;
  203: 
  204: 	/* Undoing inserts means deleting some text. */
  205: 	case UNDO_INSERT:
  206: 	  rl_delete_text (start, end);
  207: 	  rl_point = start;
  208: 	  _rl_fix_point (1);
  209: 	  break;
  210: 
  211: 	/* Undoing an END means undoing everything 'til we get to a BEGIN. */
  212: 	case UNDO_END:
  213: 	  waiting_for_begin++;
  214: 	  break;
  215: 
  216: 	/* Undoing a BEGIN means that we are done with this group. */
  217: 	case UNDO_BEGIN:
  218: 	  if (waiting_for_begin)
  219: 	    waiting_for_begin--;
  220: 	  else
  221: 	    rl_ding ();
  222: 	  break;
  223: 	}
  224: 
  225:       _rl_doing_an_undo = 0;
  226:       RL_UNSETSTATE(RL_STATE_UNDOING);
  227: 
  228:       release = rl_undo_list;
  229:       rl_undo_list = rl_undo_list->next;
  230:       release->next = 0;	/* XXX */
  231: 
  232:       /* If we are editing a history entry, make sure the change is replicated
  233: 	 in the history entry's line */
  234:       cur = current_history ();
  235:       if (cur && cur->data && (UNDO_LIST *)cur->data == release)
  236: 	{
  237: 	  temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list);
  238: 	  xfree (temp->line);
  239: 	  FREE (temp->timestamp);
  240: 	  xfree (temp);
  241: 	}
  242: 
  243:       /* Make sure there aren't any history entries with that undo list */
  244:       _hs_replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
  245: 
  246:       /* And make sure this list isn't anywhere in the saved line for history */
  247:       if (_rl_saved_line_for_history && _rl_saved_line_for_history->data)
  248: 	{
  249: 	  /* Brute force; no finesse here */
  250: 	  search = (UNDO_LIST *)_rl_saved_line_for_history->data;
  251: 	  if (search == release)
  252: 	    _rl_saved_line_for_history->data = rl_undo_list;
  253: 	  else
  254: 	    {
  255: 	      while (search->next)
  256: 		{
  257: 		  if (search->next == release)
  258: 		    {
  259: 		      search->next = rl_undo_list;
  260: 		      break;
  261: 		    }
  262: 		  search = search->next;
  263: 		}
  264: 	    }
  265: 	}
  266: 
  267:       xfree (release);
  268:     }
  269:   while (waiting_for_begin);
  270: 
  271:   return (1);
  272: }
  273: #undef TRANS
  274: 
  275: int
  276: _rl_fix_last_undo_of_type (int type, int start, int end)
  277: {
  278:   UNDO_LIST *rl;
  279: 
  280:   for (rl = rl_undo_list; rl; rl = rl->next)
  281:     {
  282:       if (rl->what == type)
  283: 	{
  284: 	  rl->start = start;
  285: 	  rl->end = end;
  286: 	  return 0;
  287: 	}
  288:     }
  289:   return 1;
  290: }
  291: 
  292: /* Begin a group.  Subsequent undos are undone as an atomic operation. */
  293: int
  294: rl_begin_undo_group (void)
  295: {
  296:   rl_add_undo (UNDO_BEGIN, 0, 0, 0);
  297:   _rl_undo_group_level++;
  298:   return 0;
  299: }
  300: 
  301: /* End an undo group started with rl_begin_undo_group (). */
  302: int
  303: rl_end_undo_group (void)
  304: {
  305:   rl_add_undo (UNDO_END, 0, 0, 0);
  306:   _rl_undo_group_level--;
  307:   return 0;
  308: }
  309: 
  310: /* Save an undo entry for the text from START to END. */
  311: int
  312: rl_modifying (int start, int end)
  313: {
  314:   if (start > end)
  315:     {
  316:       SWAP (start, end);
  317:     }
  318: 
  319:   if (start != end)
  320:     {
  321:       char *temp = rl_copy_text (start, end);
  322:       rl_begin_undo_group ();
  323:       rl_add_undo (UNDO_DELETE, start, end, temp);
  324:       rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
  325:       rl_end_undo_group ();
  326:     }
  327:   return 0;
  328: }
  329: 
  330: /* Revert the current line to its previous state. */
  331: int
  332: rl_revert_line (int count, int key)
  333: {
  334:   if (rl_undo_list == 0)
  335:     rl_ding ();
  336:   else
  337:     {
  338:       while (rl_undo_list)
  339: 	rl_do_undo ();
  340: #if defined (VI_MODE)
  341:       if (rl_editing_mode == vi_mode)
  342: 	rl_point = rl_mark = 0;		/* rl_end should be set correctly */
  343: #endif
  344:     }
  345:     
  346:   return 0;
  347: }
  348: 
  349: /* Do some undoing of things that were done. */
  350: int
  351: rl_undo_command (int count, int key)
  352: {
  353:   if (count < 0)
  354:     return 0;	/* Nothing to do. */
  355: 
  356:   while (count)
  357:     {
  358:       if (rl_do_undo ())
  359: 	count--;
  360:       else
  361: 	{
  362: 	  rl_ding ();
  363: 	  break;
  364: 	}
  365:     }
  366:   return 0;
  367: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>