(Faref): Delete codes for a composite character..
[bpt/emacs.git] / src / indent.c
index 195973f..af5b689 100644 (file)
@@ -1,5 +1,5 @@
 /* Indentation functions.
-   Copyright (C) 1985,86,87,88,93,94,95 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,88,93,94,95,98 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -203,7 +203,7 @@ width_run_cache_on_off ()
    characters immediately following, then *NEXT_BOUNDARY_P
    will equal the return value.  */
 
-static int
+int
 skip_invisible (pos, next_boundary_p, to, window)
      int pos;
      int *next_boundary_p;
@@ -266,6 +266,32 @@ skip_invisible (pos, next_boundary_p, to, window)
   return pos;
 }
 \f
+/* Set variables WIDTH and BYTES for a multibyte sequence starting at P.
+
+   DP is a display table or NULL.
+
+   This macro is used in current_column_1, Fmove_to_column, and
+   compute_motion.  */
+
+#define MULTIBYTE_BYTES_WIDTH(p, dp)                                     \
+  do {                                                                   \
+    int c;                                                               \
+                                                                         \
+    wide_column = 0;                                                     \
+    c = STRING_CHAR_AND_LENGTH (p, MAX_LENGTH_OF_MULTI_BYTE_FORM, bytes); \
+    if (BYTES_BY_CHAR_HEAD (*p) != bytes)                                \
+      width = bytes * 4;                                                 \
+    else                                                                 \
+      {                                                                          \
+       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))                \
+         width = XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;               \
+       else                                                              \
+         width = WIDTH_BY_CHAR_HEAD (*p);                                \
+       if (width > 1)                                                    \
+         wide_column = width;                                            \
+      }                                                                          \
+  } while (0)
+
 DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
   "Return the horizontal position of point.  Beginning of line is column 0.\n\
 This is calculated by adding together the widths of all the displayed\n\
@@ -439,7 +465,9 @@ current_column_1 ()
        }
 
       c = FETCH_BYTE (scan_byte);
-      if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
+      if (dp != 0
+         && ! (multibyte && BASE_LEADING_CODE_P (c))
+         && VECTORP (DISP_CHAR_VECTOR (dp, c)))
        {
          col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
          scan++;
@@ -460,42 +488,14 @@ current_column_1 ()
        }
       else if (multibyte && BASE_LEADING_CODE_P (c))
        {
-         scan_byte--;
-         /* Start of multi-byte form.  */
-         if (c == LEADING_CODE_COMPOSITION)
-           {
-             unsigned char *ptr = BYTE_POS_ADDR (scan_byte);
+         unsigned char *ptr;
+         int bytes, width, wide_column;
 
-             int cmpchar_id
-               = str_cmpchar_id (ptr, next_boundary_byte - scan_byte);
-             if (cmpchar_id >= 0)
-               {
-                 scan_byte += cmpchar_table[cmpchar_id]->len;
-                 col += cmpchar_table[cmpchar_id]->width;
-               }
-             else
-               {               /* invalid composite character */
-                 scan_byte++;
-                 col += 4;
-               }
-           }
-         else
-           {
-             /* Here, we check that the following bytes are valid
-                constituents of multi-byte form.  */
-             int len = BYTES_BY_CHAR_HEAD (c), i;
-
-             for (i = 1, scan_byte++; i < len; i++, scan_byte++)
-               /* We don't need range checking for PTR because there
-                  are anchors (`\0') at GAP and Z.  */
-               if (CHAR_HEAD_P (FETCH_BYTE (scan_byte)))
-                 break;
-
-             if (i < len)
-               col += 4, scan_byte -= i - 1;
-             else
-               col += WIDTH_BY_CHAR_HEAD (c);
-           }
+         scan_byte--;
+         ptr = BYTE_POS_ADDR (scan_byte);
+         MULTIBYTE_BYTES_WIDTH (ptr, dp);
+         scan_byte += bytes;
+         col += width;
        }
       else if (ctl_arrow && (c < 040 || c == 0177))
         col += 2;
@@ -640,6 +640,8 @@ even if that goes past COLUMN; by default, MININUM is zero.")
 }
 
 \f
