(x_draw_image_glyph_string): Adjust stipple origin when
[bpt/emacs.git] / src / indent.c
index 63f1ed3..b3c1d0c 100644 (file)
@@ -1,12 +1,12 @@
 /* Indentation functions.
-   Copyright (C) 1985,86,87,88,93,94,95,98,2000,01,02,03,2004
-   Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1998, 2000, 2001,
+                 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -16,8 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include <config.h>
 #include "lisp.h"
@@ -116,7 +116,7 @@ character_width (c, dp)
     return 0;
 }
 
-/* Return true iff the display table DISPTAB specifies the same widths
+/* Return true if the display table DISPTAB specifies the same widths
    for characters as WIDTHTAB.  We use this to decide when to
    invalidate the buffer's width_run_cache.  */
 
@@ -220,7 +220,7 @@ skip_invisible (pos, next_boundary_p, to, window)
      Lisp_Object window;
 {
   Lisp_Object prop, position, overlay_limit, proplimit;
-  Lisp_Object buffer;
+  Lisp_Object buffer, tmp;
   int end, inv_p;
 
   XSETFASTINT (position, pos);
@@ -251,8 +251,9 @@ skip_invisible (pos, next_boundary_p, to, window)
       /* No matter what. don't go past next overlay change.  */
       if (XFASTINT (overlay_limit) < XFASTINT (proplimit))
        proplimit = overlay_limit;
-      end = XFASTINT (Fnext_single_property_change (position, Qinvisible,
-                                                   buffer, proplimit));
+      tmp = Fnext_single_property_change (position, Qinvisible,
+                                         buffer, proplimit);
+      end = XFASTINT (tmp);
 #if 0
       /* Don't put the boundary in the middle of multibyte form if
          there is no actual property change.  */
@@ -334,12 +335,14 @@ DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
        doc: /* Return the horizontal position of point.  Beginning of line is column 0.
 This is calculated by adding together the widths of all the displayed
 representations of the character between the start of the previous line
-and point.  (eg control characters will have a width of 2 or 4, tabs
-will have a variable width)
+and point (eg. control characters will have a width of 2 or 4, tabs
+will have a variable width).
 Ignores finite width of frame, which means that this function may return
 values greater than (frame-width).
 Whether the line is visible (if `selective-display' is t) has no effect;
-however, ^M is treated as end of line when `selective-display' is t.  */)
+however, ^M is treated as end of line when `selective-display' is t.
+Text that has an invisible property is considered as having width 0, unless
+`buffer-invisibility-spec' specifies that it is replaced by an ellipsis.  */)
      ()
 {
   Lisp_Object temp;
@@ -731,8 +734,10 @@ string_display_width (string, beg, end)
 \f
 DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
        doc: /* Indent from point with tabs and spaces until COLUMN is reached.
-Optional second argument MININUM says always do at least MININUM spaces
-even if that goes past COLUMN; by default, MININUM is zero.  */)
+Optional second argument MINIMUM says always do at least MINIMUM spaces
+even if that goes past COLUMN; by default, MINIMUM is zero.
+
+The return value is COLUMN.  */)
      (column, minimum)
      Lisp_Object column, minimum;
 {
@@ -906,6 +911,7 @@ indented_beyond_p (pos, pos_byte, column)
 \f
 DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, "p",
        doc: /* Move point to column COLUMN in the current line.
+Interactively, COLUMN is the value of prefix numeric argument.
 The column of a character is calculated by adding together the widths
 as displayed of the previous characters in the line.
 This function ignores line-continuation;
@@ -915,10 +921,10 @@ and horizontal scrolling has no effect.
 If specified column is within a character, point goes after that character.
 If it's past end of line, point goes to end of line.
 
-A non-nil second (optional) argument FORCE means,
-if COLUMN is in the middle of a tab character, change it to spaces.
-In addition, if FORCE is t, and the line is too short
-to reach column COLUMN, add spaces/tabs to get there.
+Optional second argument FORCE non-nil means if COLUMN is in the
+middle of a tab character, change it to spaces.
+In addition, if FORCE is t, and the line is too short to reach
+COLUMN, add spaces/tabs to get there.
 
 The return value is the current column.  */)
      (column, force)
@@ -945,7 +951,6 @@ The return value is the current column.  */)
   pos = PT;
   pos_byte = PT_BYTE;
   end = ZV;
