use dynwind_begin and dynwind_end
[bpt/emacs.git] / src / indent.c
index 45b6afb..5b95bcf 100644 (file)
@@ -1,5 +1,5 @@
 /* Indentation functions.
-   Copyright (C) 1985-1988, 1993-1995, 1998, 2000-2013 Free Software
+   Copyright (C) 1985-1988, 1993-1995, 1998, 2000-2014 Free Software
    Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -56,11 +56,6 @@ static EMACS_INT last_known_column_modified;
 static ptrdiff_t current_column_1 (void);
 static ptrdiff_t position_indentation (ptrdiff_t);
 
-/* Cache of beginning of line found by the last call of
-   current_column. */
-
-static ptrdiff_t current_column_bol_cache;
-
 /* Get the display table to use for the current buffer.  */
 
 struct Lisp_Char_Table *
@@ -138,7 +133,7 @@ recompute_width_table (struct buffer *buf, struct Lisp_Char_Table *disptab)
   struct Lisp_Vector *widthtab;
 
   if (!VECTORP (BVAR (buf, width_table)))
-    bset_width_table (buf, Fmake_vector (make_number (256), make_number (0)));
+    bset_width_table (buf, make_uninit_vector (256));
   widthtab = XVECTOR (BVAR (buf, width_table));
   eassert (widthtab->header.size == 256);
 
@@ -146,33 +141,54 @@ recompute_width_table (struct buffer *buf, struct Lisp_Char_Table *disptab)
     XSETFASTINT (widthtab->contents[i], character_width (i, disptab));
 }
 
-/* Allocate or free the width run cache, as requested by the current
-   state of current_buffer's cache_long_line_scans variable.  */
+/* Allocate or free the width run cache, as requested by the
+   current state of current_buffer's cache_long_scans variable.  */
 
-static void
+static struct region_cache *
 width_run_cache_on_off (void)
 {
-  if (NILP (BVAR (current_buffer, cache_long_line_scans))
+  struct buffer *cache_buffer = current_buffer;
+  bool indirect_p = false;
+
+  if (cache_buffer->base_buffer)
+    {
+      cache_buffer = cache_buffer->base_buffer;
+      indirect_p = true;
+    }
+
+  if (NILP (BVAR (current_buffer, cache_long_scans))
       /* And, for the moment, this feature doesn't work on multibyte
          characters.  */
       || !NILP (BVAR (current_buffer, enable_multibyte_characters)))
     {
-      /* It should be off.  */
-      if (current_buffer->width_run_cache)
-        {
-          free_region_cache (current_buffer->width_run_cache);
-          current_buffer->width_run_cache = 0;
-          bset_width_table (current_buffer, Qnil);
+      if (!indirect_p
+         || NILP (BVAR (cache_buffer, cache_long_scans))
+         || !NILP (BVAR (cache_buffer, enable_multibyte_characters)))
+       {
+         /* It should be off.  */
+         if (cache_buffer->width_run_cache)
+           {
+             free_region_cache (cache_buffer->width_run_cache);
+             cache_buffer->width_run_cache = 0;
+             bset_width_table (current_buffer, Qnil);
+           }
         }
+      return NULL;
     }
   else
     {
-      /* It should be on.  */
-      if (current_buffer->width_run_cache == 0)
-        {
-          current_buffer->width_run_cache = new_region_cache ();
-          recompute_width_table (current_buffer, buffer_display_table ());
-        }
+      if (!indirect_p
+         || (!NILP (BVAR (cache_buffer, cache_long_scans))
+             && NILP (BVAR (cache_buffer, enable_multibyte_characters))))
+       {
+         /* It should be on.  */
+         if (cache_buffer->width_run_cache == 0)
+           {
+             cache_buffer->width_run_cache = new_region_cache ();
+             recompute_width_table (current_buffer, buffer_display_table ());
+           }
+       }
+      return cache_buffer->width_run_cache;
     }
 }
 
@@ -254,7 +270,7 @@ skip_invisible (ptrdiff_t pos, ptrdiff_t *next_boundary_p, ptrdiff_t to, Lisp_Ob
      the next property change */
   prop = Fget_char_property (position, Qinvisible,
                             (!NILP (window)
-                             && EQ (XWINDOW (window)->buffer, buffer))
+                             && EQ (XWINDOW (window)->contents, buffer))
                             ? window : buffer);
   inv_p = TEXT_PROP_MEANS_INVISIBLE (prop);
   /* When counting columns (window == nil), don't skip over ellipsis text.  */
@@ -291,7 +307,7 @@ 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
+and point (e.g., 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).
@@ -439,11 +455,6 @@ current_column (void)
       col += post_tab;
     }
 
-  if (ptr == BEGV_ADDR)
-    current_column_bol_cache = BEGV;
-  else
-    current_column_bol_cache = BYTE_TO_CHAR (PTR_BYTE_POS (ptr));
-
   last_known_column = col;
   last_known_column_point = PT;
   last_known_column_modified = MODIFF;
@@ -520,16 +531,10 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, ptrdiff_t *prevcol)
   register ptrdiff_t col = 0, prev_col = 0;
   EMACS_INT goal = goalcol ? *goalcol : MOST_POSITIVE_FIXNUM;
   ptrdiff_t end = endpos ? *endpos : PT;
