Annotation of GNUtools/emacs/src/undo.c, revision 1.1.1.1

1.1       root        1: /* undo handling for GNU Emacs.
                      2:    Copyright (C) 1990 Free Software Foundation, Inc.
                      3: 
                      4: This file is part of GNU Emacs.
                      5: 
                      6: GNU Emacs is free software; you can redistribute it and/or modify
                      7: it under the terms of the GNU General Public License as published by
                      8: the Free Software Foundation; either version 1, or (at your option)
                      9: any later version.
                     10: 
                     11: GNU Emacs is distributed in the hope that it will be useful,
                     12: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     14: GNU General Public License for more details.
                     15: 
                     16: You should have received a copy of the GNU General Public License
                     17: along with GNU Emacs; see the file COPYING.  If not, write to
                     18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
                     19: 
                     20: 
                     21: #include "config.h"
                     22: #include "lisp.h"
                     23: #include "buffer.h"
                     24: 
                     25: /* Last buffer for which undo information was recorded.  */
                     26: Lisp_Object last_undo_buffer;
                     27: 
                     28: /* Record an insertion that just happened or is about to happen,
                     29:    for LENGTH characters at position BEG.
                     30:    (It is possible to record an insertion before or after the fact
                     31:    because we don't need to record the contents.)  */
                     32: 
                     33: record_insert (beg, length)
                     34:      Lisp_Object beg, length;
                     35: {
                     36:   Lisp_Object lbeg, lend;
                     37: 
                     38:   if (current_buffer != XBUFFER (last_undo_buffer))
                     39:     Fundo_boundary ();
                     40:   XSET (last_undo_buffer, Lisp_Buffer, current_buffer);
                     41: 
                     42:   if (EQ (current_buffer->undo_list, Qt))
                     43:     return;
                     44:   if (MODIFF <= current_buffer->save_modified)
                     45:     record_first_change ();
                     46: 
                     47:   /* If this is following another insertion and consecutive with it
                     48:      in the buffer, combine the two.  */
                     49:   if (XTYPE (current_buffer->undo_list) == Lisp_Cons)
                     50:     {
                     51:       Lisp_Object elt;
                     52:       elt = XCONS (current_buffer->undo_list)->car;
                     53:       if (XTYPE (elt) == Lisp_Cons
                     54:          && XTYPE (XCONS (elt)->car) == Lisp_Int
                     55:          && XTYPE (XCONS (elt)->cdr) == Lisp_Int
                     56:          && XINT (XCONS (elt)->cdr) == beg)
                     57:        {
                     58:          XSETINT (XCONS (elt)->cdr, beg + length);
                     59:          return;
                     60:        }
                     61:     }
                     62: 
                     63:   XFASTINT (lbeg) = beg;
                     64:   XFASTINT (lend) = beg + length;
                     65:   current_buffer->undo_list = Fcons (Fcons (lbeg, lend), current_buffer->undo_list);
                     66: }
                     67: 
                     68: /* Record that a deletion is about to take place,
                     69:    for LENGTH characters at location BEG.  */
                     70: 
                     71: record_delete (beg, length)
                     72:      int beg, length;
                     73: {
                     74:   Lisp_Object lbeg, llength, lend, sbeg;
                     75: 
                     76:   if (current_buffer != XBUFFER (last_undo_buffer))
                     77:     Fundo_boundary ();
                     78:   XSET (last_undo_buffer, Lisp_Buffer, current_buffer);
                     79: 
                     80:   if (EQ (current_buffer->undo_list, Qt))
                     81:     return;
                     82:   if (MODIFF <= current_buffer->save_modified)
                     83:     record_first_change ();
                     84: 
                     85:   if (point == beg + length)
                     86:     XSET (sbeg, Lisp_Int, -beg);
                     87:   else
                     88:     XFASTINT (sbeg) = beg;
                     89:   XFASTINT (lbeg) = beg;
                     90:   XFASTINT (llength) = length;
                     91:   XFASTINT (lend) = beg + length;
                     92:   current_buffer->undo_list = Fcons (Fcons (Fbuffer_substring (lbeg, lend), sbeg),
                     93:                             current_buffer->undo_list);
                     94: }
                     95: 
                     96: /* Record that a replacement is about to take place,
                     97:    for LENGTH characters at location BEG.
                     98:    The replacement does not change the number of characters.  */
                     99: 
                    100: record_change (beg, length)
                    101:      int beg, length;
                    102: {
                    103:   record_delete (beg, length);
                    104:   record_insert (beg, length);
                    105: }
                    106: 
                    107: /* Record that an unmodified buffer is about to be changed.
                    108:    Record the file modification date so that when undoing this entry
                    109:    we can tell whether it is obsolete because the file was saved again.  */
                    110: 
                    111: record_first_change ()
                    112: {
                    113:   Lisp_Object high, low;
                    114:   XFASTINT (high) = (current_buffer->modtime >> 16) & 0xffff;
                    115:   XFASTINT (low) = current_buffer->modtime & 0xffff;
                    116:   current_buffer->undo_list = Fcons (Fcons (Qt, Fcons (high, low)), current_buffer->undo_list);
                    117: }
                    118: 
                    119: DEFUN ("undo-boundary", Fundo_boundary, Sundo_boundary, 0, 0, 0,
                    120:   "Mark a boundary between units of undo.\n\
                    121: An undo command will stop at this point,\n\
                    122: but another undo command will undo to the previous boundary.")
                    123:   ()
                    124: {
                    125:   Lisp_Object tem;
                    126:   if (EQ (current_buffer->undo_list, Qt))
                    127:     return Qnil;
                    128:   tem = Fcar (current_buffer->undo_list);
                    129:   if (!NULL (tem))
                    130:     current_buffer->undo_list = Fcons (Qnil, current_buffer->undo_list);
                    131:   return Qnil;
                    132: }
                    133: 
                    134: /* At garbage collection time, make an undo list shorter at the end,
                    135:    returning the truncated list.
                    136:    MINSIZE and MAXSIZE are the limits on size allowed, as described below.
                    137:    In practice, these are the values of undo-threshold and
                    138:    undo-high-threshold.  */
                    139: 
                    140: Lisp_Object
                    141: truncate_undo_list (list, minsize, maxsize)
                    142:      Lisp_Object list;
                    143:      int minsize, maxsize;
                    144: {
                    145:   Lisp_Object prev, next, save_prev;
                    146:   int size_so_far = 0;
                    147: 
                    148:   prev = Qnil;
                    149:   next = list;
                    150:   save_prev = Qnil;
                    151: 
                    152:   while (XTYPE (next) == Lisp_Cons)
                    153:     {
                    154:       Lisp_Object elt;
                    155:       elt = XCONS (next)->car;
                    156: 
                    157:       /* When we get to a boundary, decide whether to truncate
                    158:         either before or after it.  The lower threshold, MINSIZE,
                    159:         tells us to truncate after it.  If its size pushes past
                    160:         the higher threshold MAXSIZE as well, we truncate before it.  */
                    161:       if (NULL (elt))
                    162:        {
                    163:          if (size_so_far > maxsize)
                    164:            break;
                    165:          save_prev = prev;
                    166:          if (size_so_far > minsize)
                    167:            break;
                    168:        }
                    169: 
                    170:       /* Add in the space occupied by this element and its chain link.  */
                    171:       size_so_far += 8;
                    172:       if (XTYPE (elt) == Lisp_Cons)
                    173:        {
                    174:          size_so_far += 8;
                    175:          if (XTYPE (XCONS (elt)->car) == Lisp_String)
                    176:            size_so_far += 6 + XSTRING (XCONS (elt)->car)->size;
                    177:        }
                    178: 
                    179:       /* Advance to next element.  */
                    180:       prev = next;
                    181:       next = XCONS (next)->cdr;
                    182:     }
                    183: 
                    184:   /* If we scanned the whole list, it is short enough; don't change it.  */
                    185:   if (NULL (next))
                    186:     return list;
                    187: 
                    188:   /* Truncate at the boundary where we decided to truncate.  */
                    189:   if (!NULL (save_prev))
                    190:     {
                    191:       XCONS (save_prev)->cdr = Qnil;
                    192:       return list;
                    193:     }
                    194:   else
                    195:     return Qnil;
                    196: }
                    197: 
                    198: DEFUN ("primitive-undo", Fprimitive_undo, Sprimitive_undo, 2, 2, 0,
                    199:   "Undo N records from the front of the list LIST.\n\
                    200: Return what remains of the list.")
                    201:   (count, list)
                    202:      Lisp_Object count, list;
                    203: {
                    204:   register int arg = XINT (count);
                    205: #if 0  /* This is a good feature, but would make undo-start
                    206:          unable to do what is expected.  */
                    207:   Lisp_Object tem;
                    208: 
                    209:   /* If the head of the list is a boundary, it is the boundary
                    210:      preceding this command.  Get rid of it and don't count it.  */
                    211:   tem = Fcar (list);
                    212:   if (NULL (tem))
                    213:     list = Fcdr (list);
                    214: #endif
                    215: 
                    216:   while (arg > 0)
                    217:     {
                    218:       while (1)
                    219:        {
                    220:          Lisp_Object next, car, cdr;
                    221:          next = Fcar (list);
                    222:          list = Fcdr (list);
                    223:          if (NULL (next))
                    224:            break;
                    225:          car = Fcar (next);
                    226:          cdr = Fcdr (next);
                    227:          if (EQ (car, Qt))
                    228:            {
                    229:              Lisp_Object high, low;
                    230:              int mod_time;
                    231:              high = Fcar (cdr);
                    232:              low = Fcdr (cdr);
                    233:              mod_time = (high << 16) + low;
                    234:              /* If this records an obsolete save
                    235:                 (not matching the actual disk file)
                    236:                 then don't mark unmodified.  */
                    237:              if (mod_time != current_buffer->modtime)
                    238:                break;
                    239: #ifdef CLASH_DETECTION
                    240:              Funlock_buffer ();
                    241: #endif /* CLASH_DETECTION */
                    242:              Fset_buffer_modified_p (Qnil);
                    243:            }
                    244:          else if (XTYPE (car) == Lisp_Int && XTYPE (cdr) == Lisp_Int)
                    245:            {
                    246:              Lisp_Object end;
                    247:              if (XINT (car) < BEGV
                    248:                  || XINT (cdr) > ZV)
                    249:                error ("Changes to be undone are outside visible portion of buffer");
                    250:              Fdelete_region (car, cdr);
                    251:              Fgoto_char (car);
                    252:            }
                    253:          else if (XTYPE (car) == Lisp_String && XTYPE (cdr) == Lisp_Int)
                    254:            {
                    255:              Lisp_Object membuf;
                    256:              int pos = XINT (cdr);
                    257:              membuf = car;
                    258:              if (pos < 0)
                    259:                {
                    260:                  if (-pos < BEGV || -pos > ZV)
                    261:                    error ("Changes to be undone are outside visible portion of buffer");
                    262:                  SET_PT (-pos);
                    263:                  Finsert (1, &membuf);
                    264:                }
                    265:              else
                    266:                {
                    267:                  if (pos < BEGV || pos > ZV)
                    268:                    error ("Changes to be undone are outside visible portion of buffer");
                    269:                  SET_PT (pos);
                    270:                  /* The idea here is to leave mark after this text,
                    271:                     which will be the desirable thing if undoing C-w.  */
                    272:                  Finsert_before_markers (1, &membuf);
                    273:                  SET_PT (pos);
                    274:                }
                    275:            }
                    276:        }
                    277:       arg--;
                    278:     }
                    279: 
                    280:   return list;
                    281: }
                    282: 
                    283: syms_of_undo ()
                    284: {
                    285:   defsubr (&Sprimitive_undo);
                    286:   defsubr (&Sundo_boundary);
                    287: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.