+static int position_indentation P_ ((int));
+
 DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
   0, 0, 0,
   "Return the indentation of the current line.\n\
@@ -751,16 +753,16 @@ int
 indented_beyond_p (pos, pos_byte, column)
      int pos, pos_byte, column;
 {
-  Lisp_Object val;
+  int val;
   int opoint = PT, opoint_byte = PT_BYTE;
 
   SET_PT_BOTH (pos, pos_byte);
   while (PT > BEGV && FETCH_BYTE (PT_BYTE) == '\n')
     scan_newline (PT - 1, PT_BYTE - 1, BEGV, BEGV_BYTE, -1, 0);
 
-  XSETFASTINT (val, position_indentation (PT_BYTE));
+  val = position_indentation (PT_BYTE);
   SET_PT_BOTH (opoint, opoint_byte);
-  return val;
+  return val >= column;
 }
 \f
 DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, "p",
@@ -773,9 +775,10 @@ and horizontal scrolling has no effect.\n\
 \n\
 If specified column is within a character, point goes after that character.\n\
 If it's past end of line, point goes to end of line.\n\n\
-A non-nil second (optional) argument FORCE means, if the line\n\
-is too short to reach column COLUMN then add spaces/tabs to get there,\n\
-and if COLUMN is in the middle of a tab character, change it to spaces.\n\
+A non-nil second (optional) argument FORCE means,\n\
+if COLUMN is in the middle of a tab character, change it to spaces.\n\
+In addition, if FORCE is t, and the line is too short\n\
+to reach column COLUMN, add spaces/tabs to get there.\n\
 \n\
 The return value is the current column.")
   (column, force)
@@ -838,7 +841,9 @@ The return value is the current column.")
        break;
 
       c = FETCH_BYTE (pos_byte);
-      if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
+      if (dp != 0
+         && ! (multibyte && BASE_LEADING_CODE_P (c))
+         && VECTORP (DISP_CHAR_VECTOR (dp, c)))
        {
          col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
          pos_byte++;
@@ -867,41 +872,13 @@ The return value is the current column.")
        {
          /* Start of multi-byte form.  */
          unsigned char *ptr;
+         int bytes, width, wide_column;
 
-         pos_byte--;           /* rewind to the character head */
+         pos_byte--;
          ptr = BYTE_POS_ADDR (pos_byte);
-         if (c == LEADING_CODE_COMPOSITION)
-           {
-             int cmpchar_id = str_cmpchar_id (ptr, end_byte - pos_byte);
-
-             if (cmpchar_id >= 0)
-               {
-                 col += cmpchar_table[cmpchar_id]->width;
-                 pos_byte += cmpchar_table[cmpchar_id]->len;
-               }
-             else
-               {               /* invalid composite character */
-                 col += 4;
-                 pos_byte++;
-               }
-           }
-         else
-           {
-             /* Here, we check that the following bytes are valid
-                constituents of multi-byte form.  */
-             int len = BYTES_BY_CHAR_HEAD (c), i;
-
-             for (i = 1, ptr++; i < len; i++, ptr++)
-               /* We don't need range checking for PTR because there
-                  are anchors (`\0') both at GPT and Z.  */
-               if (CHAR_HEAD_P (*ptr))
-                 break;
-
-             if (i < len)
-               col += 4, pos_byte++;
-             else
-               col += WIDTH_BY_CHAR_HEAD (c), pos_byte += i;
-           }
+         MULTIBYTE_BYTES_WIDTH (ptr, dp);
+         pos_byte += bytes;
+         col += width;
        }
       else
        col += 4;
@@ -927,7 +904,7 @@ The return value is the current column.")
     }
 
   /* If line ends prematurely, add space to the end.  */
-  if (col < goal && !NILP (force))
+  if (col < goal && EQ (force, Qt))
     Findent_to (make_number (col = goal), Qnil);
 
   last_known_column = col;
@@ -1046,8 +1023,9 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
   Lisp_Object window;
 
   int multibyte = !NILP (current_buffer->enable_multibyte_characters);
-  int wide_column = 0;         /* Set to 1 when a previous character
-                                  is wide-colomn.  */
+  /* If previous char scanned was a wide character,
+     this is the column where it ended.  Otherwise, this is 0.  */
+  int wide_column_end_hpos = 0;
   int prev_pos;                        /* Previous buffer position.  */
   int prev_pos_byte;           /* Previous buffer position.  */
   int contin_hpos;             /* HPOS of last column of continued line.  */
@@ -1079,6 +1057,26 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
          int pos_here = pos;
          int newpos;
 