-  ptrdiff_t scan, scan_byte;
-  ptrdiff_t next_boundary;
-  {
-  ptrdiff_t opoint = PT, opoint_byte = PT_BYTE;
-  scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1);
-  current_column_bol_cache = PT;
-  scan = PT, scan_byte = PT_BYTE;
-  SET_PT_BOTH (opoint, opoint_byte);
+  ptrdiff_t scan, scan_byte, next_boundary;
+
+  scan = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &scan_byte, 1);
   next_boundary = scan;
-  }
 
   window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
   w = ! NILP (window) ? XWINDOW (window) : NULL;
@@ -695,7 +700,7 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, ptrdiff_t *prevcol)
     *prevcol = prev_col;
 }
 
-/* Return the column number of position POS
+/* Return the column number of point
    by scanning forward from the beginning of the line.
    This function handles characters that are invisible
    due to text properties or overlays.  */
@@ -846,14 +851,10 @@ This is the horizontal position of the character
 following any initial whitespace.  */)
   (void)
 {
-  Lisp_Object val;
-  ptrdiff_t opoint = PT, opoint_byte = PT_BYTE;
-
-  scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1);
+  ptrdiff_t posbyte;
 
-  XSETFASTINT (val, position_indentation (PT_BYTE));
-  SET_PT_BOTH (opoint, opoint_byte);
-  return val;
+  find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &posbyte, 1);
+  return make_number (position_indentation (posbyte));
 }
 
 static ptrdiff_t
@@ -919,7 +920,7 @@ position_indentation (ptrdiff_t pos_byte)
          column += tab_width - column % tab_width;
          break;
        default:
-         if (ASCII_BYTE_P (p[-1])
+         if (ASCII_CHAR_P (p[-1])
              || NILP (BVAR (current_buffer, enable_multibyte_characters)))
            return column;
          {
@@ -946,16 +947,13 @@ position_indentation (ptrdiff_t pos_byte)
 bool
 indented_beyond_p (ptrdiff_t pos, ptrdiff_t pos_byte, EMACS_INT column)
 {
-  ptrdiff_t val;
-  ptrdiff_t 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);
-
-  val = position_indentation (PT_BYTE);
-  SET_PT_BOTH (opoint, opoint_byte);
-  return val >= column;
+  while (pos > BEGV && FETCH_BYTE (pos_byte) == '\n')
+    {
+      DEC_BOTH (pos, pos_byte);
+      pos = find_newline (pos, pos_byte, BEGV, BEGV_BYTE,
+                         -1, NULL, &pos_byte, 0);
+    }
+  return position_indentation (pos_byte) >= column;
 }
 \f
 DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2,
@@ -1088,8 +1086,8 @@ static struct position val_compute_motion;
            : (window_width + window_left != frame_cols))
 
        where
