Annotation of embedaddon/readline/undo.c, revision 1.1.1.2

1.1.1.2 ! misho       1: /* undo.c - manage list of changes to lines, offering opportunity to undo them */
1.1       misho       2: 
1.1.1.2 ! misho       3: /* Copyright (C) 1987-2017 Free Software Foundation, Inc.
1.1       misho       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: 
1.1.1.2 ! misho      52: extern void _hs_replace_history_data PARAMS((int, histdata_t *, histdata_t *));
        !            53: 
        !            54: extern HIST_ENTRY *_rl_saved_line_for_history;
1.1       misho      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 *
1.1.1.2 ! misho      73: alloc_undo_entry (enum undo_code what, int start, int end, char *text)
1.1       misho      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
1.1.1.2 ! misho      90: rl_add_undo (enum undo_code what, int start, int end, char *text)
1.1       misho      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
1.1.1.2 ! misho     101: _rl_free_undo_list (UNDO_LIST *ul)
1.1       misho     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
1.1.1.2 ! misho     119: rl_free_undo_list (void)
1.1       misho     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;
1.1.1.2 ! misho     126:   _hs_replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL);
1.1       misho     127: }
                    128: 
                    129: UNDO_LIST *
1.1.1.2 ! misho     130: _rl_copy_undo_entry (UNDO_LIST *entry)
1.1       misho     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 *
1.1.1.2 ! misho     140: _rl_copy_undo_list (UNDO_LIST *head)
1.1       misho     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
1.1.1.2 ! misho     169: rl_do_undo (void)
1.1       misho     170: {
1.1.1.2 ! misho     171:   UNDO_LIST *release, *search;
1.1       misho     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;
1.1.1.2 ! misho     199:          _rl_fix_point (1);
1.1       misho     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;
1.1.1.2 ! misho     208:          _rl_fix_point (1);
1.1       misho     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;
1.1.1.2 ! misho     230:       release->next = 0;       /* XXX */
1.1       misho     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: 
1.1.1.2 ! misho     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:        }
1.1       misho     266: 
                    267:       xfree (release);
                    268:     }
                    269:   while (waiting_for_begin);
                    270: 
                    271:   return (1);
                    272: }
                    273: #undef TRANS
                    274: 
                    275: int
1.1.1.2 ! misho     276: _rl_fix_last_undo_of_type (int type, int start, int end)
1.1       misho     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
1.1.1.2 ! misho     294: rl_begin_undo_group (void)
1.1       misho     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
1.1.1.2 ! misho     303: rl_end_undo_group (void)
1.1       misho     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
1.1.1.2 ! misho     312: rl_modifying (int start, int end)
1.1       misho     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
1.1.1.2 ! misho     332: rl_revert_line (int count, int key)
1.1       misho     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
1.1.1.2 ! misho     351: rl_undo_command (int count, int key)
1.1       misho     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>