]> code.delx.au - gnu-emacs/blobdiff - src/editfns.c
*** empty log message ***
[gnu-emacs] / src / editfns.c
index 1abd2696ba6b146a0907783079f399c44041912a..d4f8b5fd8c46c21b8c02763eebfb266e251f3836 100644 (file)
@@ -49,6 +49,7 @@ Boston, MA 02111-1307, USA.  */
 #endif
 
 extern char **environ;
+extern int use_dialog_box;
 extern Lisp_Object make_time ();
 extern void insert_from_buffer ();
 static int tm_diff ();
@@ -62,6 +63,10 @@ Lisp_Object Vbuffer_access_fontified_property;
 
 Lisp_Object Fuser_full_name ();
 
+/* Non-nil means don't stop at field boundary in text motion commands.  */
+
+Lisp_Object Vinhibit_field_text_motion;
+
 /* Some static data, and a function to initialize it for each run */
 
 Lisp_Object Vsystem_name;
@@ -131,11 +136,11 @@ DEFUN ("char-to-string", Fchar_to_string, Schar_to_string, 1, 1, 0,
      Lisp_Object character;
 {
   int len;
-  unsigned char workbuf[4], *str;
+  unsigned char str[MAX_MULTIBYTE_LENGTH];
 
   CHECK_NUMBER (character, 0);
 
-  len = CHAR_STRING (XFASTINT (character), workbuf, str);
+  len = CHAR_STRING (XFASTINT (character), str);
   return make_string_from_bytes (str, 1, len);
 }
 
@@ -272,23 +277,9 @@ If you set the marker not to point anywhere, the buffer will have no mark.")
   return current_buffer->mark;
 }
 \f
-/* Returns the position before POS in the current buffer.  POS must not
-   be at the beginning of the buffer.  */
-static Lisp_Object
-preceding_pos (int pos)
-{
-  int pos_byte = CHAR_TO_BYTE (pos);
-         
-  /* Decrement POS_BYTE (is all this cruft really necessary?).  */
-  if (NILP (current_buffer->enable_multibyte_characters))
-    pos_byte--;
-  else
-    DEC_POS (pos_byte);
+/* Return nonzero if POS1 and POS2 have the same value
+   for the text property PROP.  */
 
-  return make_number (BYTE_TO_CHAR (pos_byte));
-}
-
-/* Returns true if POS1 and POS2 have the same value for text property PROP. */
 static int
 text_property_eq (prop, pos1, pos2)
      Lisp_Object prop;
@@ -302,9 +293,11 @@ text_property_eq (prop, pos1, pos2)
   return EQ (pval1, pval2);
 }
 
-/* Returns the direction that the text-property PROP would be inherited
-   by any new text inserted at POS: 1 if it would be inherited from POS,
-   -1 if it would be inherited from POS-1, and 0 if from neither.  */
+/* Return the direction from which the text-property PROP would be
+   inherited by any new text inserted at POS: 1 if it would be
+   inherited from the char after POS, -1 if it would be inherited from
+   the char before POS, and 0 if from neither.  */
+
 static int
 text_property_stickiness (prop, pos)
      Lisp_Object prop;
@@ -312,58 +305,60 @@ text_property_stickiness (prop, pos)
 {
   Lisp_Object front_sticky;
 
-  if (PT > BEGV)
-    /* Consider previous position.  */
+  if (XINT (pos) > BEGV)
+    /* Consider previous character.  */
     {
       Lisp_Object prev_pos, rear_non_sticky;
 
-      prev_pos = preceding_pos (pos);
+      prev_pos = make_number (XINT (pos) - 1);
       rear_non_sticky = Fget_text_property (prev_pos, Qrear_nonsticky, Qnil);
 
       if (EQ (rear_non_sticky, Qnil)
          || (CONSP (rear_non_sticky)
-             && !Fmemq (prop, rear_non_sticky)))
+             && NILP (Fmemq (prop, rear_non_sticky))))
        /* PROP is not rear-non-sticky, and since this takes precedence over
-          any front-stickiness, that must be the answer.  */
+          any front-stickiness, PROP is inherited from before.  */
        return -1;
     }
 
-  /* Consider current position.  */
+  /* Consider following character.  */
   front_sticky = Fget_text_property (pos, Qfront_sticky, Qnil);
 
   if (EQ (front_sticky, Qt)
       || (CONSP (front_sticky)
-         && Fmemq (prop, front_sticky)))
-    /* PROP is front-sticky.  */
+         && !NILP (Fmemq (prop, front_sticky))))
+    /* PROP is inherited from after.  */
     return 1;
 
