Annotation of GNUtools/emacs/src/undo.c, revision 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.