(window_loop) <GET_BUFFER_WINDOW>: Prefer to return
[bpt/emacs.git] / src / indent.c
index 6ca70c7..9e187b8 100644 (file)
@@ -25,6 +25,7 @@ Boston, MA 02111-1307, USA.  */
 #include "charset.h"
 #include "category.h"
 #include "indent.h"
+#include "keyboard.h"
 #include "frame.h"
 #include "window.h"
 #include "termchar.h"
@@ -203,7 +204,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,68 +267,55 @@ skip_invisible (pos, next_boundary_p, to, window)
   return pos;
 }
 \f
-/* Set variables WIDTH and BYTES for a multibyte sequence starting at P.
+/* If a composition starts at POS/POS_BYTE and it doesn't stride over
+   POINT, set *LEN / *LEN_BYTE to the character and byte lengths, *WIDTH
+   to the width, and return 1.  Otherwise, return 0.  */
+
+static int
+check_composition (pos, pos_byte, point, len, len_byte, width)
+     int pos, pos_byte, point;
+     int *len, *len_byte, *width;
+{
+  Lisp_Object prop;
+  int start, end;
+  int id;
 
-   C is *P which should satisfy `BASE_LEADING_CODE_P (c)'.
+  if (! find_composition (pos, -1, &start, &end, &prop, Qnil)
+      || pos != start || point < end
+      || !COMPOSITION_VALID_P (start, end, prop))
+    return 0;
+  if ((id = get_composition_id (pos, pos_byte, end - pos, prop, Qnil)) < 0)
+    return 0;
+
+  *len = COMPOSITION_LENGTH (prop);
+  *len_byte = CHAR_TO_BYTE (end) - pos_byte;
+  *width = composition_table[id]->width;
+  return 1;
+}
+\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, c, dp)                                        \
+#define MULTIBYTE_BYTES_WIDTH(p, dp)                                   \
   do {                                                                 \
-    unsigned char *pend = p + 1;                                       \
+    int c;                                                             \
                                                                        \
     wide_column = 0;                                                   \
-    while (! CHAR_HEAD_P (*pend)) pend++;                              \
-                                                                       \
-    if (c == LEADING_CODE_COMPOSITION)                                 \
-      {                                                                        \
-       int id = str_cmpchar_id (p, pend - p);                          \
-       int ch = MAKE_COMPOSITE_CHAR (id);                              \
-                                                                       \
-       if (id >= 0)                                                    \
-         {                                                             \
-           bytes = cmpchar_table[id]->len;                             \
-           if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, ch)))         \
-             width = XVECTOR (DISP_CHAR_VECTOR (dp, ch))->size;        \
-           else                                                        \
-             width = cmpchar_table[id]->width;                         \
-           if (width > 1)                                              \
-             wide_column = width;                                      \
-         }                                                             \
-       else                                                            \
-         {                                                             \
-           bytes = 1;                                                  \
-           width = 4;                                                  \
-         }                                                             \
-      }                                                                        \
+    c = STRING_CHAR_AND_LENGTH (p, MAX_MULTIBYTE_LENGTH, bytes);       \
+    if (BYTES_BY_CHAR_HEAD (*p) != bytes)                              \
+      width = bytes * 4;                                               \
     else                                                               \
       {                                                                        \
-       bytes = BYTES_BY_CHAR_HEAD (c);                                 \
-       if (bytes >= 2 && bytes <= pend - p)                            \
-         {                                                             \
-           int ch;                                                     \
-                                                                       \
-           if (dp && (ch = STRING_CHAR (p, bytes),                     \
-                      VECTORP (DISP_CHAR_VECTOR (dp, ch))))            \
-             width = XVECTOR (DISP_CHAR_VECTOR (dp, ch))->size;        \
-           else                                                        \
-             width = WIDTH_BY_CHAR_HEAD (c);                           \
-           if (width > 1)                                              \
-             wide_column = width;                                      \
-         }                                                             \
+       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))              \
+         width = XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;             \
        else                                                            \
-         {                                                             \
-           bytes = 1;                                                  \
-           width = 4;                                                  \
-         }                                                             \
-      }                                                                        \
-    if (p + bytes < pend)                                              \
-      {                                                                        \
-       width += 4 * (pend - (p + bytes));                              \
-       bytes = pend - p;                                               \
+         width = WIDTH_BY_CHAR_HEAD (*p);                              \
+       if (width > 1)                                                  \
+         wide_column = width;                                          \
       }                                                                        \
   } while (0)
 
@@ -367,7 +355,6 @@ current_column ()
   register int tab_width = XINT (current_buffer->tab_width);
   int ctl_arrow = !NILP (current_buffer->ctl_arrow);
   register struct Lisp_Char_Table *dp = buffer_display_table ();
-  int stopchar;
 
   if (PT == last_known_column_point
       && MODIFF == last_known_column_modified)
@@ -503,6 +490,21 @@ current_column_1 ()
          next_boundary_byte = CHAR_TO_BYTE (next_boundary);
        }
 
+      /* Check composition sequence.  */
+      {
+       int len, len_byte, width;
+
+       if (check_composition (scan, scan_byte, opoint,
+                              &len, &len_byte, &width))
+         {
+           scan += len;
+           scan_byte += len_byte;
+           if (scan <= opoint)
+             col += width;
+           continue;
+         }
+      }
+
       c = FETCH_BYTE (scan_byte);
       if (dp != 0
          && ! (multibyte && BASE_LEADING_CODE_P (c))
@@ -532,7 +534,7 @@ current_column_1 ()
 
          scan_byte--;
          ptr = BYTE_POS_ADDR (scan_byte);
-         MULTIBYTE_BYTES_WIDTH (ptr, c, dp);
+         MULTIBYTE_BYTES_WIDTH (ptr, dp);
          scan_byte += bytes;
          col += width;
        }
@@ -801,7 +803,7 @@ indented_beyond_p (pos, pos_byte, column)
 
   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",
@@ -814,9 +816,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)
@@ -832,8 +835,8 @@ The return value is the current column.")
   register int multibyte = !NILP (current_buffer->enable_multibyte_characters);
 
   Lisp_Object val;
-  int prev_col;
-  int c;
+  int prev_col = 0;
+  int c = 0;
   int next_boundary;
 
   int pos_byte, end_byte, next_boundary_byte;
@@ -878,6 +881,19 @@ The return value is the current column.")
       if (col >= goal)
        break;
 
+      /* Check composition sequence.  */
+      {
+       int len, len_byte, width;
+
+       if (check_composition (pos, pos_byte, Z, &len, &len_byte, &width))
+         {
+           pos += len;
+           pos_byte += len_byte;
+           col += width;
+           continue;
+         }
+      }
+
       c = FETCH_BYTE (pos_byte);
       if (dp != 0
          && ! (multibyte && BASE_LEADING_CODE_P (c))
@@ -914,7 +930,7 @@ The return value is the current column.")
 
          pos_byte--;
          ptr = BYTE_POS_ADDR (pos_byte);
-         MULTIBYTE_BYTES_WIDTH (ptr, c, dp);
+         MULTIBYTE_BYTES_WIDTH (ptr, dp);
          pos_byte += bytes;
          col += width;
        }
@@ -929,20 +945,27 @@ The return value is the current column.")
      and scan through it again.  */
   if (!NILP (force) && col > goal && c == '\t' && prev_col < goal)
     {
-      int old_point, old_point_byte;
-
-      del_range (PT - 1, PT);
-      Findent_to (make_number (goal), Qnil);
-      old_point = PT;
-      old_point_byte = PT_BYTE;
+      int goal_pt, goal_pt_byte;
+
+      /* Insert spaces in front of the tab to reach GOAL.  Do this
+        first so that a marker at the end of the tab gets
+        adjusted.  */
+      SET_PT_BOTH (PT - 1, PT_BYTE - 1);
+      Finsert_char (make_number (' '), make_number (goal - prev_col), Qt);
+
+      /* Now delete the tab, and indent to COL.  */
+      del_range (PT, PT + 1);
+      goal_pt = PT;
+      goal_pt_byte = PT_BYTE;
       Findent_to (make_number (col), Qnil);
-      SET_PT_BOTH (old_point, old_point_byte);
+      SET_PT_BOTH (goal_pt, goal_pt_byte);
+      
       /* Set the last_known... vars consistently.  */
       col = goal;
     }
 
   /* 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;
@@ -1030,7 +1053,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
 
   register int pos;
   int pos_byte;
-  register int c;
+  register int c = 0;
   register int tab_width = XFASTINT (current_buffer->tab_width);
   register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
   register struct Lisp_Char_Table *dp = window_display_table (win);
@@ -1082,7 +1105,11 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
        run cache, because that's based on the buffer's display table.  */
     width_table = 0;
 
-  if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
+  if (tab_width <= 0 || tab_width > 1000)
+    tab_width = 8;
+
+  immediate_quit = 1;
+  QUIT;
 
   pos = prev_pos = from;
   pos_byte = prev_pos_byte = CHAR_TO_BYTE (from);
@@ -1095,6 +1122,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
@@ -1124,6 +1171,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
          if (newpos >= to)
            {
              pos = min (to, newpos);
+             pos_byte = CHAR_TO_BYTE (pos);
              goto after_loop;
            }
 
@@ -1260,7 +1308,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
-             && wide_column_end_hpos > width)
+             && 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
@@ -1338,6 +1387,20 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
       else
        {
          c = FETCH_BYTE (pos_byte);
+
+         /* Check composition sequence.  */
+         {
+           int len, len_byte, width;
+
+           if (check_composition (pos, pos_byte, to, &len, &len_byte, &width))
+             {
+               pos += len;
+               pos_byte += len_byte;
+               hpos += width;
+               continue;
+             }
+         }
+
          pos++, pos_byte++;
 
          /* Perhaps add some info to the width_run_cache.  */
@@ -1393,7 +1456,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
@@ -1454,7 +1519,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
 
              pos_byte--;       /* rewind POS_BYTE */
              ptr = BYTE_POS_ADDR (pos_byte);
-             MULTIBYTE_BYTES_WIDTH (ptr, c, dp);
+             MULTIBYTE_BYTES_WIDTH (ptr, dp);
              pos_byte += bytes;
              if (wide_column)
                wide_column_end_hpos = hpos + wide_column;
@@ -1488,9 +1553,11 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
   /* Nonzero if have just continued a line */
   val_compute_motion.contin = (contin_hpos && prev_hpos == 0);
 
+  immediate_quit = 0;
   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,
@@ -1542,26 +1609,26 @@ DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0,
      Lisp_Object from, frompos, to, topos;
      Lisp_Object width, offsets, window;
 {
-  Lisp_Object bufpos, hpos, vpos, prevhpos, contin;
+  Lisp_Object bufpos, hpos, vpos, prevhpos;
   struct position *pos;
   int hscroll, tab_offset;
 
   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;
@@ -1576,10 +1643,10 @@ DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0,
   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 (XCONS (frompos)->cdr),
-                       XINT (XCONS (frompos)->car), 0,
-                       XINT (to), XINT (XCONS (topos)->cdr),
-                       XINT (XCONS (topos)->car),
+  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));
 
@@ -1620,21 +1687,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)
     {
@@ -1653,14 +1716,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));
@@ -1716,13 +1776,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));
@@ -1778,19 +1835,40 @@ 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 window *w;
+  Lisp_Object old_buffer;
+  struct gcpro gcpro1;
 
   CHECK_NUMBER (lines, 0);
   if (! NILP (window))
     CHECK_WINDOW (window, 0);
   else
     window = selected_window;
+  w = XWINDOW (window);
 
-  pos = *vmotion (PT, (int) XINT (lines), XWINDOW (window));
-
-  SET_PT (pos.bufpos);
-  return make_number (pos.vpos);
+  old_buffer = Qnil;
+  GCPRO1 (old_buffer);
+  if (XBUFFER (w->buffer) != current_buffer)
+    {
+      /* Set the window's buffer temporarily to the current buffer.  */
+      old_buffer = w->buffer;
+      XSETBUFFER (w->buffer, current_buffer);
+    }
+      
+  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 (BUFFERP (old_buffer))
+    w->buffer = old_buffer;
+  
+  RETURN_UNGCPRO (make_number (it.vpos));
 }
+
+
 \f
 /* file's initialization.  */