-  /* PROP is not sticky at all.  */
+  /* PROP is not inherited from either side.  */
   return 0;
 }
 \f
-/* Name for the text property we use to distinguish fields. */
+/* Symbol for the text property used to mark fields.  */
 Lisp_Object Qfield;
 
-/* Returns the field surrounding POS in *BEG and *END; an
-   `field' is a region of text with the same `field' property.
-   If POS is nil, the position of the current buffer's point is used.
-   If MERGE_AT_BOUNDARY is true, then if POS is at the very first
+/* Find the field surrounding POS in *BEG and *END.  If POS is nil,
+   the value of point is used instead.
+
+   If MERGE_AT_BOUNDARY is nonzero, then if POS is at the very first
    position of a field, then the beginning of the previous field
    is returned instead of the beginning of POS's field (since the end of
    a field is actually also the beginning of the next input
-   field, this behavior is sometimes useful).  BEG or END may be 0, in
-   which case the corresponding value is not returned.  */
+   field, this behavior is sometimes useful).
+
+   Either BEG or END may be 0, in which case the corresponding value
+   is not stored.  */
+
 void
 find_field (pos, merge_at_boundary, beg, end)
      Lisp_Object pos;
      Lisp_Object merge_at_boundary;
      int *beg, *end;
 {
-  /* If POS is at the edge of a field, then -1 or 1 depending on
-     whether it should be considered as the beginning of the following
-     field, or the end of the previous field, respectively.  If POS is
-     not at a field-boundary, then STICKINESS is 0.  */
-  int stickiness = 0;
+  /* 1 if POS counts as the start of a field.  */
+  int at_field_start = 0;
+  /* 1 if POS counts as the end of a field.  */
+  int at_field_end = 0;
   
   if (NILP (pos))
     XSETFASTINT (pos, PT);
@@ -382,30 +377,35 @@ find_field (pos, merge_at_boundary, beg, end)
       Lisp_Object after_field, before_field;
 
       after_field = Fget_text_property (pos, Qfield, Qnil);
-      before_field = Fget_text_property (preceding_pos (pos), Qfield, Qnil);
+      before_field = Fget_text_property (make_number (XINT (pos) - 1),
+                                        Qfield, Qnil);
 
       if (! EQ (after_field, before_field))
        /* We are at a boundary, see which direction is inclusive.  */
        {
-         stickiness = text_property_stickiness (Qfield, pos);
+         int stickiness = text_property_stickiness (Qfield, pos);
 
-         if (stickiness == 0)
+         if (stickiness > 0)
+           at_field_start = 1;
+         else if (stickiness < 0)
+           at_field_end = 1;
+         else
            /* STICKINESS == 0 means that any inserted text will get a
               `field' text-property of nil, so check to see if that
               matches either of the adjacent characters (this being a
-              kind of `stickiness by default').  */
+              kind of "stickiness by default").  */
            {
              if (NILP (before_field))
-               stickiness = -1; /* Sticks to the left.  */
+               at_field_end = 1; /* Sticks to the left.  */
              else if (NILP (after_field))
-               stickiness = 1; /* Sticks to the right.  */
+               at_field_start = 1; /* Sticks to the right.  */
            }
        }
     }
 
   if (beg)
     {
-      if (stickiness > 0)
+      if (at_field_start)
        /* POS is at the edge of a field, and we should consider it as
           the beginning of the following field.  */
        *beg = XFASTINT (pos);
@@ -414,13 +414,13 @@ find_field (pos, merge_at_boundary, beg, end)
        {
          Lisp_Object prev;
          prev = Fprevious_single_property_change (pos, Qfield, Qnil, Qnil);
-         *beg = NILP(prev) ? BEGV : XFASTINT (prev);
+         *beg = NILP (prev) ? BEGV : XFASTINT (prev);
        }
     }
 
   if (end)
     {
-      if (stickiness < 0)
+      if (at_field_end)
        /* POS is at the edge of a field, and we should consider it as
           the end of the previous field.  */
        *end = XFASTINT (pos);
@@ -429,15 +429,15 @@ find_field (pos, merge_at_boundary, beg, end)
        {
          Lisp_Object next;
          next = Fnext_single_property_change (pos, Qfield, Qnil, Qnil);
-         *end = NILP(next) ? ZV : XFASTINT (next);
+         *end = NILP (next) ? ZV : XFASTINT (next);
        }
     }
 }
 \f