-         window_width is XFASTINT (w->total_cols),
-         window_left is XFASTINT (w->left_col),
+         window_width is w->total_cols,
+         window_left is w->left_col,
          has_vertical_scroll_bars is
            WINDOW_HAS_VERTICAL_SCROLL_BAR (window)
          and frame_cols = FRAME_COLS (XFRAME (window->frame))
@@ -1102,8 +1100,8 @@ static struct position val_compute_motion;
    the scroll bars if they are turned on.  */
 
 struct position *
-compute_motion (ptrdiff_t from, EMACS_INT fromvpos, EMACS_INT fromhpos,
-               bool did_motion, ptrdiff_t to,
+compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos,
+               EMACS_INT fromhpos, bool did_motion, ptrdiff_t to,
                EMACS_INT tovpos, EMACS_INT tohpos, EMACS_INT width,
                ptrdiff_t hscroll, int tab_offset, struct window *win)
 {
@@ -1151,12 +1149,16 @@ compute_motion (ptrdiff_t from, EMACS_INT fromvpos, EMACS_INT fromhpos,
   EMACS_INT contin_hpos;       /* HPOS of last column of continued line.  */
   int prev_tab_offset;         /* Previous tab offset.  */
   int continuation_glyph_width;
+  struct buffer *cache_buffer = current_buffer;
+  struct region_cache *width_cache;
 
   struct composition_it cmp_it;
 
   XSETWINDOW (window, win);
 
-  width_run_cache_on_off ();
+  if (cache_buffer->base_buffer)
+    cache_buffer = cache_buffer->base_buffer;
+  width_cache = width_run_cache_on_off ();
   if (dp == buffer_display_table ())
     width_table = (VECTORP (BVAR (current_buffer, width_table))
                    ? XVECTOR (BVAR (current_buffer, width_table))->contents
@@ -1169,7 +1171,7 @@ compute_motion (ptrdiff_t from, EMACS_INT fromvpos, EMACS_INT fromhpos,
   /* Negative width means use all available text columns.  */
   if (width < 0)
     {
-      width = window_body_cols (win);
+      width = window_body_width (win, 0);
       /* We must make room for continuation marks if we don't have fringes.  */
 #ifdef HAVE_WINDOW_SYSTEM
       if (!FRAME_WINDOW_P (XFRAME (win->frame)))
@@ -1186,8 +1188,11 @@ compute_motion (ptrdiff_t from, EMACS_INT fromvpos, EMACS_INT fromhpos,
   immediate_quit = 1;
   QUIT;
 
+  /* It's just impossible to be too paranoid here.  */
+  eassert (from == BYTE_TO_CHAR (frombyte) && frombyte == CHAR_TO_BYTE (from));
+
   pos = prev_pos = from;
-  pos_byte = prev_pos_byte = CHAR_TO_BYTE (from);
+  pos_byte = prev_pos_byte = frombyte;
   contin_hpos = 0;
   prev_tab_offset = tab_offset;
   memset (&cmp_it, 0, sizeof cmp_it);
@@ -1328,8 +1333,7 @@ compute_motion (ptrdiff_t from, EMACS_INT fromvpos, EMACS_INT fromhpos,
                  TO (we need to go back below).  */
              if (pos <= to)
                {
-                 pos = find_before_next_newline (pos, to, 1);
-                 pos_byte = CHAR_TO_BYTE (pos);
+                 pos = find_before_next_newline (pos, to, 1, &pos_byte);
                  hpos = width;
                  /* If we just skipped next_boundary,
                     loop around in the main while
@@ -1425,13 +1429,11 @@ compute_motion (ptrdiff_t from, EMACS_INT fromvpos, EMACS_INT fromhpos,
 
       /* Consult the width run cache to see if we can avoid inspecting
          the text character-by-character.  */
-      if (current_buffer->width_run_cache && pos >= next_width_run)
+      if (width_cache && pos >= next_width_run)
         {
           ptrdiff_t run_end;
           int common_width
-            = region_cache_forward (current_buffer,
-                                    current_buffer->width_run_cache,
-                                    pos, &run_end);
+            = region_cache_forward (cache_buffer, width_cache, pos, &run_end);
 
           /* A width of zero means the character's width varies (like
              a tab), is meaningless (like a newline), or we just don't
@@ -1507,7 +1509,7 @@ compute_motion (ptrdiff_t from, EMACS_INT fromvpos, EMACS_INT fromhpos,
          pos++, pos_byte++;
 
          /* Perhaps add some info to the width_run_cache.  */
-         if (current_buffer->width_run_cache)
+         if (width_cache)
            {
              /* Is this character part of the current run?  If so, extend
                 the run.  */
@@ -1523,8 +1525,7 @@ compute_motion (ptrdiff_t from, EMACS_INT fromvpos, EMACS_INT fromhpos,
                     (Currently, we only cache runs of width == 1).  */
                  if (width_run_start < width_run_end
                      && width_run_width == 1)
-                   know_region_cache (current_buffer,
-                                      current_buffer->width_run_cache,
+                   know_region_cache (cache_buffer, width_cache,
                                       width_run_start, width_run_end);
 
                  /* Start recording a new width run.  */
@@ -1583,10 +1584,9 @@ compute_motion (ptrdiff_t from, EMACS_INT fromvpos, EMACS_INT fromhpos,
                          /* Skip any number of invisible lines all at once */
                          do
                            {
-                             pos = find_before_next_newline (pos, to, 1);
+                             pos = find_before_next_newline (pos, to, 1, &pos_byte);
                              if (pos < to)
-                               pos++;
-                             pos_byte = CHAR_TO_BYTE (pos);
+                               INC_BOTH (pos, pos_byte);
                            }
                          while (pos < to
                                 && indented_beyond_p (pos, pos_byte,
@@ -1622,10 +1622,7 @@ compute_motion (ptrdiff_t from, EMACS_INT fromvpos, EMACS_INT fromhpos,
                     everything from a ^M to the end of the line is invisible.
                     Stop *before* the real newline.  */
                  if (pos < to)
-                   {
-                     pos = find_before_next_newline (pos, to, 1);
-                     pos_byte = CHAR_TO_BYTE (pos);
-                   }
+                   pos = find_before_next_newline (pos, to, 1, &pos_byte);
                  /* If we just skipped next_boundary,
                     loop around in the main while
                     and handle it.  */
@@ -1664,10 +1661,10 @@ compute_motion (ptrdiff_t from, EMACS_INT fromvpos, EMACS_INT fromhpos,
  after_loop:
 
   /* Remember any final width run in the cache.  */
-  if (current_buffer->width_run_cache
+  if (width_cache
       && width_run_width == 1
       && width_run_start < width_run_end)
-    know_region_cache (current_buffer, current_buffer->width_run_cache,
+    know_region_cache (cache_buffer, width_cache,
                        width_run_start, width_run_end);
 
   val_compute_motion.bufpos = pos;
@@ -1729,7 +1726,8 @@ of a certain window, pass the window's starting location as FROM
 and the window's upper-left coordinates as FROMPOS.
 Pass the buffer's (point-max) as TO, to limit the scan to the end of the
 visible section of the buffer, and pass LINE and COL as TOPOS.  */)
-  (Lisp_Object from, Lisp_Object frompos, Lisp_Object to, Lisp_Object topos, Lisp_Object width, Lisp_Object offsets, Lisp_Object window)
+  (Lisp_Object from, Lisp_Object frompos, Lisp_Object to, Lisp_Object topos,
+   Lisp_Object width, Lisp_Object offsets, Lisp_Object window)
 {
   struct window *w;
   Lisp_Object bufpos, hpos, vpos, prevhpos;
@@ -1772,14 +1770,15 @@ visible section of the buffer, and pass LINE and COL as TOPOS.  */)
   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)),
+  pos = compute_motion (XINT (from), CHAR_TO_BYTE (XINT (from)),
+                       XINT (XCDR (frompos)),
                        XINT (XCAR (frompos)), 0,
                        XINT (to),
                        (NILP (topos)
                         ? window_internal_height (w)
                         : XINT (XCDR (topos))),
                        (NILP (topos)
-                        ? (window_body_cols (w)
+                        ? (window_body_width (w, 0)
                            - (
 #ifdef HAVE_WINDOW_SYSTEM
                               FRAME_WINDOW_P (XFRAME (w->frame)) ? 0 :
@@ -1794,28 +1793,23 @@ visible section of the buffer, and pass LINE and COL as TOPOS.  */)
   XSETINT (vpos, pos->vpos);
   XSETINT (prevhpos, pos->prevhpos);
 
-  return Fcons (bufpos,
-               Fcons (hpos,
-                      Fcons (vpos,
-                             Fcons (prevhpos,
-                                    Fcons (pos->contin ? Qt : Qnil, Qnil)))));
-
+  return list5 (bufpos, hpos, vpos, prevhpos, pos->contin ? Qt : Qnil);
 }
-\f
-/* Fvertical_motion and vmotion */
+
+/* Fvertical_motion and vmotion */
 
 static struct position val_vmotion;
 
 struct position *
-vmotion (register ptrdiff_t from, register EMACS_INT vtarget, struct window *w)
+vmotion (register ptrdiff_t from, register ptrdiff_t from_byte,
+        register EMACS_INT vtarget, struct window *w)
 {
   ptrdiff_t hscroll = w->hscroll;
   struct position pos;
-  /* vpos is cumulative vertical position, changed as from is changed */
+  /* VPOS is cumulative vertical position, changed as from is changed.  */
   register EMACS_INT vpos = 0;
   ptrdiff_t prevline;
   register ptrdiff_t first;
-  ptrdiff_t from_byte;
   ptrdiff_t lmargin = hscroll > 0 ? 1 - hscroll : 0;
   ptrdiff_t selective
     = (INTEGERP (BVAR (current_buffer, selective_display))
@@ -1831,7 +1825,7 @@ vmotion (register ptrdiff_t from, register EMACS_INT vtarget, struct window *w)
 
   /* 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 ()))
+  if (EQ (w->contents, Fcurrent_buffer ()))
     text_prop_object = window;
   else
     text_prop_object = Fcurrent_buffer ();
@@ -1845,44 +1839,44 @@ vmotion (register ptrdiff_t from, register EMACS_INT vtarget, struct window *w)
 
       while ((vpos > vtarget || first) && from > BEGV)
        {
+         ptrdiff_t bytepos = from_byte;
          Lisp_Object propval;
 
-         prevline = find_next_newline_no_quit (from - 1, -1);
+         prevline = from;
+         DEC_BOTH (prevline, bytepos);
+         prevline = find_newline_no_quit (prevline, bytepos, -1, &bytepos);
+
          while (prevline > BEGV
                 && ((selective > 0
-                     && indented_beyond_p (prevline,
-                                           CHAR_TO_BYTE (prevline),
-                                           selective))
+                     && indented_beyond_p (prevline, bytepos, selective))
                     /* 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))))
-           prevline = find_next_newline_no_quit (prevline - 1, -1);
-         pos = *compute_motion (prevline, 0,
-                                lmargin,
-                                0,
-                                from,
+           {
+             DEC_BOTH (prevline, bytepos);
+             prevline = find_newline_no_quit (prevline, bytepos, -1, &bytepos);
+           }
+         pos = *compute_motion (prevline, bytepos, 0, lmargin, 0, from,
                                 /* Don't care for VPOS...  */
                                 1 << (BITS_PER_SHORT - 1),
                                 /* ... nor HPOS.  */
                                 1 << (BITS_PER_SHORT - 1),
-                                -1, hscroll,
-                                0,
-                                w);
+                                -1, hscroll, 0, w);
          vpos -= pos.vpos;
          first = 0;
          from = prevline;
+         from_byte = bytepos;
        }
 
-      /* If we made exactly the desired vertical distance,
-        or if we hit beginning of buffer,
-        return point found */
+      /* If we made exactly the desired vertical distance, or
+        if we hit beginning of buffer, return point found.  */
       if (vpos >= vtarget)
        {
          val_vmotion.bufpos = from;
-         val_vmotion.bytepos = CHAR_TO_BYTE (from);
+         val_vmotion.bytepos = from_byte;
          val_vmotion.vpos = vpos;
          val_vmotion.hpos = lmargin;
          val_vmotion.contin = 0;
@@ -1890,39 +1884,37 @@ vmotion (register ptrdiff_t from, register EMACS_INT vtarget, struct window *w)
          return &val_vmotion;
        }
 
-      /* Otherwise find the correct spot by moving down */
+      /* Otherwise find the correct spot by moving down */
     }
-  /* Moving downward is simple, but must calculate from beg of line
-     to determine hpos of starting point */
-  from_byte = CHAR_TO_BYTE (from);
+
+  /* Moving downward is simple, but must calculate from
+     beg of line to determine hpos of starting point.  */
+
   if (from > BEGV && FETCH_BYTE (from_byte - 1) != '\n')
     {
+      ptrdiff_t bytepos;
       Lisp_Object propval;
 
-      prevline = find_next_newline_no_quit (from, -1);
+      prevline = find_newline_no_quit (from, from_byte, -1, &bytepos);
       while (prevline > BEGV
             && ((selective > 0
-                 && indented_beyond_p (prevline,
-                                       CHAR_TO_BYTE (prevline),
-                                       selective))
+                 && indented_beyond_p (prevline, bytepos, selective))
                 /* 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))))
-       prevline = find_next_newline_no_quit (prevline - 1, -1);
-      pos = *compute_motion (prevline, 0,
-                            lmargin,
-                            0,
-                            from,
+       {
+         DEC_BOTH (prevline, bytepos);
+         prevline = find_newline_no_quit (prevline, bytepos, -1, &bytepos);
+       }
+      pos = *compute_motion (prevline, bytepos, 0, lmargin, 0, from,
                             /* Don't care for VPOS...  */
                             1 << (BITS_PER_SHORT - 1),
                             /* ... nor HPOS.  */
                             1 << (BITS_PER_SHORT - 1),
-                            -1, hscroll,
-                            0,
-                            w);
+                            -1, hscroll, 0, w);
       did_motion = 1;
     }
   else
@@ -1931,11 +1923,9 @@ vmotion (register ptrdiff_t from, register EMACS_INT vtarget, struct window *w)
       pos.vpos = 0;
       did_motion = 0;
     }
-  return compute_motion (from, vpos, pos.hpos, did_motion,
+  return compute_motion (from, from_byte, vpos, pos.hpos, did_motion,
                         ZV, vtarget, - (1 << (BITS_PER_SHORT - 1)),
-                        -1, hscroll,
-                        0,
-                        w);
+                        -1, hscroll, 0, w);
 }
 
 DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 2, 0,
@@ -1954,9 +1944,12 @@ The optional second argument WINDOW specifies the window to use for
 parameters such as width, horizontal scrolling, and so on.
 The default is to use the selected window's parameters.
 
-LINES can optionally take the form (COLS . LINES), in which case
-the motion will not stop at the start of a screen line but on
-its column COLS (if such exists on that line, that is).
+LINES can optionally take the form (COLS . LINES), in which case the
+motion will not stop at the start of a screen line but COLS column
+from the visual start of the line (if such exists on that line, that
+is).  If the line is scrolled horizontally, COLS is interpreted
+visually, i.e., as addition to the columns of text beyond the left
+edge of the window.
 
 `vertical-motion' always uses the current buffer,
 regardless of which buffer is displayed in WINDOW.
@@ -1988,21 +1981,21 @@ whether or not it is currently displayed in some window.  */)
 
   old_buffer = Qnil;
   GCPRO1 (old_buffer);
-  if (XBUFFER (w->buffer) != current_buffer)
+  if (XBUFFER (w->contents) != current_buffer)
     {
       /* Set the window's buffer temporarily to the current buffer.  */
-      old_buffer = w->buffer;
+      old_buffer = w->contents;
       old_charpos = marker_position (w->pointm);
       old_bytepos = marker_byte_position (w->pointm);
       wset_buffer (w, Fcurrent_buffer ());
-      set_marker_both (w->pointm, w->buffer,
+      set_marker_both (w->pointm, w->contents,
                       BUF_PT (current_buffer), BUF_PT_BYTE (current_buffer));
     }
 
   if (noninteractive)
     {
       struct position pos;
-      pos = *vmotion (PT, XINT (lines), w);
+      pos = *vmotion (PT, PT_BYTE, XINT (lines), w);
       SET_PT_BOTH (pos.bufpos, pos.bytepos);
     }
   else
@@ -2026,11 +2019,15 @@ whether or not it is currently displayed in some window.  */)
          const char *s = SSDATA (it.string);
          const char *e = s + SBYTES (it.string);
 
+         disp_string_at_start_p =
          /* If it.area is anything but TEXT_AREA, we need not bother
             about the display string, as it doesn't affect cursor
             positioning.  */
-         disp_string_at_start_p =
-           it.string_from_display_prop_p && it.area == TEXT_AREA;
+           it.area == TEXT_AREA
+           && it.string_from_display_prop_p
+           /* A display string on anything but buffer text (e.g., on
+              an overlay string) doesn't affect cursor positioning.  */
+           && (it.sp > 0 && it.stack[it.sp - 1].method == GET_FROM_BUFFER);
          while (s < e)
            {
              if (*s++ == '\n')
@@ -2057,8 +2054,15 @@ whether or not it is currently displayed in some window.  */)
           string, move_it_to will overshoot it, while vertical-motion
           wants to put the cursor _before_ the display string.  So in
           that case, we move to buffer position before the display
-          string, and avoid overshooting.  */
-       move_it_to (&it, disp_string_at_start_p ? PT - 1 : PT,
+          string, and avoid overshooting.  But if the position before
+          the display string is a newline, we don't do this, because
+          otherwise we will end up in a screen line that is one too
+          far back.  */
+       move_it_to (&it,
+                   (!disp_string_at_start_p
+                    || FETCH_BYTE (IT_BYTEPOS (it)) == '\n')
+                   ? PT
+                   : PT - 1,
                    -1, -1, -1, MOVE_TO_POS);
 
       /* IT may move too far if truncate-lines is on and PT lies
@@ -2125,20 +2129,14 @@ whether or not it is currently displayed in some window.  */)
            }
        }
 
-      /* Move to the goal column, if one was specified.  */
+      /* Move to the goal column, if one was specified.  If the window
+        was originally hscrolled, the goal column is interpreted as
+        an addition to the hscroll amount.  */
       if (!NILP (lcols))
        {
-         /* If the window was originally hscrolled, move forward by
-            the hscrolled amount first.  */
-         if (first_x > 0)
-           {
-             move_it_in_display_line (&it, ZV, first_x, MOVE_TO_X);
-             it.current_x = 0;
-           }
-         move_it_in_display_line
-           (&it, ZV,
-            (int)(cols * FRAME_COLUMN_WIDTH (XFRAME (w->frame)) + 0.5),
-            MOVE_TO_X);
+         int to_x = (int)(cols * FRAME_COLUMN_WIDTH (XFRAME (w->frame)) + 0.5);
+
+         move_it_in_display_line (&it, ZV, first_x + to_x, MOVE_TO_X);
        }
 
       SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
@@ -2148,11 +2146,11 @@ whether or not it is currently displayed in some window.  */)
   if (BUFFERP (old_buffer))
     {
       wset_buffer (w, old_buffer);
-      set_marker_both (w->pointm, w->buffer,
+      set_marker_both (w->pointm, w->contents,
                       old_charpos, old_bytepos);
     }
 
-  RETURN_UNGCPRO (make_number (it.vpos));
+  return make_number (it.vpos);
 }
 
 
@@ -2162,14 +2160,9 @@ whether or not it is currently displayed in some window.  */)
 void
 syms_of_indent (void)
 {
+#include "indent.x"
+
   DEFVAR_BOOL ("indent-tabs-mode", indent_tabs_mode,
               doc: /* Indentation can insert tabs if this is non-nil.  */);
   indent_tabs_mode = 1;
-
-  defsubr (&Scurrent_indentation);
-  defsubr (&Sindent_to);
-  defsubr (&Scurrent_column);
-  defsubr (&Smove_to_column);
-  defsubr (&Svertical_motion);
-  defsubr (&Scompute_motion);
 }