+         /* Don't skip invisible if we are already at the margin.  */
+         if (vpos > tovpos || vpos == tovpos && hpos >= tohpos)
+           {
+             if (contin_hpos && prev_hpos == 0
+                 && hpos > tohpos
+                 && (contin_hpos == width || wide_column_end_hpos > width))
+               { /* Line breaks because we can't put the character at the
+                    previous line any more.  It is not the multi-column
+                    character continued in middle.  Go back to previous
+                    buffer position, screen position, and set tab offset
+                    to previous value.  It's the beginning of the
+                    line.  */
+                 pos = prev_pos;
+                 pos_byte = prev_pos_byte;
+                 hpos = prev_hpos;
+                 tab_offset = prev_tab_offset;
+               }
+             break;
+           }
+
          /* If the caller says that the screen position came from an earlier
             call to compute_motion, then we've already accounted for the
             overlay strings at point.  This is only true the first time
@@ -1091,7 +1089,8 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
            {
              unsigned char *ovstr;
              int ovlen = overlay_strings (pos, win, &ovstr);
-             hpos += (multibyte ? strwidth (ovstr, ovlen) : ovlen);
+             hpos += ((multibyte && ovlen > 0)
+                      ? strwidth (ovstr, ovlen) : ovlen);
            }
          did_motion = 0;
 
@@ -1105,7 +1104,10 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
          newpos = skip_invisible (pos, &next_boundary, to, window);
 
          if (newpos >= to)
-           goto after_loop;
+           {
+             pos = min (to, newpos);
+             goto after_loop;
+           }
 
          if (newpos != pos_here)
            {
@@ -1165,20 +1167,21 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
                  && width + 1 < FRAME_WIDTH (XFRAME (WINDOW_FRAME (win))))
              || !NILP (current_buffer->truncate_lines))
            {
-             /* Truncating: skip to newline.  */
-             if (pos <= to)  /* This IF is needed because we may past TO */
+             /* Truncating: skip to newline, unless we are already past
+                 TO (we need to go back below).  */
+             if (pos <= to)
                {
                  pos = find_before_next_newline (pos, to, 1);
                  pos_byte = CHAR_TO_BYTE (pos);
+                 hpos = width;
+                 /* If we just skipped next_boundary,
+                    loop around in the main while
+                    and handle it.  */
+                 if (pos >= next_boundary)
+                   next_boundary = pos + 1;
+                 prev_hpos = width;
+                 prev_tab_offset = tab_offset;
                }
-             hpos = width;
-             /* If we just skipped next_boundary,
-                loop around in the main while
-                and handle it.  */
-             if (pos >= next_boundary)
-               next_boundary = pos + 1;
-             prev_hpos = width;
-             prev_tab_offset = tab_offset;
            }
          else
            {
@@ -1186,7 +1189,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
              /* Remember the previous value.  */
              prev_tab_offset = tab_offset;
 
-             if (wide_column)
+             if (wide_column_end_hpos > width)
                {
                  hpos -= prev_hpos;
                  tab_offset += prev_hpos;
@@ -1222,7 +1225,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
           */
 
          if (contin_hpos && prev_hpos == 0
-             && contin_hpos < width && !wide_column)
+             && contin_hpos < width && !wide_column_end_hpos)
            {
              /* Line breaking occurs in the middle of multi-column
                 character.  Go back to previous line.  */
@@ -1239,7 +1242,8 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
       if (vpos > tovpos || vpos == tovpos && hpos >= tohpos)
        {
          if (contin_hpos && prev_hpos == 0
-             && ((hpos > tohpos && contin_hpos == width) || wide_column))
+             && hpos > tohpos
+             && (contin_hpos == width || wide_column_end_hpos > width))
            { /* Line breaks because we can't put the character at the
                 previous line any more.  It is not the multi-column
                 character continued in middle.  Go back to previous
@@ -1259,7 +1263,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
       prev_hpos = hpos;
       prev_pos = pos;
       prev_pos_byte = pos_byte;
-      wide_column = 0;
+      wide_column_end_hpos = 0;
 
       /* Consult the width run cache to see if we can avoid inspecting
          the text character-by-character.  */
@@ -1347,8 +1351,9 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
                }
            }
 
-         if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c))
-             && ! (multibyte && BASE_LEADING_CODE_P (c)))
+         if (dp != 0
+             && ! (multibyte && BASE_LEADING_CODE_P (c))
+             && VECTORP (DISP_CHAR_VECTOR (dp, c)))
            hpos += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
          else if (c >= 040 && c < 0177)
            hpos++;
