(get_truename_buffer): New function.
[bpt/emacs.git] / src / buffer.c
index 96f2e56..db1e311 100644 (file)
@@ -100,7 +100,9 @@ struct buffer buffer_local_types;
 
 Lisp_Object Fset_buffer ();
 void set_buffer_internal ();
+void set_buffer_internal_1 ();
 static void call_overlay_mod_hooks ();
+static void swap_out_buffer_local_variables ();
 
 /* Alist of all buffer names vs the buffers. */
 /* This used to be a variable, but is no longer,
@@ -126,7 +128,10 @@ Lisp_Object Vkill_buffer_query_functions;
 
 /* List of functions to call before changing an unmodified buffer.  */
 Lisp_Object Vfirst_change_hook;
+
 Lisp_Object Qfirst_change_hook;
+Lisp_Object Qbefore_change_functions;
+Lisp_Object Qafter_change_functions;
 
 Lisp_Object Qfundamental_mode, Qmode_class, Qpermanent_local;
 
@@ -140,7 +145,7 @@ Lisp_Object Qget_file_buffer;
 
 Lisp_Object Qoverlayp;
 
-Lisp_Object Qpriority, Qwindow, Qevaporate;
+Lisp_Object Qpriority, Qwindow, Qevaporate, Qbefore_string, Qafter_string;
 
 Lisp_Object Qmodification_hooks;
 Lisp_Object Qinsert_in_front_hooks;
@@ -231,6 +236,24 @@ See also `find-buffer-visiting'.")
   return Qnil;
 }
 
+Lisp_Object
+get_truename_buffer (filename)
+     register Lisp_Object filename;
+{
+  register Lisp_Object tail, buf, tem;
+
+  for (tail = Vbuffer_alist; CONSP (tail); tail = XCONS (tail)->cdr)
+    {
+      buf = Fcdr (XCONS (tail)->car);
+      if (!BUFFERP (buf)) continue;
+      if (!STRINGP (XBUFFER (buf)->file_truename)) continue;
+      tem = Fstring_equal (XBUFFER (buf)->file_truename, filename);
+      if (!NILP (tem))
+       return buf;
+    }
+  return Qnil;
+}
+
 /* Incremented for each buffer created, to assign the buffer number. */
 int buffer_count;
 
@@ -315,7 +338,7 @@ The value is never nil.")
 
 DEFUN ("make-indirect-buffer",
        Fmake_indirect_buffer, Smake_indirect_buffer, 2, 2,
-       "BMake indirect buffer (to buffer): \nbName of indirect buffer: ",
+       "bMake indirect buffer (to buffer): \nBName of indirect buffer: ",
   "Create and return an indirect buffer for buffer BASE, named NAME.\n\
 BASE should be an existing buffer (or buffer name).\n\
 NAME should be a string which is not the name of an existing buffer.")
@@ -673,7 +696,7 @@ A non-nil FLAG means mark the buffer modified.")
   /* If buffer becoming modified, lock the file.
      If buffer becoming unmodified, unlock the file.  */
 
-  fn = current_buffer->filename;
+  fn = current_buffer->file_truename;
   if (!NILP (fn))
     {
       already = SAVE_MODIFF < MODIFF;
@@ -805,8 +828,8 @@ If BUFFER is omitted or nil, some interesting buffer is returned.")
   return Fget_buffer_create (build_string ("*scratch*"));
 }
 \f
-DEFUN ("buffer-disable-undo", Fbuffer_disable_undo, Sbuffer_disable_undo, 0, 1,
-0,
+DEFUN ("buffer-disable-undo", Fbuffer_disable_undo, Sbuffer_disable_undo,
+       0, 1, "",
   "Make BUFFER stop keeping undo information.\n\
 No argument or nil as argument means do this for the current buffer.")
   (buffer)
@@ -887,6 +910,10 @@ with `delete-process'.")
 
   b = XBUFFER (buf);
 
+  /* Avoid trouble for buffer already dead.  */
+  if (NILP (b->name))
+    return Qnil;
+
   /* Query if the buffer is still modified.  */
   if (INTERACTIVE && !NILP (b->filename)
       && BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
@@ -944,7 +971,9 @@ with `delete-process'.")
       GCPRO1 (buf);
 
       for (other = all_buffers; other; other = other->next)
-       if (other->base_buffer == b)
+       /* all_buffers contains dead buffers too;
+          don't re-kill them.  */
+       if (other->base_buffer == b && !NILP (other->name))
          {
            Lisp_Object buf;
            XSETBUFFER (buf, other);
@@ -990,11 +1019,26 @@ with `delete-process'.")
        internal_delete_file (b->auto_save_file_name);
     }
 
