]> code.delx.au - gnu-emacs/blobdiff - src/buffer.c
(Fother_buffer): Doc fix.
[gnu-emacs] / src / buffer.c
index 323d697f06b9a2cd1176343a4993e67c24699b7d..8dc2c848ee930f38dc4573728834cfe0c24c0ad0 100644 (file)
@@ -33,6 +33,12 @@ extern int errno;
 #endif /* not MAXPATHLEN */
 
 #include <config.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 #include "lisp.h"
 #include "intervals.h"
 #include "window.h"
@@ -100,8 +106,11 @@ static Lisp_Object Vbuffer_local_symbols;
    buffer-local slots.  If a slot contains Qnil, then the
    corresponding buffer slot may contain a value of any type.  If a
    slot contains an integer, then prospective values' tags must be
-   equal to that integer.  When a tag does not match, the function
-   buffer_slot_type_mismatch will signal an error.  */
+   equal to that integer (except nil is always allowed).
+   When a tag does not match, the function
+   buffer_slot_type_mismatch will signal an error.
+
+   If a slot here contains -1, the corresponding variable is read-only.  */
 struct buffer buffer_local_types;
 
 /* Flags indicating which built-in buffer-local variables
@@ -518,8 +527,10 @@ reset_buffer (b)
   b->file_format = Qnil;
   b->last_selected_window = Qnil;
   XSETINT (b->display_count, 0);
+  b->display_time = Qnil;
   b->extra2 = Qnil;
   b->extra3 = Qnil;
+  b->enable_multibyte_characters = buffer_defaults.enable_multibyte_characters;
 }
 
 /* Reset buffer B's local variables info.
@@ -879,26 +890,31 @@ This does not change the name of the visited file (if any).")
   return current_buffer->name;
 }
 
-DEFUN ("other-buffer", Fother_buffer, Sother_buffer, 0, 2, 0,
+DEFUN ("other-buffer", Fother_buffer, Sother_buffer, 0, 3, 0,
   "Return most recently selected buffer other than BUFFER.\n\
 Buffers not visible in windows are preferred to visible buffers,\n\
 unless optional second argument VISIBLE-OK is non-nil.\n\
+If the optional third argument FRAME is non-nil, use that frame's\n\
+buffer list instead of the selected frame's buffer list.\n\
 If no other buffer exists, the buffer `*scratch*' is returned.\n\
 If BUFFER is omitted or nil, some interesting buffer is returned.")
-  (buffer, visible_ok)
-     register Lisp_Object buffer, visible_ok;
+  (buffer, visible_ok, frame)
+     register Lisp_Object buffer, visible_ok, frame;
 {
   Lisp_Object Fset_buffer_major_mode ();
   register Lisp_Object tail, buf, notsogood, tem, pred, add_ons;
   notsogood = Qnil;
 
+  if (NILP (frame))
+    frame = Fselected_frame ();
+
   tail = Vbuffer_alist;
-  pred = frame_buffer_predicate ();
+  pred = frame_buffer_predicate (frame);
 
   /* Consider buffers that have been seen in the selected frame
      before other buffers.  */
     