@@ -1371,7 +1376,9 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
                      /* Skip any number of invisible lines all at once */
                      do
                        {
-                         pos = find_before_next_newline (pos, to, 1) + 1;
+                         pos = find_before_next_newline (pos, to, 1);
+                         if (pos < to)
+                           pos++;
                          pos_byte = CHAR_TO_BYTE (pos);
                        }
                      while (pos < to
@@ -1428,37 +1435,15 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
            {
              /* Start of multi-byte form.  */
              unsigned char *ptr;
-             int len, actual_len;
-
-             pos--, pos_byte--;                /* rewind POS */
+             int bytes, width, wide_column;
 
+             pos_byte--;       /* rewind POS_BYTE */
              ptr = BYTE_POS_ADDR (pos_byte);
-             len = BUFFER_CEILING_OF (pos_byte) - pos_byte + 1;
-
-             c = STRING_CHAR_AND_LENGTH (ptr, len, actual_len);
-
-             if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
-               hpos += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
-             else if (actual_len == 1)
-               hpos += 4;
-             else if (COMPOSITE_CHAR_P (c))
-               {
-                 int id = COMPOSITE_CHAR_ID (c);
-                 int width = (id < n_cmpchars) ? cmpchar_table[id]->width : 0;
-                 hpos += width;
-                 if (width > 1)
-                   wide_column = 1;
-               }
-             else
-               {
-                 int width = WIDTH_BY_CHAR_HEAD (*ptr);
-                 hpos += width;
-                 if (width > 1)
-                   wide_column = 1;
-               }
-
-             pos++;
-             pos_byte += actual_len;
+             MULTIBYTE_BYTES_WIDTH (ptr, dp);
+             pos_byte += bytes;
+             if (wide_column)
+               wide_column_end_hpos = hpos + wide_column;
+             hpos += width;
            }
          else
            hpos += (ctl_arrow && c < 0200) ? 2 : 4;
@@ -1478,7 +1463,10 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
   val_compute_motion.bytepos = pos_byte;
   val_compute_motion.hpos = hpos;
   val_compute_motion.vpos = vpos;
-  val_compute_motion.prevhpos = prev_hpos;
+  if (contin_hpos && prev_hpos == 0)
+    val_compute_motion.prevhpos = contin_hpos;
+  else
+    val_compute_motion.prevhpos = prev_hpos;
   /* We alalways handle all of them here; none of them remain to do.  */
   val_compute_motion.ovstring_chars_done = 0;
 
@@ -1488,6 +1476,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
   return &val_compute_motion;
 }
 