-  if (b->base_buffer)
+  if (b->base_buffer)
     {
-      /* Unchain all markers of this buffer
+      /* Unchain all markers that belong to this indirect buffer.
+        Don't unchain the markers that belong to the base buffer
+        or its other indirect buffers.  */
+      for (tem = BUF_MARKERS (b); !NILP (tem); )
+       {
+         Lisp_Object next;
+         m = XMARKER (tem);
+         next = m->chain;
+         if (m->buffer == b)
+           unchain_marker (tem);
+         tem = next;
+       }
+    }
+  else
+    {
+      /* Unchain all markers of this buffer and its indirect buffers.
         and leave them pointing nowhere.  */
-      for (tem = BUF_MARKERS (b); !EQ (tem, Qnil); )
+      for (tem = BUF_MARKERS (b); !NILP (tem); )
        {
          m = XMARKER (tem);
          m->buffer = 0;
@@ -1010,6 +1054,13 @@ with `delete-process'.")
       /* Perhaps we should explicitly free the interval tree here... */
     }
 
+  /* Reset the local variables, so that this buffer's local values
+     won't be protected from GC.  They would be protected
+     if they happened to remain encached in their symbols.
+     This gets rid of them for certain.  */
+  swap_out_buffer_local_variables (b);
+  reset_buffer_local_variables (b);
+
   b->name = Qnil;
 
   BLOCK_INPUT;
@@ -1173,7 +1224,7 @@ DEFUN ("current-buffer", Fcurrent_buffer, Scurrent_buffer, 0, 0, 0,
   return buf;
 }
 \f
-/* Set the current buffer to b */
+/* Set the current buffer to B.  */
 
 void
 set_buffer_internal (b)
@@ -1187,6 +1238,23 @@ set_buffer_internal (b)
     return;
 
   windows_or_buffers_changed = 1;
+  set_buffer_internal_1 (b);
+}
+
+/* Set the current buffer to B, and do not set windows_or_buffers_changed.
+   This is used by redisplay.  */
+
+void
+set_buffer_internal_1 (b)
+     register struct buffer *b;
+{
+  register struct buffer *old_buf;
+  register Lisp_Object tail, valcontents;
+  Lisp_Object tem;
+
+  if (current_buffer == b)
+    return;
+
   old_buf = current_buffer;
   current_buffer = b;
   last_known_column_point = -1;   /* invalidate indentation cache */
@@ -1266,7 +1334,7 @@ set_buffer_internal (b)
 }
 
 /* Switch to buffer B temporarily for redisplay purposes.
-   This avoids certain things thatdon't need to be done within redisplay.  */
+   This avoids certain things that don't need to be done within redisplay.  */
 
 void
 set_buffer_temp (b)
@@ -1445,37 +1513,10 @@ the normal hook `change-major-mode-hook'.")
     call1 (Vrun_hooks, intern ("change-major-mode-hook"));
   oalist = current_buffer->local_var_alist;
 
-  /* Make sure no local variables remain set up with this buffer
-     for their current values.  */
+  /* Make sure none of the bindings in oalist
+     remain swapped in, in their symbols.  */
 
-  for (alist = oalist; !NILP (alist); alist = XCONS (alist)->cdr)
-    {
-      sym = XCONS (XCONS (alist)->car)->car;
-
-      /* Need not do anything if some other buffer's binding is now encached.  */
-      tem = XCONS (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->cdr)->car;
-      if (XBUFFER (tem) == current_buffer)
-       {
-         /* Symbol is set up for this buffer's old local value.
-            Set it up for the current buffer with the default value.  */
-
-         tem = XCONS (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->cdr)->cdr;
-         /* Store the symbol's current value into the alist entry
-            it is currently set up for.  This is so that, if the
-            local is marked permanent, and we make it local again below,
-            we don't lose the value.  */
-         XCONS (XCONS (tem)->car)->cdr
-           = do_symval_forwarding (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->car);
-         /* Switch to the symbol's default-value alist entry.  */
-         XCONS (tem)->car = tem;
-         /* Mark it as current for the current buffer.  */
-         XCONS (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->cdr)->car
-           = Fcurrent_buffer ();
-         /* Store the current value into any forwarding in the symbol.  */
-         store_symval_forwarding (sym, XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->car,
-                                  XCONS (tem)->cdr);
-       }
-    }
+  swap_out_buffer_local_variables (current_buffer);
 
   /* Actually eliminate all local bindings of this buffer.  */
 
@@ -1505,13 +1546,55 @@ the normal hook `change-major-mode-hook'.")
 
   return Qnil;
 }
+
+/* Make sure no local variables remain set up with buffer B
+   for their current values.  */
+
+static void
+swap_out_buffer_local_variables (b)
+     struct buffer *b;
+{
+  Lisp_Object oalist, alist, sym, tem, buffer;
+
+  XSETBUFFER (buffer, b);
+  oalist = b->local_var_alist;
+
+  for (alist = oalist; !NILP (alist); alist = XCONS (alist)->cdr)
+    {
+      sym = XCONS (XCONS (alist)->car)->car;
+
+      /* Need not do anything if some other buffer's binding is now encached.  */
+      tem = XCONS (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->cdr)->car;
+      if (XBUFFER (tem) == current_buffer)
+       {
+         /* Symbol is set up for this buffer's old local value.
+            Set it up for the current buffer with the default value.  */
+
+         tem = XCONS (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->cdr)->cdr;
+         /* Store the symbol's current value into the alist entry
+            it is currently set up for.  This is so that, if the
+            local is marked permanent, and we make it local again
+            later in Fkill_all_local_variables, we don't lose the value.  */
+         XCONS (XCONS (tem)->car)->cdr
+           = do_symval_forwarding (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->car);
+         /* Switch to the symbol's default-value alist entry.  */
+         XCONS (tem)->car = tem;
+         /* Mark it as current for buffer B.  */
+         XCONS (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->cdr)->car
+           = buffer;
+         /* Store the current value into any forwarding in the symbol.  */
+         store_symval_forwarding (sym, XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->car,
+                                  XCONS (tem)->cdr);
+       }
+    }
+}
 \f
 /* Find all the overlays in the current buffer that contain position POS.
    Return the number found, and store them in a vector in *VEC_PTR.  
    Store in *LEN_PTR the size allocated for the vector.
    Store in *NEXT_PTR the next position after POS where an overlay starts,
      or ZV if there are no more overlays.
-   Store in *PREV_PTR the previous position after POS where an overlay ends,
+   Store in *PREV_PTR the previous position before POS where an overlay ends,
      or BEGV if there are no previous overlays.
    NEXT_PTR and/or PREV_PTR may be 0, meaning don't store that info.
 
@@ -1631,7 +1714,139 @@ overlays_at (pos, extend, vec_ptr, len_ptr, next_ptr, prev_ptr)
     *prev_ptr = prev;
   return idx;
 }
+\f
+/* Find all the overlays in the current buffer that overlap the range BEG-END
+   or are empty at BEG.
+
+   Return the number found, and store them in a vector in *VEC_PTR.  
+   Store in *LEN_PTR the size allocated for the vector.
+   Store in *NEXT_PTR the next position after POS where an overlay starts,
+     or ZV if there are no more overlays.
+   Store in *PREV_PTR the previous position before POS where an overlay ends,
+     or BEGV if there are no previous overlays.
+   NEXT_PTR and/or PREV_PTR may be 0, meaning don't store that info.
+
+   *VEC_PTR and *LEN_PTR should contain a valid vector and size
+   when this function is called.
+
+   If EXTEND is non-zero, we make the vector bigger if necessary.
+   If EXTEND is zero, we never extend the vector,
+   and we store only as many overlays as will fit.
+   But we still return the total number of overlays.  */
+
+int
+overlays_in (beg, end, extend, vec_ptr, len_ptr, next_ptr, prev_ptr)
+     int beg, end;
+     int extend;
+     Lisp_Object **vec_ptr;
+     int *len_ptr;
+     int *next_ptr;
+     int *prev_ptr;
+{
+  Lisp_Object tail, overlay, ostart, oend, result;
+  int idx = 0;
+  int len = *len_ptr;
+  Lisp_Object *vec = *vec_ptr;
+  int next = ZV;
+  int prev = BEGV;
+  int inhibit_storing = 0;
+
+  for (tail = current_buffer->overlays_before;
+       GC_CONSP (tail);
+       tail = XCONS (tail)->cdr)
+    {
+      int startpos, endpos;
+
+      overlay = XCONS (tail)->car;
+
+      ostart = OVERLAY_START (overlay);
+      oend = OVERLAY_END (overlay);
+      endpos = OVERLAY_POSITION (oend);
+      if (endpos < beg)
+       {
+         if (prev < endpos)
+           prev = endpos;
+         break;
+       }
+      startpos = OVERLAY_POSITION (ostart);
+      /* Count an interval if it either overlaps the range
+        or is empty at the start of the range.  */
+      if ((beg < endpos && startpos < end)
+         || (startpos == endpos && beg == endpos))
+       {
+         if (idx == len)
+           {
+             /* The supplied vector is full.
+                Either make it bigger, or don't store any more in it.  */
+             if (extend)
+               {
+                 *len_ptr = len *= 2;
+                 vec = (Lisp_Object *) xrealloc (vec, len * sizeof (Lisp_Object));
+                 *vec_ptr = vec;
+               }
+             else
+               inhibit_storing = 1;
+           }
+
+         if (!inhibit_storing)
+           vec[idx] = overlay;
+         /* Keep counting overlays even if we can't return them all.  */
+         idx++;
+       }
+      else if (startpos < next)
+       next = startpos;
+    }
+
+  for (tail = current_buffer->overlays_after;
+       GC_CONSP (tail);
+       tail = XCONS (tail)->cdr)
+    {
+      int startpos, endpos;
+
+      overlay = XCONS (tail)->car;
 
+      ostart = OVERLAY_START (overlay);
+      oend = OVERLAY_END (overlay);
+      startpos = OVERLAY_POSITION (ostart);
+      if (end < startpos)
+       {
+         if (startpos < next)
+           next = startpos;
+         break;
+       }
+      endpos = OVERLAY_POSITION (oend);
+      /* Count an interval if it either overlaps the range
+        or is empty at the start of the range.  */
+      if ((beg < endpos && startpos < end)
+         || (startpos == endpos && beg == endpos))
+       {
+         if (idx == len)
+           {
+             if (extend)
+               {
+                 *len_ptr = len *= 2;
+                 vec = (Lisp_Object *) xrealloc (vec, len * sizeof (Lisp_Object));
+                 *vec_ptr = vec;
+               }
+             else
+               inhibit_storing = 1;
+           }
+
+         if (!inhibit_storing)
+           vec[idx] = overlay;
+         idx++;
+       }
+      else if (endpos < beg && endpos > prev)
+       prev = endpos;
+    }
+
+  if (next_ptr)
+    *next_ptr = next;
+  if (prev_ptr)
+    *prev_ptr = prev;
+  return idx;
+}
+\f
 /* Fast function to just test if we're at an overlay boundary.  */
 int
 overlay_touches_p (pos)
@@ -1753,6 +1968,194 @@ sort_overlays (overlay_vec, noverlays, w)
   return (noverlays);
 }
 \f
+struct sortstr
+{
+  Lisp_Object string, string2;
+  int size;
+  int priority;
+};
+
+struct sortstrlist
+{
+  struct sortstr *buf; /* An array that expands as needed; never freed.  */
+  int size;            /* Allocated length of that array.  */
+  int used;            /* How much of the array is currently in use.  */
+  int bytes;           /* Total length of the strings in buf.  */
+};
+
+/* Buffers for storing information about the overlays touching a given
+   position.  These could be automatic variables in overlay_strings, but
+   it's more efficient to hold onto the memory instead of repeatedly
+   allocating and freeing it.  */
+static struct sortstrlist overlay_heads, overlay_tails;
+static char *overlay_str_buf;
+
+/* Allocated length of overlay_str_buf.  */
+static int overlay_str_len;
+
+/* A comparison function suitable for passing to qsort.  */
+static int
+cmp_for_strings (as1, as2)
+     char *as1, *as2;
+{
+  struct sortstr *s1 = (struct sortstr *)as1;
+  struct sortstr *s2 = (struct sortstr *)as2;
+  if (s1->size != s2->size)
+    return s2->size - s1->size;
+  if (s1->priority != s2->priority)
+    return s1->priority - s2->priority;
+  return 0;
+}
+
+static void
+record_overlay_string (ssl, str, str2, pri, size)
+     struct sortstrlist *ssl;
+     Lisp_Object str, str2, pri;
+     int size;
+{
+  if (ssl->used == ssl->size)
+    {
+      if (ssl->buf)
+       ssl->size *= 2;
+      else
+       ssl->size = 5;
+      ssl->buf = ((struct sortstr *)
+                 xrealloc (ssl->buf, ssl->size * sizeof (struct sortstr)));
+    }
+  ssl->buf[ssl->used].string = str;
+  ssl->buf[ssl->used].string2 = str2;
+  ssl->buf[ssl->used].size = size;
+  ssl->buf[ssl->used].priority = (INTEGERP (pri) ? XINT (pri) : 0);
+  ssl->used++;
+  ssl->bytes += XSTRING (str)->size;
+  if (STRINGP (str2))
+    ssl->bytes += XSTRING (str2)->size;
+}
+
+/* Return the concatenation of the strings associated with overlays that
+   begin or end at POS, ignoring overlays that are specific to a window
+   other than W.  The strings are concatenated in the appropriate order:
+   shorter overlays nest inside longer ones, and higher priority inside
+   lower.  Normally all of the after-strings come first, but zero-sized
+   overlays have their after-strings ride along with the before-strings
+   because it would look strange to print them inside-out.
+
+   Returns the string length, and stores the contents indirectly through
+   PSTR, if that variable is non-null.  The string may be overwritten by
+   subsequent calls.  */
+int
+overlay_strings (pos, w, pstr)
+     int pos;
+     struct window *w;
+     char **pstr;
+{
+  Lisp_Object ov, overlay, window, str;
+  int startpos, endpos;
+
+  overlay_heads.used = overlay_heads.bytes = 0;
+  overlay_tails.used = overlay_tails.bytes = 0;
+  for (ov = current_buffer->overlays_before; CONSP (ov); ov = XCONS (ov)->cdr)
+    {
+      overlay = XCONS (ov)->car;
+      if (!OVERLAYP (overlay))
+       abort ();
+
+      startpos = OVERLAY_POSITION (OVERLAY_START (overlay));
+      endpos = OVERLAY_POSITION (OVERLAY_END (overlay));
+      if (endpos < pos)
+       break;
+      if (endpos != pos && startpos != pos)
+       continue;
+      window = Foverlay_get (overlay, Qwindow);
+      if (WINDOWP (window) && XWINDOW (window) != w)
+       continue;
+      if (startpos == pos
+         && (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str)))
+       record_overlay_string (&overlay_heads, str,
+                              (startpos == endpos
+                               ? Foverlay_get (overlay, Qafter_string)
+                               : Qnil),
+                              Foverlay_get (overlay, Qpriority),
+                              endpos - startpos);
+      else if (endpos == pos
+         && (str = Foverlay_get (overlay, Qafter_string), STRINGP (str)))
+       record_overlay_string (&overlay_tails, str, Qnil,
+                              Foverlay_get (overlay, Qpriority),
+                              endpos - startpos);
+    }
+  for (ov = current_buffer->overlays_after; CONSP (ov); ov = XCONS (ov)->cdr)
+    {
+      overlay = XCONS (ov)->car;
+      if (!OVERLAYP (overlay))
+       abort ();
+
+      startpos = OVERLAY_POSITION (OVERLAY_START (overlay));
+      endpos = OVERLAY_POSITION (OVERLAY_END (overlay));
+      if (startpos > pos)
+       break;
+      if (endpos != pos && startpos != pos)
+       continue;
+      window = Foverlay_get (overlay, Qwindow);
+      if (WINDOWP (window) && XWINDOW (window) != w)
+       continue;
+      if (startpos == pos
+         && (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str)))
+       record_overlay_string (&overlay_heads, str,
+                              (startpos == endpos
+                               ? Foverlay_get (overlay, Qafter_string)
+                               : Qnil),
+                              Foverlay_get (overlay, Qpriority),
+                              endpos - startpos);
+      else if (endpos == pos
+              && (str = Foverlay_get (overlay, Qafter_string), STRINGP (str)))
+       record_overlay_string (&overlay_tails, str, Qnil,
+                              Foverlay_get (overlay, Qpriority),
+                              endpos - startpos);
+    }
+  if (overlay_tails.used > 1)
+    qsort (overlay_tails.buf, overlay_tails.used, sizeof (struct sortstr),
+          cmp_for_strings);
+  if (overlay_heads.used > 1)
+    qsort (overlay_heads.buf, overlay_heads.used, sizeof (struct sortstr),
+          cmp_for_strings);
+  if (overlay_heads.bytes || overlay_tails.bytes)
+    {
+      Lisp_Object tem;
+      int i;
+      char *p;
+      int total = overlay_heads.bytes + overlay_tails.bytes;
+
+      if (total > overlay_str_len)
+       overlay_str_buf = (char *)xrealloc (overlay_str_buf,
+                                           overlay_str_len = total);
+      p = overlay_str_buf;
+      for (i = overlay_tails.used; --i >= 0;)
+       {
+         tem = overlay_tails.buf[i].string;
+         bcopy (XSTRING (tem)->data, p, XSTRING (tem)->size);
+         p += XSTRING (tem)->size;
+       }
+      for (i = 0; i < overlay_heads.used; ++i)
+       {
+         tem = overlay_heads.buf[i].string;
+         bcopy (XSTRING (tem)->data, p, XSTRING (tem)->size);
+         p += XSTRING (tem)->size;
+         tem = overlay_heads.buf[i].string2;
+         if (STRINGP (tem))
+           {
+             bcopy (XSTRING (tem)->data, p, XSTRING (tem)->size);
+             p += XSTRING (tem)->size;
+           }
+       }
+      if (p != overlay_str_buf + total)
+       abort ();
+      if (pstr)
+       *pstr = overlay_str_buf;
+      return total;
+    }
+  return 0;
+}
+\f
 /* Shift overlays in BUF's overlay lists, to center the lists at POS.  */
 
 void
@@ -1915,6 +2318,40 @@ recenter_overlay_lists (buf, pos)
   XSETFASTINT (buf->overlay_center, pos);
 }
 
+void
+adjust_overlays_for_insert (pos, length)
+     int pos;
+     int length;
+{
+  /* After an insertion, the lists are still sorted properly,
+     but we may need to update the value of the overlay center.  */
+  if (XFASTINT (current_buffer->overlay_center) >= pos)
+    XSETFASTINT (current_buffer->overlay_center,
+                XFASTINT (current_buffer->overlay_center) + length);
+}
+
+void
+adjust_overlays_for_delete (pos, length)
+     int pos;
+     int length;
+{
+  if (XFASTINT (current_buffer->overlay_center) < pos)
+    /* The deletion was to our right.  No change needed; the before- and
+       after-lists are still consistent.  */
+    ;
+  else if (XFASTINT (current_buffer->overlay_center) > pos + length)
+    /* The deletion was to our left.  We need to adjust the center value
+       to account for the change in position, but the lists are consistent
+       given the new value.  */
+    XSETFASTINT (current_buffer->overlay_center,
+                XFASTINT (current_buffer->overlay_center) - length);
+  else
+    /* We're right in the middle.  There might be things on the after-list
+       that now belong on the before-list.  Recentering will move them,
+       and also update the center point.  */
+    recenter_overlay_lists (current_buffer, pos);
+}
+
 /* Fix up overlays that were garbled as a result of permuting markers
    in the range START through END.  Any overlay with at least one
    endpoint in this range will need to be unlinked from the overlay
@@ -2062,7 +2499,7 @@ BEG and END may be integers or markers.")
   end = Fset_marker (Fmake_marker (), end, buffer);
 
   overlay = allocate_misc ();
-  XMISC (overlay)->type = Lisp_Misc_Overlay;
+  XMISCTYPE (overlay) = Lisp_Misc_Overlay;
   XOVERLAY (overlay)->start = beg;
   XOVERLAY (overlay)->end = end;
   XOVERLAY (overlay)->plist = Qnil;
@@ -2146,9 +2583,6 @@ buffer.")
 
       /* Redisplay where the overlay is going to be.  */
       redisplay_region (b, XINT (beg), XINT (end));
-
-      /* Don't limit redisplay to the selected window.  */
-      windows_or_buffers_changed = 1;
     }
   else
     /* Redisplay the area the overlay has just left, or just enclosed.  */
@@ -2290,7 +2724,40 @@ DEFUN ("overlays-at", Foverlays_at, Soverlays_at, 1, 1, 0,
 
   /* Put all the overlays we want in a vector in overlay_vec.
      Store the length in len.  */
-  noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len, NULL, NULL);
+  noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
+                          (int *) 0, (int *) 0);
+
+  /* Make a list of them all.  */
+  result = Flist (noverlays, overlay_vec);
+
+  xfree (overlay_vec);
+  return result;
+}
+
+DEFUN ("overlays-in", Foverlays_in, Soverlays_in, 2, 2, 0,
+  "Return a list of the overlays that overlap the region BEG ... END.\n\
+Overlap means that at least one character is contained within the overlay\n\
+and also contained within the specified region.\n\
+Empty overlays are included in the result if they are located at BEG\n\
+or between BEG and END.")
+  (beg, end)
+     Lisp_Object beg, end;
+{
+  int noverlays;
+  Lisp_Object *overlay_vec;
+  int len;
+  Lisp_Object result;
+
+  CHECK_NUMBER_COERCE_MARKER (beg, 0);
+  CHECK_NUMBER_COERCE_MARKER (end, 0);
+
+  len = 10;
+  overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
+
+  /* Put all the overlays we want in a vector in overlay_vec.
+     Store the length in len.  */
+  noverlays = overlays_in (XINT (beg), XINT (end), 1, &overlay_vec, &len,
+                          (int *) 0, (int *) 0);
 
   /* Make a list of them all.  */
   result = Flist (noverlays, overlay_vec);
@@ -2320,7 +2787,8 @@ If there are no more overlay boundaries after POS, return (point-max).")
   /* Put all the overlays we want in a vector in overlay_vec.
      Store the length in len.
      endpos gets the position where the next overlay starts.  */
-  noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len, &endpos, NULL);
+  noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
+                          &endpos, (int *) 0);
 
   /* If any of these overlays ends before endpos,
      use its ending point instead.  */
@@ -2342,7 +2810,7 @@ If there are no more overlay boundaries after POS, return (point-max).")
 DEFUN ("previous-overlay-change", Fprevious_overlay_change,
        Sprevious_overlay_change, 1, 1, 0,
   "Return the previous position before POS where an overlay starts or ends.\n\
-If there are no more overlay boundaries after POS, return (point-min).")
+If there are no more overlay boundaries before POS, return (point-min).")
   (pos)
      Lisp_Object pos;
 {
@@ -2351,18 +2819,25 @@ If there are no more overlay boundaries after POS, return (point-min).")
   Lisp_Object *overlay_vec;
   int len;
   int i;
+  Lisp_Object tail;
 
   CHECK_NUMBER_COERCE_MARKER (pos, 0);
 
   len = 10;
   overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
 
+  /* At beginning of buffer, we know the answer;
+     avoid bug subtracting 1 below.  */
+  if (XINT (pos) == BEGV)
+    return pos;
+
   /* Put all the overlays we want in a vector in overlay_vec.
      Store the length in len.
      prevpos gets the position of an overlay end.  */
-  noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len, NULL, &prevpos);
+  noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
+                          (int *) 0, &prevpos);
 
-  /* If any of these overlays starts before endpos,
+  /* If any of these overlays starts after prevpos,
      maybe use its starting point instead.  */
   for (i = 0; i < noverlays; i++)
     {
@@ -2375,6 +2850,22 @@ If there are no more overlay boundaries after POS, return (point-min).")
        prevpos = ostartpos;
     }
 
+  /* If any overlay ends at pos, consider its starting point too.  */
+  for (tail = current_buffer->overlays_before;
+       GC_CONSP (tail);
+       tail = XCONS (tail)->cdr)
+    {
+      Lisp_Object overlay, ostart;
+      int ostartpos;
+
+      overlay = XCONS (tail)->car;
+
+      ostart = OVERLAY_START (overlay);
+      ostartpos = OVERLAY_POSITION (ostart);
+      if (ostartpos > prevpos && ostartpos < XINT (pos))
+       prevpos = ostartpos;
+    }
+
   xfree (overlay_vec);
   return make_number (prevpos);
 }
@@ -2481,15 +2972,58 @@ DEFUN ("overlay-put", Foverlay_put, Soverlay_put, 3, 3, 0,
   return value;
 }
 \f
+/* Subroutine of report_overlay_modification.  */
+
+/* Lisp vector holding overlay hook functions to call.
+   Vector elements come in pairs.
+   Each even-index element is a list of hook functions.
+   The following odd-index element is the overlay they came from.
+
+   Before the buffer change, we fill in this vector
+   as we call overlay hook functions.
+   After the buffer change, we get the functions to call from this vector.
+   This way we always call the same functions before and after the change.  */
+static Lisp_Object last_overlay_modification_hooks;
+
+/* Number of elements actually used in last_overlay_modification_hooks.  */
+static int last_overlay_modification_hooks_used;
+
+/* Add one functionlist/overlay pair
+   to the end of last_overlay_modification_hooks.  */
+
+static void
+add_overlay_mod_hooklist (functionlist, overlay)
+     Lisp_Object functionlist, overlay;
+{
+  int oldsize = XVECTOR (last_overlay_modification_hooks)->size;
+
+  if (last_overlay_modification_hooks_used == oldsize)
+    {
+      Lisp_Object old;
+      old = last_overlay_modification_hooks;
+      last_overlay_modification_hooks
+       = Fmake_vector (make_number (oldsize * 2), Qnil);
+      bcopy (XVECTOR (last_overlay_modification_hooks)->contents,
+            XVECTOR (old)->contents,
+            sizeof (Lisp_Object) * oldsize);
+    }
+  XVECTOR (last_overlay_modification_hooks)->contents[last_overlay_modification_hooks_used++] = functionlist;
+  XVECTOR (last_overlay_modification_hooks)->contents[last_overlay_modification_hooks_used++] = overlay;
+}
+\f
 /* Run the modification-hooks of overlays that include
    any part of the text in START to END.
-   Run the insert-before-hooks of overlay starting at END,
+   If this change is an insertion, also
+   run the insert-before-hooks of overlay starting at END,
    and the insert-after-hooks of overlay ending at START.
 
    This is called both before and after the modification.
    AFTER is nonzero when we call after the modification.
 
-   ARG1, ARG2, ARG3 are arguments to pass to the hook functions.  */
+   ARG1, ARG2, ARG3 are arguments to pass to the hook functions.
+   When AFTER is nonzero, they are the start position,
+   the position after the inserted new text,
+   and the length of deleted or replaced old text.  */
 
 void
 report_overlay_modification (start, end, after, arg1, arg2, arg3)
@@ -2498,7 +3032,8 @@ report_overlay_modification (start, end, after, arg1, arg2, arg3)
      Lisp_Object arg1, arg2, arg3;
 {
   Lisp_Object prop, overlay, tail;
-  int insertion = EQ (start, end);
+  /* 1 if this change is an insertion.  */
+  int insertion = (after ? XFASTINT (arg3) == 0 : EQ (start, end));
   int tail_copied;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
 
@@ -2506,6 +3041,35 @@ report_overlay_modification (start, end, after, arg1, arg2, arg3)
   tail = Qnil;
   GCPRO5 (overlay, tail, arg1, arg2, arg3);
 
+  if (after)
+    {
+      /* Call the functions recorded in last_overlay_modification_hooks
+        rather than scanning the overlays again.
+        First copy the vector contents, in case some of these hooks
+        do subsequent modification of the buffer.  */
+      int size = last_overlay_modification_hooks_used;
+      Lisp_Object *copy = (Lisp_Object *) alloca (size * sizeof (Lisp_Object));
+      int i;
+
+      bcopy (XVECTOR (last_overlay_modification_hooks)->contents,
+            copy, size * sizeof (Lisp_Object));
+      gcpro1.var = copy;
+      gcpro1.nvars = size;
+
+      for (i = 0; i < size;)
+       {
+         Lisp_Object prop, overlay;
+         prop = copy[i++];
+         overlay = copy[i++];
+         call_overlay_mod_hooks (prop, overlay, after, arg1, arg2, arg3);
+       }
+      UNGCPRO;
+      return;
+    }
+
+  /* We are being called before a change.
+     Scan the overlays to find the functions to call.  */
+  last_overlay_modification_hooks_used = 0;
   tail_copied = 0;
   for (tail = current_buffer->overlays_before;
        CONSP (tail);
@@ -2522,7 +3086,8 @@ report_overlay_modification (start, end, after, arg1, arg2, arg3)
       if (XFASTINT (start) > endpos)
        break;
       startpos = OVERLAY_POSITION (ostart);
-      if (XFASTINT (end) == startpos && insertion)
+      if (insertion && (XFASTINT (start) == startpos
+                       || XFASTINT (end) == startpos))
        {
          prop = Foverlay_get (overlay, Qinsert_in_front_hooks);
          if (!NILP (prop))
@@ -2534,7 +3099,8 @@ report_overlay_modification (start, end, after, arg1, arg2, arg3)
              call_overlay_mod_hooks (prop, overlay, after, arg1, arg2, arg3);
            }
        }
-      if (XFASTINT (start) == endpos && insertion)
+      if (insertion && (XFASTINT (start) == endpos
+                       || XFASTINT (end) == endpos))
        {
          prop = Foverlay_get (overlay, Qinsert_behind_hooks);
          if (!NILP (prop))
@@ -2576,7 +3142,8 @@ report_overlay_modification (start, end, after, arg1, arg2, arg3)
       endpos = OVERLAY_POSITION (oend);
       if (XFASTINT (end) < startpos)
        break;
-      if (XFASTINT (end) == startpos && insertion)
+      if (insertion && (XFASTINT (start) == startpos
+                       || XFASTINT (end) == startpos))
        {
          prop = Foverlay_get (overlay, Qinsert_in_front_hooks);
          if (!NILP (prop))
@@ -2587,7 +3154,8 @@ report_overlay_modification (start, end, after, arg1, arg2, arg3)
              call_overlay_mod_hooks (prop, overlay, after, arg1, arg2, arg3);
            }
        }
-      if (XFASTINT (start) == endpos && insertion)
+      if (insertion && (XFASTINT (start) == endpos
+                       || XFASTINT (end) == endpos))
        {
          prop = Foverlay_get (overlay, Qinsert_behind_hooks);
          if (!NILP (prop))
@@ -2623,7 +3191,11 @@ call_overlay_mod_hooks (list, overlay, after, arg1, arg2, arg3)
      Lisp_Object arg1, arg2, arg3;
 {
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+
   GCPRO4 (list, arg1, arg2, arg3);
+  if (! after)
+    add_overlay_mod_hooklist (list, overlay);
+
   while (!NILP (list))
     {
       if (NILP (arg3))
@@ -2654,7 +3226,7 @@ evaporate_overlays (pos)
        if (endpos < pos)
          break;
        if (endpos == pos && OVERLAY_POSITION (OVERLAY_START (overlay)) == pos
-           && Foverlay_get (overlay, Qevaporate))
+           && ! NILP (Foverlay_get (overlay, Qevaporate)))
          hit_list = Fcons (overlay, hit_list);
       }
   else
@@ -2667,7 +3239,7 @@ evaporate_overlays (pos)
        if (startpos > pos)
          break;
        if (startpos == pos && OVERLAY_POSITION (OVERLAY_END (overlay)) == pos
-           && Foverlay_get (overlay, Qevaporate))
+           && ! NILP (Foverlay_get (overlay, Qevaporate)))
          hit_list = Fcons (overlay, hit_list);
       }
   for (; CONSP (hit_list); hit_list = XCONS (hit_list)->cdr)
@@ -2736,7 +3308,7 @@ init_buffer_once ()
   buffer_defaults.file_format = Qnil;
   buffer_defaults.overlays_before = Qnil;
   buffer_defaults.overlays_after = Qnil;
-  XSETFASTINT (buffer_defaults.overlay_center, 1);
+  XSETFASTINT (buffer_defaults.overlay_center, BEG);
 
   XSETFASTINT (buffer_defaults.tab_width, 8);
   buffer_defaults.truncate_lines = Qnil;
@@ -2864,6 +3436,10 @@ syms_of_buffer ()
 {
   extern Lisp_Object Qdisabled;
 
+  staticpro (&last_overlay_modification_hooks);
+  last_overlay_modification_hooks
+    = Fmake_vector (make_number (10), Qnil);
+
   staticpro (&Vbuffer_defaults);
   staticpro (&Vbuffer_local_symbols);
   staticpro (&Qfundamental_mode);
@@ -2873,23 +3449,32 @@ syms_of_buffer ()
   staticpro (&Qprotected_field);
   staticpro (&Qpermanent_local);
   staticpro (&Qkill_buffer_hook);
+  Qoverlayp = intern ("overlayp");
   staticpro (&Qoverlayp);
   Qevaporate = intern ("evaporate");
   staticpro (&Qevaporate);
-  staticpro (&Qmodification_hooks);
   Qmodification_hooks = intern ("modification-hooks");
-  staticpro (&Qinsert_in_front_hooks);
+  staticpro (&Qmodification_hooks);
   Qinsert_in_front_hooks = intern ("insert-in-front-hooks");
-  staticpro (&Qinsert_behind_hooks);
+  staticpro (&Qinsert_in_front_hooks);
   Qinsert_behind_hooks = intern ("insert-behind-hooks");
-  staticpro (&Qget_file_buffer);
+  staticpro (&Qinsert_behind_hooks);
   Qget_file_buffer = intern ("get-file-buffer");
+  staticpro (&Qget_file_buffer);
   Qpriority = intern ("priority");
   staticpro (&Qpriority);
   Qwindow = intern ("window");
   staticpro (&Qwindow);
-
-  Qoverlayp = intern ("overlayp");
+  Qbefore_string = intern ("before-string");
+  staticpro (&Qbefore_string);
+  Qafter_string = intern ("after-string");
+  staticpro (&Qafter_string);
+  Qfirst_change_hook = intern ("first-change-hook");
+  staticpro (&Qfirst_change_hook);
+  Qbefore_change_functions = intern ("before-change-functions");
+  staticpro (&Qbefore_change_functions);
+  Qafter_change_functions = intern ("after-change-functions");
+  staticpro (&Qafter_change_functions);
 
   Fput (Qprotected_field, Qerror_conditions,
        Fcons (Qprotected_field, Fcons (Qerror, Qnil)));
@@ -3068,8 +3653,9 @@ Each buffer has its own value of this variable.");
 
   DEFVAR_PER_BUFFER ("buffer-file-truename", &current_buffer->file_truename,
                     make_number (Lisp_String),
-    "Truename of file visited in current buffer, or nil if not visiting a file.\n\
-The truename of a file is calculated by `file-truename'.\n\
+    "Abbreviated truename of file visited in current buffer, or nil if none.\n\
+The truename of a file is calculated by `file-truename'\n\
+and then abbreviated with `abbreviate-file-name'.\n\
 Each buffer has its own value of this variable.");
 
   DEFVAR_PER_BUFFER ("buffer-auto-save-file-name",
@@ -3220,8 +3806,6 @@ accomplishing an equivalent result by using other variables.");
   "A list of functions to call before changing a buffer which is unmodified.\n\
 The functions are run using the `run-hooks' function.");
   Vfirst_change_hook = Qnil;
-  Qfirst_change_hook = intern ("first-change-hook");
-  staticpro (&Qfirst_change_hook);
 
 #if 0 /* The doc string is too long for some compilers,
         but make-docfile can find it in this comment.  */
@@ -3229,8 +3813,8 @@ The functions are run using the `run-hooks' function.");
     "List of undo entries in current buffer.\n\
 Recent changes come first; older changes follow newer.\n\
 \n\
-An entry (START . END) represents an insertion which begins at\n\
-position START and ends at position END.\n\
+An entry (BEG . END) represents an insertion which begins at\n\
+position BEG and ends at position END.\n\
 \n\
 An entry (TEXT . POSITION) represents the deletion of the string TEXT\n\
 from (abs POSITION).  If POSITION is positive, point was at the front\n\
@@ -3306,8 +3890,8 @@ The default is t, which means that text is invisible\n\
 if it has a non-nil `invisible' property.\n\
 If the value is a list, a text character is invisible if its `invisible'\n\
 property is an element in that list.\n\
-If an element is a cons cell of the for (PROP . ELLIPSIS),\n\
-then characters with property value PROP is invisible,\n\
+If an element is a cons cell of the form (PROP . ELLIPSIS),\n\
+then characters with property value PROP are invisible,\n\
 and they have an ellipsis as well if ELLIPSIS is non-nil.");
 
   DEFVAR_LISP ("transient-mark-mode", &Vtransient_mark_mode,
@@ -3364,6 +3948,7 @@ is a member of the list.");
   defsubr (&Soverlay_buffer);
   defsubr (&Soverlay_properties);
   defsubr (&Soverlays_at);
+  defsubr (&Soverlays_in);
   defsubr (&Snext_overlay_change);
   defsubr (&Sprevious_overlay_change);
   defsubr (&Soverlay_recenter);