-DEFUN ("delete-field", Fdelete_field, Sdelete_field, 0, 1, "d",
+DEFUN ("delete-field", Fdelete_field, Sdelete_field, 0, 1, 0,
   "Delete the field surrounding POS.\n\
 A field is a region of text with the same `field' property.\n\
-If POS is nil, the position of the current buffer's point is used.")
+If POS is nil, the value of point is used for POS.")
   (pos)
      Lisp_Object pos;
 {
@@ -445,12 +445,13 @@ If POS is nil, the position of the current buffer's point is used.")
   find_field (pos, Qnil, &beg, &end);
   if (beg != end)
     del_range (beg, end);
+  return Qnil;
 }
 
 DEFUN ("field-string", Ffield_string, Sfield_string, 0, 1, 0,
   "Return the contents of the field surrounding POS as a string.\n\
 A field is a region of text with the same `field' property.\n\
-If POS is nil, the position of the current buffer's point is used.")
+If POS is nil, the value of point is used for POS.")
   (pos)
      Lisp_Object pos;
 {
@@ -462,7 +463,7 @@ If POS is nil, the position of the current buffer's point is used.")
 DEFUN ("field-string-no-properties", Ffield_string_no_properties, Sfield_string_no_properties, 0, 1, 0,
   "Return the contents of the field around POS, without text-properties.\n\
 A field is a region of text with the same `field' property.\n\
-If POS is nil, the position of the current buffer's point is used.")
+If POS is nil, the value of point is used for POS.")
   (pos)
      Lisp_Object pos;
 {
@@ -474,8 +475,8 @@ If POS is nil, the position of the current buffer's point is used.")
 DEFUN ("field-beginning", Ffield_beginning, Sfield_beginning, 0, 2, 0,
   "Return the beginning of the field surrounding POS.\n\
 A field is a region of text with the same `field' property.\n\
-If POS is nil, the position of the current buffer's point is used.\n\
-If ESCAPE-FROM-EDGE is non-nil and POS is already at beginning of an\n\
+If POS is nil, the value of point is used for POS.\n\
+If ESCAPE-FROM-EDGE is non-nil and POS is at the beginning of its\n\
 field, then the beginning of the *previous* field is returned.")
   (pos, escape_from_edge)
      Lisp_Object pos, escape_from_edge;
@@ -488,8 +489,8 @@ field, then the beginning of the *previous* field is returned.")
 DEFUN ("field-end", Ffield_end, Sfield_end, 0, 2, 0,
   "Return the end of the field surrounding POS.\n\
 A field is a region of text with the same `field' property.\n\
-If POS is nil, the position of the current buffer's point is used.\n\
-If ESCAPE-FROM-EDGE is non-nil and POS is already at end of a field,\n\
+If POS is nil, the value of point is used for POS.\n\
+If ESCAPE-FROM-EDGE is non-nil and POS is at the end of its field,\n\
 then the end of the *following* field is returned.")
   (pos, escape_from_edge)
      Lisp_Object pos, escape_from_edge;
@@ -517,7 +518,9 @@ If the optional argument ONLY-IN-LINE is non-nil and constraining\n\
 NEW-POS would move it to a different line, NEW-POS is returned\n\
 unconstrained.  This useful for commands that move by line, like\n\
 \\[next-line] or \\[beginning-of-line], which should generally respect field boundaries\n\
-only in the case where they can still move to the right line.")
+only in the case where they can still move to the right line.\n\
+\n\
+Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.")
   (new_pos, old_pos, escape_from_edge, only_in_line)
      Lisp_Object new_pos, old_pos, escape_from_edge, only_in_line;
 {
@@ -531,7 +534,9 @@ only in the case where they can still move to the right line.")
       XSETFASTINT (new_pos, PT);
     }
 
-  if (!EQ (new_pos, old_pos) && !text_property_eq (Qfield, new_pos, old_pos))
+  if (NILP (Vinhibit_field_text_motion)
+      && !EQ (new_pos, old_pos)
+      && !text_property_eq (Qfield, new_pos, old_pos))
     /* NEW_POS is not within the same field as OLD_POS; try to
        move NEW_POS so that it is.  */
     {
@@ -578,10 +583,12 @@ DEFUN ("line-beginning-position", Fline_beginning_position, Sline_beginning_posi
   "Return the character position of the first character on the current line.\n\
 With argument N not nil or 1, move forward N - 1 lines first.\n\
 If scan reaches end of buffer, return that position.\n\
-This function does not move point.\n\n\
-In the minibuffer, if point is not within the prompt,\n\
-the return value is never within the prompt either.")
-
+The scan does not cross a field boundary unless it would move\n\
+beyond there to a different line.  Field boundaries are not noticed if\n\
+`inhibit-field-text-motion' is non-nil. .And if N is nil or 1,\n\
+and scan starts at a field boundary, the scan stops as soon as it starts.\n\
+\n\
+This function does not move point.")
   (n)
      Lisp_Object n;
 {
@@ -600,7 +607,9 @@ the return value is never within the prompt either.")
   SET_PT_BOTH (orig, orig_byte);
 
   /* Return END constrained to the current input field.  */
-  return Fconstrain_to_field (make_number (end), make_number (orig), Qnil, Qt);
+  return Fconstrain_to_field (make_number (end), make_number (orig),
+                             XINT (n) != 1 ? Qt : Qnil,
+                             Qt);
 }
 
 DEFUN ("line-end-position", Fline_end_position, Sline_end_position,
@@ -623,8 +632,8 @@ This function does not move point.")
   end_pos = find_before_next_newline (orig, 0, XINT (n) - (XINT (n) <= 0));
 
   /* Return END_POS constrained to the current input field.  */
-  return
-    Fconstrain_to_field (make_number (end_pos), make_number (orig), Qnil, Qt);
+  return Fconstrain_to_field (make_number (end_pos), make_number (orig),
+                             Qnil, Qt);
 }
 \f
 Lisp_Object
@@ -834,10 +843,7 @@ If BYTEPOS is out of range, the value is nil.")
 \f
 DEFUN ("following-char", Ffollowing_char, Sfollowing_char, 0, 0, 0,
   "Return the character following point, as a number.\n\
-At the end of the buffer or accessible region, return 0.\n\
-If `enable-multibyte-characters' is nil or point is not\n\
- at character boundary,  multibyte form is ignored,\n\
- and only one byte following point is returned as a character.")
+At the end of the buffer or accessible region, return 0.")
   ()
 {
   Lisp_Object temp;
@@ -850,10 +856,7 @@ If `enable-multibyte-characters' is nil or point is not\n\
 
 DEFUN ("preceding-char", Fprevious_char, Sprevious_char, 0, 0, 0,
   "Return the character preceding point, as a number.\n\
-At the beginning of the buffer or accessible region, return 0.\n\
-If `enable-multibyte-characters' is nil or point is not\n\
- at character boundary, multi-byte form is ignored,\n\
- and only one byte preceding point is returned as a character.")
+At the beginning of the buffer or accessible region, return 0.")
   ()
 {
   Lisp_Object temp;
@@ -911,7 +914,7 @@ DEFUN ("eolp", Feolp, Seolp, 0, 0, 0,
 
 DEFUN ("char-after", Fchar_after, Schar_after, 0, 1, 0,
   "Return character in current buffer at position POS.\n\
-POS is an integer or a buffer pointer.\n\
+POS is an integer or a marker.\n\
 If POS is out of range, the value is nil.")
   (pos)
      Lisp_Object pos;
@@ -944,7 +947,7 @@ If POS is out of range, the value is nil.")
 
 DEFUN ("char-before", Fchar_before, Schar_before, 0, 1, 0,
   "Return character in current buffer preceding position POS.\n\
-POS is an integer or a buffer pointer.\n\
+POS is an integer or a marker.\n\
 If POS is out of range, the value is nil.")
   (pos)
      Lisp_Object pos;
@@ -1298,7 +1301,7 @@ DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
   if (! tm)
     error ("Specified time is not representable");
 
-  synchronize_time_locale ();
+  synchronize_system_time_locale ();
 
   while (1)
     {
@@ -1713,17 +1716,16 @@ general_insert_function (insert_func, insert_from_string_func,
     retry:
       if (INTEGERP (val))
        {
-         unsigned char workbuf[4], *str;
+         unsigned char str[MAX_MULTIBYTE_LENGTH];
          int len;
 
          if (!NILP (current_buffer->enable_multibyte_characters))
-           len = CHAR_STRING (XFASTINT (val), workbuf, str);
+           len = CHAR_STRING (XFASTINT (val), str);
          else
            {
-             workbuf[0] = (SINGLE_BYTE_CHAR_P (XINT (val))
-                           ? XINT (val)
-                           : multibyte_char_to_unibyte (XINT (val), Qnil));
-             str = workbuf;
+             str[0] = (SINGLE_BYTE_CHAR_P (XINT (val))
+                       ? XINT (val)
+                       : multibyte_char_to_unibyte (XINT (val), Qnil));
              len = 1;
            }
          (*insert_func) (str, len);
@@ -1844,15 +1846,15 @@ from adjoining text, if those properties are sticky.")
   register int strlen;
   register int i, n;
   int len;
-  unsigned char workbuf[4], *str;
+  unsigned char str[MAX_MULTIBYTE_LENGTH];
 
   CHECK_NUMBER (character, 0);
   CHECK_NUMBER (count, 1);
 
   if (!NILP (current_buffer->enable_multibyte_characters))
-    len = CHAR_STRING (XFASTINT (character), workbuf, str);
+    len = CHAR_STRING (XFASTINT (character), str);
   else
-    workbuf[0] = XFASTINT (character), str = workbuf, len = 1;
+    str[0] = XFASTINT (character), len = 1;
   n = XINT (count) * len;
   if (n <= 0)
     return Qnil;
@@ -1939,7 +1941,6 @@ make_buffer_string_both (start, start_byte, end, end_byte, props)
         end_byte - start_byte);
 
   /* If desired, update and copy the text properties.  */
-#ifdef USE_TEXT_PROPERTIES
   if (props)
     {
       update_buffer_properties (start, end);
@@ -1951,7 +1952,6 @@ make_buffer_string_both (start, start_byte, end, end_byte, props)
        copy_intervals_to_string (result, current_buffer, start,
                                  end - start);
     }
-#endif
 
   return result;
 }
@@ -1963,7 +1963,6 @@ static void
 update_buffer_properties (start, end)
      int start, end;
 {
-#ifdef USE_TEXT_PROPERTIES
   /* If this buffer has some access functions,
      call them, specifying the range of the buffer being accessed.  */
   if (!NILP (Vbuffer_access_fontify_functions))
@@ -1988,7 +1987,6 @@ update_buffer_properties (start, end)
       else
        Frun_hook_with_args (3, args);
     }
-#endif
 }
 
 DEFUN ("buffer-substring", Fbuffer_substring, Sbuffer_substring, 2, 2, 0,
@@ -2267,22 +2265,25 @@ Both characters must have the same length of multi-byte form.")
 {
   register int pos, pos_byte, stop, i, len, end_byte;
   int changed = 0;
-  unsigned char fromwork[4], *fromstr, towork[4], *tostr, *p;
+  unsigned char fromstr[MAX_MULTIBYTE_LENGTH], tostr[MAX_MULTIBYTE_LENGTH];
+  unsigned char *p;
   int count = specpdl_ptr - specpdl;
 #define COMBINING_NO    0
 #define COMBINING_BEFORE 1
 #define COMBINING_AFTER  2
 #define COMBINING_BOTH (COMBINING_BEFORE | COMBINING_AFTER)
   int maybe_byte_combining = COMBINING_NO;
+  int last_changed;
+  int multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
 
   validate_region (&start, &end);
   CHECK_NUMBER (fromchar, 2);
   CHECK_NUMBER (tochar, 3);
 
-  if (! NILP (current_buffer->enable_multibyte_characters))
+  if (multibyte_p)
     {
-      len = CHAR_STRING (XFASTINT (fromchar), fromwork, fromstr);
-      if (CHAR_STRING (XFASTINT (tochar), towork, tostr) != len)
+      len = CHAR_STRING (XFASTINT (fromchar), fromstr);
+      if (CHAR_STRING (XFASTINT (tochar), tostr) != len)
        error ("Characters in subst-char-in-region have different byte-lengths");
       if (!ASCII_BYTE_P (*tostr))
        {
@@ -2299,8 +2300,8 @@ Both characters must have the same length of multi-byte form.")
   else
     {
       len = 1;
-      fromwork[0] = XFASTINT (fromchar), fromstr = fromwork;
-      towork[0] = XFASTINT (tochar), tostr = towork;
+      fromstr[0] = XFASTINT (fromchar);
+      tostr[0] = XFASTINT (tochar);
     }
 
   pos = XINT (start);
@@ -2335,7 +2336,10 @@ Both characters must have the same length of multi-byte form.")
          stop = end_byte;
        }
       p = BYTE_POS_ADDR (pos_byte);
-      INC_POS (pos_byte_next);
+      if (multibyte_p)
+       INC_POS (pos_byte_next);
+      else
+       ++pos_byte_next;
       if (pos_byte_next - pos_byte == len
          && p[0] == fromstr[0]
          && (len == 1
@@ -2345,7 +2349,8 @@ Both characters must have the same length of multi-byte form.")
        {
          if (! changed)
            {
-             modify_region (current_buffer, XINT (start), XINT (end));
+             changed = pos;
+             modify_region (current_buffer, changed, XINT (end));
 
              if (! NILP (noundo))
                {
@@ -2354,8 +2359,6 @@ Both characters must have the same length of multi-byte form.")
                  if (MODIFF - 1 == current_buffer->auto_save_modified)
                    current_buffer->auto_save_modified++;
                }
-
-             changed = 1;
            }
 
          /* Take care of the case where the new character
@@ -2402,14 +2405,18 @@ Both characters must have the same length of multi-byte form.")
                record_change (pos, 1);
              for (i = 0; i < len; i++) *p++ = tostr[i];
            }
+         last_changed =  pos + 1;
        }
       pos_byte = pos_byte_next;
       pos++;
     }
 
   if (changed)
-    signal_after_change (XINT (start),
-                        XINT (end) - XINT (start), XINT (end) - XINT (start));
+    {
+      signal_after_change (changed,
+                          last_changed - changed, last_changed - changed);
+      update_compositions (changed, last_changed, CHECK_ALL);
+    }
 
   unbind_to (count, Qnil);
   return Qnil;
@@ -2432,6 +2439,7 @@ It returns the number of characters changed.")
   int cnt;                     /* Number of changes made. */
   int size;                    /* Size of translate table. */
   int pos;
+  int multibyte = !NILP (current_buffer->enable_multibyte_characters);
 
   validate_region (&start, &end);
   CHECK_STRING (table, 2);
@@ -2452,7 +2460,10 @@ It returns the number of characters changed.")
       int oc;
       int pos_byte_next;
 
-      oc = STRING_CHAR_AND_LENGTH (p, stop - pos_byte, len);
+      if (multibyte)
+       oc = STRING_CHAR_AND_LENGTH (p, stop - pos_byte, len);
+      else
+       oc = *p, len = 1;
       pos_byte_next = pos_byte + len;
       if (oc < size && len == 1)
        {
@@ -2488,6 +2499,7 @@ It returns the number of characters changed.")
                  record_change (pos, 1);
                  *p = nc;
                  signal_after_change (pos, 1, 1);
+                 update_compositions (pos, pos + 1, CHECK_BORDER);
                }
              ++cnt;
            }
@@ -2510,6 +2522,16 @@ positions (integers or markers) specifying the stretch to be deleted.")
   del_range (XINT (start), XINT (end));
   return Qnil;
 }
+
+DEFUN ("delete-and-extract-region", Fdelete_and_extract_region,
+       Sdelete_and_extract_region, 2, 2, 0,
+  "Delete the text between START and END and return it.")
+  (start, end)
+     Lisp_Object start, end;
+{
+  validate_region (&start, &end);
+  return del_range_1 (XINT (start), XINT (end), 1, 1);
+}
 \f
 DEFUN ("widen", Fwiden, Swiden, 0, 0, "",
   "Remove restrictions (narrowing) from current buffer.\n\
@@ -2752,7 +2774,8 @@ minibuffer contents show.")
      Lisp_Object *args;
 {
 #ifdef HAVE_MENUS
-  if (NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
+  if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
+      && use_dialog_box)
     return Fmessage_box (nargs, args);
 #endif
   return Fmessage (nargs, args);
@@ -2769,7 +2792,7 @@ DEFUN ("current-message", Fcurrent_message, Scurrent_message, 0, 0, 0,
 DEFUN ("propertize", Fpropertize, Spropertize, 3, MANY, 0,
        "Return a copy of STRING with text properties added.\n\
 First argument is the string to copy.\n\
-Remaining arguments are sequences of PROPERTY VALUE pairs for text\n\
+Remaining arguments form a sequence of PROPERTY VALUE pairs for text\n\
 properties to add to the result ")
   (nargs, args)
      int nargs;
@@ -2920,7 +2943,10 @@ Use %% to put a single % into the output.")
          }
        else if (SYMBOLP (args[n]))
          {
-           XSETSTRING (args[n], XSYMBOL (args[n])->name);
+           /* Use a temp var to avoid problems when ENABLE_CHECKING
+              is turned on.  */
+           struct Lisp_String *t = XSYMBOL (args[n])->name;
+           XSETSTRING (args[n], t);
            if (STRING_MULTIBYTE (args[n]) && ! multibyte)
              {
                multibyte = 1;
@@ -2938,7 +2964,6 @@ Use %% to put a single % into the output.")
        /* Would get MPV otherwise, since Lisp_Int's `point' to low memory.  */
        else if (INTEGERP (args[n]) && *format != 's')
          {
-#ifdef LISP_FLOAT_TYPE
            /* The following loop assumes the Lisp type indicates
               the proper way to pass the argument.
               So make sure we have a flonum if the argument should
@@ -2946,7 +2971,6 @@ Use %% to put a single % into the output.")
            if (*format == 'e' || *format == 'f' || *format == 'g')
              args[n] = Ffloat (args[n]);
            else
-#endif
              if (*format != 'd' && *format != 'o' && *format != 'x'
                  && *format != 'i' && *format != 'X' && *format != 'c')
                error ("Invalid format operation %%%c", *format);
@@ -2965,14 +2989,12 @@ Use %% to put a single % into the output.")
                thissize = STRING_BYTES (XSTRING (args[n]));
              }
          }
-#ifdef LISP_FLOAT_TYPE
        else if (FLOATP (args[n]) && *format != 's')
          {
            if (! (*format == 'e' || *format == 'f' || *format == 'g'))
              args[n] = Ftruncate (args[n], Qnil);
            thissize = 200;
          }
-#endif
        else
          {
            /* Anything but a string, convert to a string using princ.  */
@@ -3341,10 +3363,8 @@ Transposing beyond buffer boundaries is an error.")
   int combined_before_bytes_2, combined_after_bytes_2;
   struct gcpro gcpro1, gcpro2;
 
-#ifdef USE_TEXT_PROPERTIES
   INTERVAL cur_intv, tmp_interval1, tmp_interval_mid, tmp_interval2;
   cur_intv = BUF_INTERVALS (current_buffer);
-#endif /* USE_TEXT_PROPERTIES */
 
   validate_region (&startr1, &endr1);
   validate_region (&startr2, &endr2);
@@ -3478,12 +3498,10 @@ Transposing beyond buffer boundaries is an error.")
       modify_region (current_buffer, start1, end2);
       record_change (start1, len1 + len2);
 
-#ifdef USE_TEXT_PROPERTIES
       tmp_interval1 = copy_intervals (cur_intv, start1, len1);
       tmp_interval2 = copy_intervals (cur_intv, start2, len2);
       Fset_text_properties (make_number (start1), make_number (end2),
                            Qnil, Qnil);
-#endif /* USE_TEXT_PROPERTIES */
 
       /* First region smaller than second.  */
       if (len1_byte < len2_byte)
@@ -3522,12 +3540,12 @@ Transposing beyond buffer boundaries is an error.")
          if (len1_byte > 20000)
            free (temp);
         }
-#ifdef USE_TEXT_PROPERTIES
       graft_intervals_into_buffer (tmp_interval1, start1 + len2,
                                    len1, current_buffer, 0);
       graft_intervals_into_buffer (tmp_interval2, start1,
                                    len2, current_buffer, 0);
-#endif /* USE_TEXT_PROPERTIES */
+      update_compositions (start1, start1 + len2, CHECK_BORDER);
+      update_compositions (start1 + len2, end2, CHECK_TAIL);
     }
   /* Non-adjacent regions, because end1 != start2, bleagh...  */
   else
@@ -3541,14 +3559,12 @@ Transposing beyond buffer boundaries is an error.")
           modify_region (current_buffer, start2, end2);
           record_change (start1, len1);
           record_change (start2, len2);
-#ifdef USE_TEXT_PROPERTIES
           tmp_interval1 = copy_intervals (cur_intv, start1, len1);
           tmp_interval2 = copy_intervals (cur_intv, start2, len2);
           Fset_text_properties (make_number (start1), make_number (end1),
                                Qnil, Qnil);
           Fset_text_properties (make_number (start2), make_number (end2),
                                Qnil, Qnil);
-#endif /* USE_TEXT_PROPERTIES */
 
          if (len1_byte > 20000)
            temp = (unsigned char *) xmalloc (len1_byte);
@@ -3561,12 +3577,10 @@ Transposing beyond buffer boundaries is an error.")
           bcopy (temp, start2_addr, len1_byte);
          if (len1_byte > 20000)
            free (temp);
-#ifdef USE_TEXT_PROPERTIES
           graft_intervals_into_buffer (tmp_interval1, start2,
                                        len1, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval2, start1,
                                        len2, current_buffer, 0);
-#endif /* USE_TEXT_PROPERTIES */
         }
 
       else if (len1_byte < len2_byte)  /* Second region larger than first */
@@ -3574,13 +3588,11 @@ Transposing beyond buffer boundaries is an error.")
         {
           modify_region (current_buffer, start1, end2);
           record_change (start1, (end2 - start1));
-#ifdef USE_TEXT_PROPERTIES
           tmp_interval1 = copy_intervals (cur_intv, start1, len1);
           tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
           tmp_interval2 = copy_intervals (cur_intv, start2, len2);
           Fset_text_properties (make_number (start1), make_number (end2),
                                Qnil, Qnil);
-#endif /* USE_TEXT_PROPERTIES */
 
          /* holds region 2 */
          if (len2_byte > 20000)
@@ -3595,14 +3607,12 @@ Transposing beyond buffer boundaries is an error.")
           bcopy (temp, start1_addr, len2_byte);
          if (len2_byte > 20000)
            free (temp);
-#ifdef USE_TEXT_PROPERTIES
           graft_intervals_into_buffer (tmp_interval1, end2 - len1,
                                        len1, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
                                        len_mid, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval2, start1,
                                        len2, current_buffer, 0);
-#endif /* USE_TEXT_PROPERTIES */
         }
       else
        /* Second region smaller than first.  */
@@ -3610,13 +3620,11 @@ Transposing beyond buffer boundaries is an error.")
           record_change (start1, (end2 - start1));
           modify_region (current_buffer, start1, end2);
 
-#ifdef USE_TEXT_PROPERTIES
           tmp_interval1 = copy_intervals (cur_intv, start1, len1);
           tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
           tmp_interval2 = copy_intervals (cur_intv, start2, len2);
           Fset_text_properties (make_number (start1), make_number (end2),
                                Qnil, Qnil);
-#endif /* USE_TEXT_PROPERTIES */
 
          /* holds region 1 */
          if (len1_byte > 20000)
@@ -3631,15 +3639,16 @@ Transposing beyond buffer boundaries is an error.")
           bcopy (temp, start1_addr + len2_byte + len_mid, len1_byte);
          if (len1_byte > 20000)
            free (temp);
-#ifdef USE_TEXT_PROPERTIES
           graft_intervals_into_buffer (tmp_interval1, end2 - len1,
                                        len1, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
                                        len_mid, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval2, start1,
                                        len2, current_buffer, 0);
-#endif /* USE_TEXT_PROPERTIES */
         }
+
+      update_compositions (start1, start1 + len2, CHECK_BORDER);
+      update_compositions (end2 - len1, end2, CHECK_BORDER);
     }
 
   /* When doing multiple transpositions, it might be nice
@@ -3666,6 +3675,10 @@ syms_of_editfns ()
     = intern ("buffer-access-fontify-functions");
   staticpro (&Qbuffer_access_fontify_functions);
 
+  DEFVAR_LISP ("inhibit-field-text-motion", &Vinhibit_field_text_motion,
+    "Non-nil means.text motion commands don't notice fields.");
+  Vinhibit_field_text_motion = Qnil;
+
   DEFVAR_LISP ("buffer-access-fontify-functions",
               &Vbuffer_access_fontify_functions,
               "List of functions called by `buffer-substring' to fontify if necessary.\n\
@@ -3785,6 +3798,7 @@ functions if all the text being accessed has this property.");
   defsubr (&Ssubst_char_in_region);
   defsubr (&Stranslate_region);
   defsubr (&Sdelete_region);
+  defsubr (&Sdelete_and_extract_region);
   defsubr (&Swiden);
   defsubr (&Snarrow_to_region);
   defsubr (&Ssave_restriction);