-  tem = frame_buffer_list ();
+  tem = frame_buffer_list (frame);
   add_ons = Qnil;
   while (CONSP (tem))
     {
@@ -1100,7 +1116,7 @@ with SIGHUP.")
      and give up if so.  */
   if (b == current_buffer)
     {
-      tem = Fother_buffer (buf, Qnil);
+      tem = Fother_buffer (buf, Qnil, Qnil);
       Fset_buffer (tem);
       if (b == current_buffer)
        return Qnil;
@@ -1208,6 +1224,8 @@ record_buffer (buf)
      Lisp_Object buf;
 {
   register Lisp_Object link, prev;
+  Lisp_Object frame;
+  frame = Fselected_frame ();
 
   prev = Qnil;
   for (link = Vbuffer_alist; CONSP (link); link = XCONS (link)->cdr)
@@ -1231,7 +1249,8 @@ record_buffer (buf)
   /* Now move this buffer to the front of frame_buffer_list also.  */
 
   prev = Qnil;
-  for (link = frame_buffer_list (); CONSP (link); link = XCONS (link)->cdr)
+  for (link = frame_buffer_list (frame); CONSP (link);
+       link = XCONS (link)->cdr)
     {
       if (EQ (XCONS (link)->car, buf))
        break;
@@ -1243,15 +1262,16 @@ record_buffer (buf)
   if (CONSP (link))
     {
       if (NILP (prev))
-       set_frame_buffer_list (XCONS (frame_buffer_list ())->cdr);
+       set_frame_buffer_list (frame,
+                              XCONS (frame_buffer_list (frame))->cdr);
       else
        XCONS (prev)->cdr = XCONS (XCONS (prev)->cdr)->cdr;
        
-      XCONS (link)->cdr = frame_buffer_list ();
-      set_frame_buffer_list (link);
+      XCONS (link)->cdr = frame_buffer_list (frame);
+      set_frame_buffer_list (frame, link);
     }
   else
-    set_frame_buffer_list (Fcons (buf, frame_buffer_list ()));
+    set_frame_buffer_list (frame, Fcons (buf, frame_buffer_list (frame)));
 }
 
 DEFUN ("set-buffer-major-mode", Fset_buffer_major_mode, Sset_buffer_major_mode, 1, 1, 0,
@@ -1306,7 +1326,7 @@ the window-buffer correspondences.")
     error ("Cannot switch buffers in a dedicated window");
 
   if (NILP (buffer))
-    buf = Fother_buffer (Fcurrent_buffer (), Qnil);
+    buf = Fother_buffer (Fcurrent_buffer (), Qnil, Qnil);
   else
     {
       buf = Fget_buffer (buffer);
@@ -1344,7 +1364,7 @@ do not put this buffer at the front of the list of recently selected ones.")
 {
   register Lisp_Object buf;
   if (NILP (buffer))
-    buf = Fother_buffer (Fcurrent_buffer (), Qnil);
+    buf = Fother_buffer (Fcurrent_buffer (), Qnil, Qnil);
   else
     {
       buf = Fget_buffer (buffer);
@@ -1468,7 +1488,7 @@ set_buffer_internal_1 (b)
       valcontents = XSYMBOL (XCONS (XCONS (tail)->car)->car)->value;
       if ((BUFFER_LOCAL_VALUEP (valcontents)
           || SOME_BUFFER_LOCAL_VALUEP (valcontents))
-         && (tem = XBUFFER_LOCAL_VALUE (valcontents)->car,
+         && (tem = XBUFFER_LOCAL_VALUE (valcontents)->realvalue,
              (BOOLFWDP (tem) || INTFWDP (tem) || OBJFWDP (tem))))
        /* Just reference the variable
             to cause it to become set for this buffer.  */
@@ -1483,7 +1503,7 @@ set_buffer_internal_1 (b)
        valcontents = XSYMBOL (XCONS (XCONS (tail)->car)->car)->value;
        if ((BUFFER_LOCAL_VALUEP (valcontents)
             || SOME_BUFFER_LOCAL_VALUEP (valcontents))
-           && (tem = XBUFFER_LOCAL_VALUE (valcontents)->car,
+           && (tem = XBUFFER_LOCAL_VALUE (valcontents)->realvalue,
                (BOOLFWDP (tem) || INTFWDP (tem) || OBJFWDP (tem))))
          /* Just reference the variable
                to cause it to become set for this buffer.  */
@@ -1610,7 +1630,7 @@ selected window if it is displayed there.")
       XSETBUFFER (buffer, current_buffer);
 
       /* If we're burying the current buffer, unshow it.  */
-      Fswitch_to_buffer (Fother_buffer (buffer, Qnil), Qnil);
+      Fswitch_to_buffer (Fother_buffer (buffer, Qnil, Qnil), Qnil);
     }
   else
     {
@@ -1679,12 +1699,22 @@ static int
 advance_to_char_boundary (byte_pos)
      int byte_pos;
 {
-  int c = FETCH_BYTE (byte_pos);
+  int c;
 
-  while (! CHAR_HEAD_P (c))
+  if (byte_pos == BEG)
+    /* Beginning of buffer is always a character boundary.  */
+    return 1;
+
+  c = FETCH_BYTE (byte_pos);
+  if (! CHAR_HEAD_P (c))
     {
-      byte_pos++;
-      c = FETCH_BYTE (byte_pos);
+      /* We should advance BYTE_POS only when C is a constituen of a
+         multibyte sequence.  */
+      DEC_POS (byte_pos);
+      INC_POS (byte_pos);
+      /* If C is a constituent of a multibyte sequence, BYTE_POS was
+         surely advance to the correct character boundary.  If C is
+         not, BYTE_POS was unchanged.  */
     }
 
   return byte_pos;
@@ -1702,6 +1732,10 @@ but the contents viewed as characters do change.")
 {
   Lisp_Object tail, markers;
 
+  /* Do nothing if nothing actually changes.  */
+  if (NILP (flag) == NILP (current_buffer->enable_multibyte_characters))
+    return flag;
+
   /* It would be better to update the list,
      but this is good enough for now.  */
   if (! EQ (current_buffer->undo_list, Qt))
@@ -1733,6 +1767,24 @@ but the contents viewed as characters do change.")
     }
   else
     {
+      /* Be sure not to have a multibyte sequence striding over the GAP.
+        Ex: We change this: "...abc\201\241\241 _GAP_ \241\241\241..."
+            to: "...abc _GAP_ \201\241\241\241\241\241..."  */
+
+      if (GPT_BYTE > 1 && GPT_BYTE < Z_BYTE
+         && ! CHAR_HEAD_P (*(GAP_END_ADDR)))
+       {
+         unsigned char *p = GPT_ADDR - 1;
+
+         while (! CHAR_HEAD_P (*p) && p > BEG_ADDR) p--;
+         if (BASE_LEADING_CODE_P (*p))
+           {
+             int new_gpt = GPT_BYTE - (GPT_ADDR - p);
+
+             move_gap_both (new_gpt, new_gpt);
+           }
+       }
+
       /* Do this first, so that chars_in_text asks the right question.
         set_intervals_multibyte needs it too.  */
       current_buffer->enable_multibyte_characters = Qt;
@@ -1740,17 +1792,17 @@ but the contents viewed as characters do change.")
       GPT_BYTE = advance_to_char_boundary (GPT_BYTE);
       GPT = chars_in_text (BEG_ADDR, GPT_BYTE - BEG_BYTE) + BEG;
 
-      Z = chars_in_text (GPT_ADDR, Z_BYTE - GPT_BYTE) + GPT;
+      Z = chars_in_text (GAP_END_ADDR, Z_BYTE - GPT_BYTE) + GPT;
 
       BEGV_BYTE = advance_to_char_boundary (BEGV_BYTE);
       if (BEGV_BYTE > GPT_BYTE)
-       BEGV = chars_in_text (GPT_ADDR, BEGV_BYTE - GPT_BYTE) + GPT;
+       BEGV = chars_in_text (GAP_END_ADDR, BEGV_BYTE - GPT_BYTE) + GPT;
       else
        BEGV = chars_in_text (BEG_ADDR, BEGV_BYTE - BEG_BYTE) + BEG;
 
       ZV_BYTE = advance_to_char_boundary (ZV_BYTE);
       if (ZV_BYTE > GPT_BYTE)
-       ZV = chars_in_text (GPT_ADDR, ZV_BYTE - GPT_BYTE) + GPT;
+       ZV = chars_in_text (GAP_END_ADDR, ZV_BYTE - GPT_BYTE) + GPT;
       else
        ZV = chars_in_text (BEG_ADDR, ZV_BYTE - BEG_BYTE) + BEG;
 
@@ -1759,13 +1811,17 @@ but the contents viewed as characters do change.")
        int pt;
 
        if (pt_byte > GPT_BYTE)
-         pt = chars_in_text (GPT_ADDR, pt_byte - GPT_BYTE) + GPT;
+         pt = chars_in_text (GAP_END_ADDR, pt_byte - GPT_BYTE) + GPT;
        else
          pt = chars_in_text (BEG_ADDR, pt_byte - BEG_BYTE) + BEG;
        TEMP_SET_PT_BOTH (pt, pt_byte);
       }
 
       tail = markers = BUF_MARKERS (current_buffer);
+
+      /* This prevents BYTE_TO_CHAR (that is, buf_bytepos_to_charpos) from
+        getting confused by the markers that have not yet been updated.
+        It is also a signal that it should never create a marker.  */
       BUF_MARKERS (current_buffer) = Qnil;
 
       while (XSYMBOL (tail) != XSYMBOL (Qnil))
@@ -1776,6 +1832,12 @@ but the contents viewed as characters do change.")
 
          tail = XMARKER (tail)->chain;
        }
+
+      /* Make sure no markers were put on the chain
+        while the chain value was incorrect.  */
+      if (! EQ (BUF_MARKERS (current_buffer), Qnil))
+       abort ();
+
       BUF_MARKERS (current_buffer) = markers;
 
       /* Do this last, so it can calculate the new correspondences
@@ -1862,26 +1924,26 @@ swap_out_buffer_local_variables (b)
       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;
+      tem = XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->buffer;
       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;
+         tem = XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->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);
+           = do_symval_forwarding (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->realvalue);
          /* 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;
+         XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->buffer = buffer;
          /* Store the current value into any forwarding in the symbol.  */
-         store_symval_forwarding (sym, XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->car,
+         store_symval_forwarding (sym,
+                                  XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->realvalue,
                                   XCONS (tem)->cdr);
        }
     }
@@ -2194,9 +2256,11 @@ struct sortvec
 };
 
 static int
-compare_overlays (s1, s2)
-     struct sortvec *s1, *s2;
+compare_overlays (v1, v2)
+     const void *v1, *v2;
 {
+  const struct sortvec *s1 = (const struct sortvec *) v1;
+  const struct sortvec *s2 = (const struct sortvec *) v2;
   if (s1->priority != s2->priority)
     return s1->priority - s2->priority;
   if (s1->beg != s2->beg)
@@ -2332,9 +2396,9 @@ record_overlay_string (ssl, str, str2, pri, size)
     nbytes = XSTRING (str)->size;
   else if (! STRING_MULTIBYTE (str))
     nbytes = count_size_as_multibyte (XSTRING (str)->data,
-                                     XSTRING (str)->size_byte);
+                                     STRING_BYTES (XSTRING (str)));
   else
-    nbytes = XSTRING (str)->size_byte;
+    nbytes = STRING_BYTES (XSTRING (str));
 
   ssl->bytes += nbytes;
 
@@ -2344,9 +2408,9 @@ record_overlay_string (ssl, str, str2, pri, size)
        nbytes = XSTRING (str2)->size;
       else if (! STRING_MULTIBYTE (str2))
        nbytes = count_size_as_multibyte (XSTRING (str2)->data,
-                                         XSTRING (str2)->size_byte);
+                                         STRING_BYTES (XSTRING (str2)));
       else
-       nbytes = XSTRING (str2)->size_byte;
+       nbytes = STRING_BYTES (XSTRING (str2));
 
       ssl->bytes += nbytes;
     }
@@ -2458,7 +2522,8 @@ overlay_strings (pos, w, pstr)
        {
          int nbytes;
          tem = overlay_tails.buf[i].string;
-         nbytes = copy_text (XSTRING (tem)->data, p, XSTRING (tem)->size_byte,
+         nbytes = copy_text (XSTRING (tem)->data, p,
+                             STRING_BYTES (XSTRING (tem)),
                              STRING_MULTIBYTE (tem), multibyte);
          p += nbytes;
        }
@@ -2466,14 +2531,15 @@ overlay_strings (pos, w, pstr)
        {
          int nbytes;
          tem = overlay_heads.buf[i].string;
-         nbytes = copy_text (XSTRING (tem)->data, p, XSTRING (tem)->size_byte,
+         nbytes = copy_text (XSTRING (tem)->data, p,
+                             STRING_BYTES (XSTRING (tem)),
                              STRING_MULTIBYTE (tem), multibyte);
          p += nbytes;
          tem = overlay_heads.buf[i].string2;
          if (STRINGP (tem))
            {
              nbytes = copy_text (XSTRING (tem)->data, p,
-                                 XSTRING (tem)->size_byte,
+                                 STRING_BYTES (XSTRING (tem)),
                                  STRING_MULTIBYTE (tem), multibyte);
              p += nbytes;
            }
@@ -3118,8 +3184,8 @@ DEFUN ("delete-overlay", Fdelete_overlay, Sdelete_overlay, 1, 1, 0,
   b->overlays_after  = Fdelq (overlay, b->overlays_after);
 
   modify_overlay (b,
-                   marker_position (OVERLAY_START (overlay)),
-                   marker_position (OVERLAY_END   (overlay)));
+                 marker_position (OVERLAY_START (overlay)),
+                 marker_position (OVERLAY_END   (overlay)));
 
   Fset_marker (OVERLAY_START (overlay), Qnil, Qnil);
   Fset_marker (OVERLAY_END   (overlay), Qnil, Qnil);
@@ -3712,7 +3778,8 @@ evaporate_overlays (pos)
 }
 \f
 /* Somebody has tried to store a value with an unacceptable type
-   into the buffer-local slot with offset OFFSET.  */
+   in the slot with offset OFFSET.  */
+
 void
 buffer_slot_type_mismatch (offset)
      int offset;
@@ -3725,14 +3792,16 @@ buffer_slot_type_mismatch (offset)
     case Lisp_Int:     type_name = "integers";  break;
     case Lisp_String:  type_name = "strings";   break;
     case Lisp_Symbol:  type_name = "symbols";   break;
+
     default:
       abort ();
     }
 
-  error ("only %s should be stored in the buffer-local variable %s",
+  error ("Only %s should be stored in the buffer-local variable %s",
         type_name, XSYMBOL (sym)->name->data);
 }
 \f
+void
 init_buffer_once ()
 {
   register Lisp_Object tem;
@@ -3792,6 +3861,7 @@ init_buffer_once ()
   buffer_defaults.cache_long_line_scans = Qnil;
   buffer_defaults.file_truename = Qnil;
   XSETFASTINT (buffer_defaults.display_count, 0);
+  buffer_defaults.display_time = Qnil;
 
   /* Assign the local-flags to the slots that have default values.
      The local flag is a bit that is used in the buffer
@@ -3818,6 +3888,8 @@ init_buffer_once ()
   XSETINT (buffer_local_flags.invisibility_spec, -1);
   XSETINT (buffer_local_flags.file_format, -1);
   XSETINT (buffer_local_flags.display_count, -1);
+  XSETINT (buffer_local_flags.display_time, -1);
+  XSETINT (buffer_local_flags.enable_multibyte_characters, -1);
 
   XSETFASTINT (buffer_local_flags.mode_line_format, 1);
   XSETFASTINT (buffer_local_flags.abbrev_mode, 2);
@@ -3844,12 +3916,9 @@ init_buffer_once ()
   XSETFASTINT (buffer_local_flags.cache_long_line_scans, 0x10000);
   XSETFASTINT (buffer_local_flags.category_table, 0x20000);
   XSETFASTINT (buffer_local_flags.direction_reversed, 0x40000);
-  XSETFASTINT (buffer_local_flags.enable_multibyte_characters, 0x80000);
+  XSETFASTINT (buffer_local_flags.buffer_file_coding_system, 0x80000);
   /* Make this one a permanent local.  */
   buffer_permanent_local_flags |= 0x80000;
-  XSETFASTINT (buffer_local_flags.buffer_file_coding_system, 0x100000);
-  /* Make this one a permanent local.  */
-  buffer_permanent_local_flags |= 0x100000;
   
   Vbuffer_alist = Qnil;
   current_buffer = 0;
@@ -3876,6 +3945,7 @@ init_buffer_once ()
   Fset_buffer (Fget_buffer_create (build_string ("*scratch*")));
 }
 
+void
 init_buffer ()
 {
   char buf[MAXPATHLEN+1];
@@ -3885,10 +3955,13 @@ init_buffer ()
   int rc;
 
   Fset_buffer (Fget_buffer_create (build_string ("*scratch*")));
+  if (NILP (buffer_defaults.enable_multibyte_characters))
+    Fset_buffer_multibyte (Qnil);
 
   /* If PWD is accurate, use it instead of calling getwd.  This is faster
      when PWD is right, and may avoid a fatal error.  */
-  if ((pwd = getenv ("PWD")) != 0 && IS_DIRECTORY_SEP (*pwd)
+  if ((pwd = getenv ("PWD")) != 0
+      && (IS_DIRECTORY_SEP (*pwd) || (*pwd && IS_DEVICE_SEP (pwd[1])))
       && stat (pwd, &pwdstat) == 0
       && stat (".", &dotstat) == 0
       && dotstat.st_ino == pwdstat.st_ino
@@ -3933,6 +4006,7 @@ init_buffer ()
 }
 
 /* initialize the buffer routines */
+void
 syms_of_buffer ()
 {
   extern Lisp_Object Qdisabled;
@@ -4136,7 +4210,8 @@ This variable does not apply to characters whose display is specified\n\
 in the current display table (if there is one).");
 
   DEFVAR_PER_BUFFER ("enable-multibyte-characters",
-                    &current_buffer->enable_multibyte_characters, Qnil,
+                    &current_buffer->enable_multibyte_characters,
+                    make_number (-1),
     "*Non-nil means the buffer contents are regarded as multi-byte form\n\
 of characters, not a binary code.  This affects the display, file I/O,\n\
 and behaviors of various editing commands.");
@@ -4145,7 +4220,7 @@ and behaviors of various editing commands.");
                     &current_buffer->buffer_file_coding_system, Qnil,
     "Coding system to be used for encoding the buffer contents on saving.\n\
 If it is nil, the buffer is saved without any code conversion unless\n\
-some coding system is specified in file-coding-system-alist\n\
+some coding system is specified in `file-coding-system-alist'\n\
 for the buffer file.\n\
 \n\
 This variable is never applied to a way of decoding\n\
@@ -4354,6 +4429,7 @@ The functions are run using the `run-hooks' function.");
         but make-docfile can find it in this comment.  */
   DEFVAR_PER_BUFFER ("buffer-undo-list", &current_buffer->undo_list, Qnil,
     "List of undo entries in current buffer.\n\
+This variable is always local in all buffers.\n\
 Recent changes come first; older changes follow newer.\n\
 \n\
 An entry (BEG . END) represents an insertion which begins at\n\
@@ -4422,16 +4498,19 @@ the cache should not affect the behavior of any of the motion\n\
 functions; it should only affect their performance.");
 
   DEFVAR_PER_BUFFER ("point-before-scroll", &current_buffer->point_before_scroll, Qnil,
-  "Value of point before the last series of scroll operations, or nil.");
+  "Value of point before the last series of scroll operations, or nil.\n\
+This variable is always local in all buffers.");
 
   DEFVAR_PER_BUFFER ("buffer-file-format", &current_buffer->file_format, Qnil,
     "List of formats to use when saving this buffer.\n\
+This variable is always local in all buffers.\n\
 Formats are defined by `format-alist'.  This variable is\n\
 set when a file is visited.  Automatically local in all buffers.");
 
   DEFVAR_PER_BUFFER ("buffer-invisibility-spec",
                     &current_buffer->invisibility_spec, Qnil,
   "Invisibility spec of this buffer.\n\
+This variable is always local in all buffers.\n\
 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\
@@ -4442,7 +4521,17 @@ and they have an ellipsis as well if ELLIPSIS is non-nil.");
 
   DEFVAR_PER_BUFFER ("buffer-display-count",
                     &current_buffer->display_count, Qnil,
-  "A number incremented each time the buffer is displayed in a window.");
+  "A number incremented each time this buffer is displayed in a window.\n\
+This variable is always local in all buffers.\n\
+The function `set-window-buffer increments it.");
+
+  DEFVAR_PER_BUFFER ("buffer-display-time",
+                    &current_buffer->display_time, Qnil,
+  "Time stamp updated each time this buffer is displayed in a window.\n\
+This variable is always local in all buffers.\n\
+The function `set-window-buffer' updates this variable\n\
+to the value obtained by calling `current-time'.\n\
+If the buffer has never been shown in a window, the value is nil.");
 
   DEFVAR_LISP ("transient-mark-mode", &Vtransient_mark_mode,
     "*Non-nil means deactivate the mark when the buffer contents change.\n\
@@ -4512,6 +4601,7 @@ is a member of the list.");
   defsubr (&Soverlay_put);
 }
 
+void
 keys_of_buffer ()
 {
   initial_define_key (control_x_map, 'b', "switch-to-buffer");