-  next_boundary = pos;
 
   /* If we're starting past the desired column,
      back up to beginning of line and scan from there.  */
@@ -957,6 +962,8 @@ The return value is the current column.  */)
       col = 0;
     }
 
+  next_boundary = pos;
+
   while (pos < end)
     {
       while (pos == next_boundary)
@@ -1260,10 +1267,10 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
        width -= 1;
     }
 
-  continuation_glyph_width = 0;
+  continuation_glyph_width = 1;
 #ifdef HAVE_WINDOW_SYSTEM
-  if (!FRAME_WINDOW_P (XFRAME (win->frame)))
-    continuation_glyph_width = 1;
+  if (FRAME_WINDOW_P (XFRAME (win->frame)))
+    continuation_glyph_width = 0;  /* In the fringe.  */
 #endif
 
   immediate_quit = 1;
@@ -1883,7 +1890,7 @@ vmotion (from, vtarget, w)
   struct position pos;
   /* vpos is cumulative vertical position, changed as from is changed */
   register int vpos = 0;
-  Lisp_Object prevline;
+  int prevline;
   register int first;
   int from_byte;
   int lmargin = hscroll > 0 ? 1 - hscroll : 0;
@@ -1917,23 +1924,21 @@ vmotion (from, vtarget, w)
        {
          Lisp_Object propval;
 
-         XSETFASTINT (prevline, find_next_newline_no_quit (from - 1, -1));
-         while (XFASTINT (prevline) > BEGV
+         prevline = find_next_newline_no_quit (from - 1, -1);
+         while (prevline > BEGV
                 && ((selective > 0
-                     && indented_beyond_p (XFASTINT (prevline),
-                                           CHAR_TO_BYTE (XFASTINT (prevline)),
+                     && indented_beyond_p (prevline,
+                                           CHAR_TO_BYTE (prevline),
                                            (double) selective)) /* iftc */
-                    /* watch out for newlines with `invisible' property */
-                    || (propval = Fget_char_property (prevline,
+                    /* Watch out for newlines with `invisible' property.
+                       When moving upward, check the newline before.  */
+                    || (propval = Fget_char_property (make_number (prevline - 1),
                                                       Qinvisible,
                                                       text_prop_object),
                         TEXT_PROP_MEANS_INVISIBLE (propval))))
-           XSETFASTINT (prevline,
-                        find_next_newline_no_quit (XFASTINT (prevline) - 1,
-                                                   -1));
-         pos = *compute_motion (XFASTINT (prevline), 0,
-                                lmargin + (XFASTINT (prevline) == BEG
-                                           ? start_hpos : 0),
+           prevline = find_next_newline_no_quit (prevline - 1, -1);
+         pos = *compute_motion (prevline, 0,
+                                lmargin + (prevline == BEG ? start_hpos : 0),
                                 0,
                                 from,
                                 /* Don't care for VPOS...  */
@@ -1944,12 +1949,11 @@ vmotion (from, vtarget, w)
                                 /* This compensates for start_hpos
                                    so that a tab as first character
                                    still occupies 8 columns.  */
-                                (XFASTINT (prevline) == BEG
-                                 ? -start_hpos : 0),
+                                (prevline == BEG ? -start_hpos : 0),
                                 w);
          vpos -= pos.vpos;
          first = 0;
-         from = XFASTINT (prevline);
+         from = prevline;
        }
 
       /* If we made exactly the desired vertical distance,
@@ -1977,21 +1981,21 @@ vmotion (from, vtarget, w)
     {
       Lisp_Object propval;
 
-      XSETFASTINT (prevline, find_next_newline_no_quit (from, -1));
-      while (XFASTINT (prevline) > BEGV
+      prevline = find_next_newline_no_quit (from, -1);
+      while (prevline > BEGV
             && ((selective > 0
-                 && indented_beyond_p (XFASTINT (prevline),
-                                       CHAR_TO_BYTE (XFASTINT (prevline)),
+                 && indented_beyond_p (prevline,
+                                       CHAR_TO_BYTE (prevline),
                                        (double) selective)) /* iftc */
-                /* watch out for newlines with `invisible' property */
-                || (propval = Fget_char_property (prevline, Qinvisible,
+                /* Watch out for newlines with `invisible' property.
+                   When moving downward, check the newline after.  */
+                || (propval = Fget_char_property (make_number (prevline),
+                                                  Qinvisible,
                                                   text_prop_object),
                     TEXT_PROP_MEANS_INVISIBLE (propval))))
-       XSETFASTINT (prevline,
-                    find_next_newline_no_quit (XFASTINT (prevline) - 1,
-                                               -1));
-      pos = *compute_motion (XFASTINT (prevline), 0,
-                            lmargin + (XFASTINT (prevline) == BEG
+       prevline = find_next_newline_no_quit (prevline - 1, -1);
+      pos = *compute_motion (prevline, 0,
+                            lmargin + (prevline == BEG
                                        ? start_hpos : 0),
                             0,
                             from,
@@ -2000,7 +2004,7 @@ vmotion (from, vtarget, w)
                             /* ... nor HPOS.  */
                             1 << (BITS_PER_SHORT - 1),
                             -1, hscroll,
-                            (XFASTINT (prevline) == BEG ? -start_hpos : 0),
+                            (prevline == BEG ? -start_hpos : 0),
                             w);
       did_motion = 1;
     }
@@ -2064,21 +2068,79 @@ whether or not it is currently displayed in some window.  */)
       XSETBUFFER (w->buffer, current_buffer);
     }
 
-  SET_TEXT_POS (pt, PT, PT_BYTE);
-  start_display (&it, w, pt);
-
-  /* Move to the start of the display line containing PT.  If we don't
-     do this, we start moving with IT->current_x == 0, while PT is
-     really at some x > 0.  The effect is, in continuation lines, that
-     we end up with the iterator placed at where it thinks X is 0,
-     while the end position is really at some X > 0, the same X that
-     PT had.  */
-  move_it_by_lines (&it, 0, 0);
+  if (noninteractive)
+    {
+      struct position pos;
+      pos = *vmotion (PT, XINT (lines), w);
+      SET_PT_BOTH (pos.bufpos, pos.bytepos);
+    }
+  else
+    {
+      int it_start;
+      int oselective;
+      int it_overshoot_expected;
+
+      SET_TEXT_POS (pt, PT, PT_BYTE);
+      start_display (&it, w, pt);
+
+      /* Scan from the start of the line containing PT.  If we don't
+        do this, we start moving with IT->current_x == 0, while PT is
+        really at some x > 0.  The effect is, in continuation lines, that
+        we end up with the iterator placed at where it thinks X is 0,
+        while the end position is really at some X > 0, the same X that
+        PT had.  */
+      it_start = IT_CHARPOS (it);
+
+      /* We expect the call to move_it_to, further down, to overshoot
+        if the starting point is on an image, stretch glyph,
+        composition, or Lisp string.  We won't need to backtrack in
+        this situation, except for one corner case: when the Lisp
+        string contains a newline.  */
+      if (it.method == GET_FROM_STRING)
+       {
+         const char *s = SDATA (it.string);
+         const char *e = s + SBYTES (it.string);
 
-  if (XINT (lines) != 0)
-    move_it_by_lines (&it, XINT (lines), 0);
+         while (s < e && *s != '\n')
+           ++s;
 
-  SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+         /* If there is no newline in the string, we need to check
+            whether there is a newline immediately after the string
+            in move_it_to below.  This may happen if there is an
+            overlay with an after-string just before the newline.  */
+         it_overshoot_expected = (s == e) ? -1 : 0;
+       }
+      else
+       it_overshoot_expected = (it.method == GET_FROM_IMAGE
+                                || it.method == GET_FROM_STRETCH
+                                || it.method == GET_FROM_COMPOSITION);
+
+      reseat_at_previous_visible_line_start (&it);
+      it.current_x = it.hpos = 0;
+      /* Temporarily disable selective display so we don't move too far */
+      oselective = it.selective;
+      it.selective = 0;
+      move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+      it.selective = oselective;
+
+      /* Move back if we got too far.  This may happen if
+        truncate-lines is on and PT is beyond right margin.
+        Don't go back if the overshoot is expected (see above).  */
+      if (IT_CHARPOS (it) > it_start && XINT (lines) > 0
+         && (!it_overshoot_expected
+             || (it_overshoot_expected < 0
+                 && it.method == GET_FROM_BUFFER
+                 && it.c == '\n')))
+       move_it_by_lines (&it, -1, 0);
+
+      it.vpos = 0;
+      /* Do this even if LINES is 0, so that we move back
+        to the beginning of the current line as we ought.  */
+      if (XINT (lines) >= 0 || IT_CHARPOS (it) > 0)
+       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;