+
 #if 0 /* The doc string is too long for some compilers,
         but make-docfile can find it in this comment.  */
 DEFUN ("compute-motion", Ffoo, Sfoo, 7, 7, 0,
@@ -1545,20 +1534,20 @@ DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0,
 
   CHECK_NUMBER_COERCE_MARKER (from, 0);
   CHECK_CONS (frompos, 0);
-  CHECK_NUMBER (XCONS (frompos)->car, 0);
-  CHECK_NUMBER (XCONS (frompos)->cdr, 0);
+  CHECK_NUMBER (XCAR (frompos), 0);
+  CHECK_NUMBER (XCDR (frompos), 0);
   CHECK_NUMBER_COERCE_MARKER (to, 0);
   CHECK_CONS (topos, 0);
-  CHECK_NUMBER (XCONS (topos)->car, 0);
-  CHECK_NUMBER (XCONS (topos)->cdr, 0);
+  CHECK_NUMBER (XCAR (topos), 0);
+  CHECK_NUMBER (XCDR (topos), 0);
   CHECK_NUMBER (width, 0);
   if (!NILP (offsets))
     {
       CHECK_CONS (offsets, 0);
-      CHECK_NUMBER (XCONS (offsets)->car, 0);
-      CHECK_NUMBER (XCONS (offsets)->cdr, 0);
-      hscroll = XINT (XCONS (offsets)->car);
-      tab_offset = XINT (XCONS (offsets)->cdr);
+      CHECK_NUMBER (XCAR (offsets), 0);
+      CHECK_NUMBER (XCDR (offsets), 0);
+      hscroll = XINT (XCAR (offsets));
+      tab_offset = XINT (XCDR (offsets));
     }
   else
     hscroll = tab_offset = 0;
@@ -1568,10 +1557,15 @@ DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0,
   else
     CHECK_LIVE_WINDOW (window, 0);
 
-  pos = compute_motion (XINT (from), XINT (XCONS (frompos)->cdr),
-                       XINT (XCONS (frompos)->car), 0,
-                       XINT (to), XINT (XCONS (topos)->cdr),
-                       XINT (XCONS (topos)->car),
+  if (XINT (from) < BEGV || XINT (from) > ZV)
+    args_out_of_range_3 (from, make_number (BEGV), make_number (ZV));
+  if (XINT (to) < BEGV || XINT (to) > ZV)
+    args_out_of_range_3 (to, make_number (BEGV), make_number (ZV));
+
+  pos = compute_motion (XINT (from), XINT (XCDR (frompos)),
+                       XINT (XCAR (frompos)), 0,
+                       XINT (to), XINT (XCDR (topos)),
+                       XINT (XCAR (topos)),
                        XINT (width), hscroll, tab_offset,
                        XWINDOW (window));
 
@@ -1612,21 +1606,17 @@ vmotion (from, vtarget, w)
   Lisp_Object window;
   int start_hpos = 0;
   int did_motion;
+  /* This is the object we use for fetching character properties.  */
+  Lisp_Object text_prop_object;
 
   XSETWINDOW (window, w);
 
-  /* The omission of the clause
-         && marker_position (w->start) == BEG
-     here is deliberate; I think we want to measure from the prompt
-     position even if the minibuffer window has scrolled.  */
-  if (EQ (window, minibuf_window))
-    {
-      if (minibuf_prompt_width == 0 && STRINGP (minibuf_prompt))
-       minibuf_prompt_width
-         = string_display_width (minibuf_prompt, Qnil, Qnil);
-
-      start_hpos = minibuf_prompt_width;
-    }
+  /* If the window contains this buffer, use it for getting text properties.
+     Otherwise use the current buffer as arg for doing that.  */
+  if (EQ (w->buffer, Fcurrent_buffer ()))
+    text_prop_object = window;
+  else
+    text_prop_object = Fcurrent_buffer ();
 
   if (vpos >= vtarget)
     {
@@ -1645,14 +1635,11 @@ vmotion (from, vtarget, w)
                      && indented_beyond_p (XFASTINT (prevline),
                                            CHAR_TO_BYTE (XFASTINT (prevline)),
                                            selective))
-#ifdef USE_TEXT_PROPERTIES
                     /* watch out for newlines with `invisible' property */
                     || (propval = Fget_char_property (prevline,
                                                       Qinvisible,
-                                                      window),
-                        TEXT_PROP_MEANS_INVISIBLE (propval))
-#endif
-                    ))
+                                                      text_prop_object),
+                        TEXT_PROP_MEANS_INVISIBLE (propval))))
            XSETFASTINT (prevline,
                         find_next_newline_no_quit (XFASTINT (prevline) - 1,
                                                    -1));
@@ -1708,13 +1695,10 @@ vmotion (from, vtarget, w)
                  && indented_beyond_p (XFASTINT (prevline),
                                        CHAR_TO_BYTE (XFASTINT (prevline)),
                                        selective))
-#ifdef USE_TEXT_PROPERTIES
                 /* watch out for newlines with `invisible' property */
                 || (propval = Fget_char_property (prevline, Qinvisible,
-                                                  window),
-                    TEXT_PROP_MEANS_INVISIBLE (propval))
-#endif
-            ))
+                                                  text_prop_object),
+                    TEXT_PROP_MEANS_INVISIBLE (propval))))
        XSETFASTINT (prevline,
                     find_next_newline_no_quit (XFASTINT (prevline) - 1,
                                                -1));
@@ -1770,7 +1754,10 @@ whether or not it is currently displayed in some window.")
   (lines, window)
      Lisp_Object lines, window;
 {
-  struct position pos;
+  struct it it;
+  struct text_pos pt;
+  struct buffer *old, *b;
+  struct window *w;
 
   CHECK_NUMBER (lines, 0);
   if (! NILP (window))
@@ -1778,14 +1765,32 @@ whether or not it is currently displayed in some window.")
   else
     window = selected_window;
 
-  pos = *vmotion (PT, (int) XINT (lines), XWINDOW (window));
-
-  SET_PT (pos.bufpos);
-  return make_number (pos.vpos);
+  w = XWINDOW (window);
+  b = XBUFFER (w->buffer);
+  if (b != current_buffer)
+    {
+      old = current_buffer;
+      set_buffer_internal_1 (b);
+    }
+  else
+    old = NULL;
+      
+  SET_TEXT_POS (pt, PT, PT_BYTE);
+  start_display (&it, w, pt);
+  move_it_by_lines (&it, XINT (lines), 0);
+  SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+
+  if (old)
+    set_buffer_internal_1 (old);
+  
+  return make_number (it.vpos);
 }
+
+
 \f
 /* file's initialization.  */
 
+void
 syms_of_indent ()
 {
   DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,