*** empty log message ***
[bpt/emacs.git] / src / indent.c
index de76464..a30ef6e 100644 (file)
@@ -1,6 +1,6 @@
 /* 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 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -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"
@@ -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,8 @@ 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.  */)
      (column, minimum)
      Lisp_Object column, minimum;
 {
@@ -1883,7 +1886,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 +1920,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 +1945,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 +1977,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 +2000,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 +2064,72 @@ 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_p;
+
+      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));
+         it_overshoot_expected_p = (s == e);
+       }
+      else
+       it_overshoot_expected_p = (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_p)
+       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;