root/src/indent.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. buffer_display_table
  2. character_width
  3. disptab_matches_widthtab
  4. recompute_width_table
  5. width_run_cache_on_off
  6. skip_invisible
  7. DEFUN
  8. invalidate_current_column
  9. current_column
  10. check_display_width
  11. scan_for_column
  12. current_column_1
  13. string_display_width
  14. DEFUN
  15. position_indentation
  16. indented_beyond_p
  17. compute_motion
  18. vmotion
  19. line_number_display_width
  20. DEFUN
  21. window_column_x
  22. restore_window_buffer
  23. syms_of_indent

     1 /* Indentation functions.
     2    Copyright (C) 1985-1988, 1993-1995, 1998, 2000-2023 Free Software
     3    Foundation, Inc.
     4 
     5 This file is part of GNU Emacs.
     6 
     7 GNU Emacs is free software: you can redistribute it and/or modify
     8 it under the terms of the GNU General Public License as published by
     9 the Free Software Foundation, either version 3 of the License, or (at
    10 your option) any later version.
    11 
    12 GNU Emacs is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    19 
    20 #include <config.h>
    21 
    22 #include "lisp.h"
    23 #include "character.h"
    24 #include "buffer.h"
    25 #include "category.h"
    26 #include "composite.h"
    27 #include "indent.h"
    28 #include "frame.h"
    29 #include "window.h"
    30 #include "disptab.h"
    31 #include "intervals.h"
    32 #include "dispextern.h"
    33 #include "region-cache.h"
    34 
    35 #define CR 015
    36 
    37 /* These three values memorize the current column to avoid recalculation.  */
    38 
    39 /* Last value returned by current_column.
    40    Some things in set last_known_column_point to -1
    41    to mark the memorized value as invalid.  */
    42 
    43 static ptrdiff_t last_known_column;
    44 
    45 /* Value of point when current_column was called.  */
    46 
    47 ptrdiff_t last_known_column_point;
    48 
    49 /* Value of MODIFF when current_column was called.  */
    50 
    51 static modiff_count last_known_column_modified;
    52 
    53 static ptrdiff_t current_column_1 (void);
    54 static ptrdiff_t position_indentation (ptrdiff_t);
    55 
    56 /* Get the display table to use for the current buffer.  */
    57 
    58 struct Lisp_Char_Table *
    59 buffer_display_table (void)
    60 {
    61   Lisp_Object thisbuf;
    62 
    63   thisbuf = BVAR (current_buffer, display_table);
    64   if (DISP_TABLE_P (thisbuf))
    65     return XCHAR_TABLE (thisbuf);
    66   if (DISP_TABLE_P (Vstandard_display_table))
    67     return XCHAR_TABLE (Vstandard_display_table);
    68   return 0;
    69 }
    70 
    71 /* Width run cache considerations.  */
    72 
    73 /* Return the width of character C under display table DP.  */
    74 
    75 static int
    76 character_width (int c, struct Lisp_Char_Table *dp)
    77 {
    78   Lisp_Object elt;
    79 
    80   /* These width computations were determined by examining the cases
    81      in display_text_line.  */
    82 
    83   /* Everything can be handled by the display table, if it's
    84      present and the element is right.  */
    85   if (dp && (elt = DISP_CHAR_VECTOR (dp, c), VECTORP (elt)))
    86     return ASIZE (elt);
    87 
    88   /* Some characters are special.  */
    89   if (c == '\n' || c == '\t' || c == '\015')
    90     return 0;
    91 
    92   /* Printing characters have width 1.  */
    93   else if (c >= 040 && c < 0177)
    94     return 1;
    95 
    96   /* Everybody else (control characters, metacharacters) has other
    97      widths.  We could return their actual widths here, but they
    98      depend on things like ctl_arrow and crud like that, and they're
    99      not very common at all.  So we'll just claim we don't know their
   100      widths.  */
   101   else
   102     return 0;
   103 }
   104 
   105 /* Return true if the display table DISPTAB specifies the same widths
   106    for characters as WIDTHTAB.  We use this to decide when to
   107    invalidate the buffer's width_run_cache.  */
   108 
   109 bool
   110 disptab_matches_widthtab (struct Lisp_Char_Table *disptab, struct Lisp_Vector *widthtab)
   111 {
   112   int i;
   113 
   114   eassert (widthtab->header.size == 256);
   115 
   116   for (i = 0; i < 256; i++)
   117     if (character_width (i, disptab)
   118         != XFIXNAT (widthtab->contents[i]))
   119       return 0;
   120 
   121   return 1;
   122 }
   123 
   124 /* Recompute BUF's width table, using the display table DISPTAB.  */
   125 
   126 void
   127 recompute_width_table (struct buffer *buf, struct Lisp_Char_Table *disptab)
   128 {
   129   int i;
   130   struct Lisp_Vector *widthtab;
   131 
   132   if (!VECTORP (BVAR (buf, width_table)))
   133     bset_width_table (buf, make_uninit_vector (256));
   134   widthtab = XVECTOR (BVAR (buf, width_table));
   135   eassert (widthtab->header.size == 256);
   136 
   137   for (i = 0; i < 256; i++)
   138     XSETFASTINT (widthtab->contents[i], character_width (i, disptab));
   139 }
   140 
   141 /* Allocate or free the width run cache, as requested by the
   142    current state of current_buffer's cache_long_scans variable.  */
   143 
   144 static struct region_cache *
   145 width_run_cache_on_off (void)
   146 {
   147   struct buffer *cache_buffer = current_buffer;
   148   bool indirect_p = false;
   149 
   150   if (cache_buffer->base_buffer)
   151     {
   152       cache_buffer = cache_buffer->base_buffer;
   153       indirect_p = true;
   154     }
   155 
   156   if (NILP (BVAR (current_buffer, cache_long_scans))
   157       /* And, for the moment, this feature doesn't work on multibyte
   158          characters.  */
   159       || !NILP (BVAR (current_buffer, enable_multibyte_characters)))
   160     {
   161       if (!indirect_p
   162           || NILP (BVAR (cache_buffer, cache_long_scans))
   163           || !NILP (BVAR (cache_buffer, enable_multibyte_characters)))
   164         {
   165           /* It should be off.  */
   166           if (cache_buffer->width_run_cache)
   167             {
   168               free_region_cache (cache_buffer->width_run_cache);
   169               cache_buffer->width_run_cache = 0;
   170               bset_width_table (current_buffer, Qnil);
   171             }
   172         }
   173       return NULL;
   174     }
   175   else
   176     {
   177       if (!indirect_p
   178           || (!NILP (BVAR (cache_buffer, cache_long_scans))
   179               && NILP (BVAR (cache_buffer, enable_multibyte_characters))))
   180         {
   181           /* It should be on.  */
   182           if (cache_buffer->width_run_cache == 0)
   183             {
   184               cache_buffer->width_run_cache = new_region_cache ();
   185               recompute_width_table (current_buffer, buffer_display_table ());
   186             }
   187         }
   188       return cache_buffer->width_run_cache;
   189     }
   190 }
   191 
   192 
   193 /* Skip some invisible characters starting from POS.
   194    This includes characters invisible because of text properties
   195    and characters invisible because of overlays.
   196 
   197    If position POS is followed by invisible characters,
   198    skip some of them and return the position after them.
   199    Otherwise return POS itself.
   200 
   201    Set *NEXT_BOUNDARY_P to the next position at which
   202    it will be necessary to call this function again.
   203 
   204    Don't scan past TO, and don't set *NEXT_BOUNDARY_P
   205    to a value greater than TO.
   206 
   207    If WINDOW is non-nil, and this buffer is displayed in WINDOW,
   208    take account of overlays that apply only in WINDOW.
   209 
   210    We don't necessarily skip all the invisible characters after POS
   211    because that could take a long time.  We skip a reasonable number
   212    which can be skipped quickly.  If there might be more invisible
   213    characters immediately following, then *NEXT_BOUNDARY_P
   214    will equal the return value.  */
   215 
   216 ptrdiff_t
   217 skip_invisible (ptrdiff_t pos, ptrdiff_t *next_boundary_p, ptrdiff_t to, Lisp_Object window)
   218 {
   219   Lisp_Object prop, position, overlay_limit, proplimit;
   220   Lisp_Object buffer, tmp;
   221   ptrdiff_t end;
   222   int inv_p;
   223 
   224   XSETFASTINT (position, pos);
   225   XSETBUFFER (buffer, current_buffer);
   226 
   227   /* We must not advance farther than the next overlay change.
   228      The overlay change might change the invisible property;
   229      or there might be overlay strings to be displayed there.  */
   230   overlay_limit = Fnext_overlay_change (position);
   231   /* As for text properties, this gives a lower bound
   232      for where the invisible text property could change.  */
   233   proplimit = Fnext_property_change (position, buffer, Qt);
   234   if (XFIXNAT (overlay_limit) < XFIXNAT (proplimit))
   235     proplimit = overlay_limit;
   236   /* PROPLIMIT is now a lower bound for the next change
   237      in invisible status.  If that is plenty far away,
   238      use that lower bound.  */
   239   if (XFIXNAT (proplimit) > pos + 100 || XFIXNAT (proplimit) >= to)
   240     *next_boundary_p = XFIXNAT (proplimit);
   241   /* Otherwise, scan for the next `invisible' property change.  */
   242   else
   243     {
   244       /* Don't scan terribly far.  */
   245       XSETFASTINT (proplimit, min (pos + 100, to));
   246       /* No matter what, don't go past next overlay change.  */
   247       if (XFIXNAT (overlay_limit) < XFIXNAT (proplimit))
   248         proplimit = overlay_limit;
   249       tmp = Fnext_single_property_change (position, Qinvisible,
   250                                           buffer, proplimit);
   251       end = XFIXNAT (tmp);
   252 #if 0
   253       /* Don't put the boundary in the middle of multibyte form if
   254          there is no actual property change.  */
   255       if (end == pos + 100
   256           && !NILP (current_buffer->enable_multibyte_characters)
   257           && end < ZV)
   258         while (pos < end && !CHAR_HEAD_P (POS_ADDR (end)))
   259           end--;
   260 #endif
   261       *next_boundary_p = end;
   262     }
   263   /* if the `invisible' property is set, we can skip to
   264      the next property change */
   265   prop = Fget_char_property (position, Qinvisible,
   266                              (!NILP (window)
   267                               && EQ (XWINDOW (window)->contents, buffer))
   268                              ? window : buffer);
   269   inv_p = TEXT_PROP_MEANS_INVISIBLE (prop);
   270   /* When counting columns (window == nil), don't skip over ellipsis text.  */
   271   if (NILP (window) ? inv_p == 1 : inv_p)
   272     return *next_boundary_p;
   273   return pos;
   274 }
   275 
   276 /* Set variables WIDTH and BYTES for a multibyte sequence starting at P.
   277 
   278    DP is a display table or NULL.
   279 
   280    This macro is used in scan_for_column and in
   281    compute_motion.  */
   282 
   283 #define MULTIBYTE_BYTES_WIDTH(p, dp, bytes, width)                      \
   284   do {                                                                  \
   285     int ch = string_char_and_length (p, &(bytes));                      \
   286     if (BYTES_BY_CHAR_HEAD (*p) != bytes)                               \
   287       width = bytes * 4;                                                \
   288     else                                                                \
   289       {                                                                 \
   290         if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, ch)))             \
   291           width = sanitize_char_width (ASIZE (DISP_CHAR_VECTOR (dp, ch))); \
   292         else                                                            \
   293           width = CHARACTER_WIDTH (ch);                                 \
   294       }                                                                 \
   295   } while (0)
   296 
   297 
   298 DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
   299        doc: /* Return the horizontal position of point.  Beginning of line is column 0.
   300 This is calculated by adding together the widths of all the displayed
   301 representations of the character between the start of the previous line
   302 and point (e.g., control characters will have a width of 2 or 4, tabs
   303 will have a variable width).
   304 Ignores finite width of frame, which means that this function may return
   305 values greater than (frame-width).
   306 In a buffer with very long lines, the value will be an approximation,
   307 because calculating the exact number is very expensive.
   308 Whether the line is visible (if `selective-display' is t) has no effect;
   309 however, ^M is treated as end of line when `selective-display' is t.
   310 Text that has an invisible property is considered as having width 0, unless
   311 `buffer-invisibility-spec' specifies that it is replaced by an ellipsis.  */)
   312   (void)
   313 {
   314   Lisp_Object temp;
   315 
   316   XSETFASTINT (temp, current_column ());
   317   return temp;
   318 }
   319 
   320 /* Cancel any recorded value of the horizontal position.  */
   321 
   322 void
   323 invalidate_current_column (void)
   324 {
   325   last_known_column_point = 0;
   326 }
   327 
   328 ptrdiff_t
   329 current_column (void)
   330 {
   331   ptrdiff_t col;
   332   unsigned char *ptr, *stop;
   333   bool tab_seen;
   334   ptrdiff_t post_tab;
   335   int c;
   336   int tab_width = SANE_TAB_WIDTH (current_buffer);
   337   bool ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow));
   338   struct Lisp_Char_Table *dp = buffer_display_table ();
   339 
   340   if (PT == last_known_column_point
   341       && MODIFF == last_known_column_modified)
   342     return last_known_column;
   343 
   344   ptrdiff_t line_beg = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1,
   345                                      NULL, NULL, 1);
   346 
   347   /* Avoid becoming abysmally slow for very long lines.  */
   348   if (current_buffer->long_line_optimizations_p
   349       && !NILP (Vlong_line_threshold)
   350       && PT - line_beg > XFIXNUM (Vlong_line_threshold))
   351     return PT - line_beg;       /* this is an approximation! */
   352   /* If the buffer has overlays, text properties,
   353      or multibyte characters, use a more general algorithm.  */
   354   if (buffer_intervals (current_buffer)
   355       || buffer_has_overlays ()
   356       || Z != Z_BYTE)
   357     return current_column_1 ();
   358 
   359   /* Scan backwards from point to the previous newline,
   360      counting width.  Tab characters are the only complicated case.  */
   361 
   362   /* Make a pointer for decrementing through the chars before point.  */
   363   ptr = BYTE_POS_ADDR (PT_BYTE - 1) + 1;
   364   /* Make a pointer to where consecutive chars leave off,
   365      going backwards from point.  */
   366   if (PT == BEGV)
   367     stop = ptr;
   368   else if (PT <= GPT || BEGV > GPT)
   369     stop = BEGV_ADDR;
   370   else
   371     stop = GAP_END_ADDR;
   372 
   373   col = 0, tab_seen = 0, post_tab = 0;
   374 
   375   while (1)
   376     {
   377       ptrdiff_t i, n;
   378       Lisp_Object charvec;
   379 
   380       if (ptr == stop)
   381         {
   382           /* We stopped either for the beginning of the buffer
   383              or for the gap.  */
   384           if (ptr == BEGV_ADDR)
   385             break;
   386 
   387           /* It was the gap.  Jump back over it.  */
   388           stop = BEGV_ADDR;
   389           ptr = GPT_ADDR;
   390 
   391           /* Check whether that brings us to beginning of buffer.  */
   392           if (BEGV >= GPT)
   393             break;
   394         }
   395 
   396       c = *--ptr;
   397 
   398       if (dp && VECTORP (DISP_CHAR_VECTOR (dp, c)))
   399         {
   400           charvec = DISP_CHAR_VECTOR (dp, c);
   401           n = ASIZE (charvec);
   402         }
   403       else
   404         {
   405           charvec = Qnil;
   406           n = 1;
   407         }
   408 
   409       for (i = n - 1; i >= 0; --i)
   410         {
   411           if (VECTORP (charvec))
   412             {
   413               /* This should be handled the same as
   414                  next_element_from_display_vector does it.  */
   415               Lisp_Object entry = AREF (charvec, i);
   416 
   417               if (GLYPH_CODE_P (entry))
   418                 c = GLYPH_CODE_CHAR (entry);
   419               else
   420                 c = ' ';
   421             }
   422 
   423           if (c >= 040 && c < 0177)
   424             col++;
   425           else if (c == '\n'
   426                    || (c == '\r'
   427                        && EQ (BVAR (current_buffer, selective_display), Qt)))
   428             {
   429               ptr++;
   430               goto start_of_line_found;
   431             }
   432           else if (c == '\t')
   433             {
   434               if (tab_seen)
   435                 col = ((col + tab_width) / tab_width) * tab_width;
   436 
   437               post_tab += col;
   438               col = 0;
   439               tab_seen = 1;
   440             }
   441           else if (VECTORP (charvec))
   442             /* With a display table entry, C is displayed as is, and
   443                not displayed as \NNN or as ^N.  If C is a single-byte
   444                character, it takes one column.  If C is multi-byte in
   445                a unibyte buffer, it's translated to unibyte, so it
   446                also takes one column.  */
   447             ++col;
   448           else
   449             col += (ctl_arrow && c < 0200) ? 2 : 4;
   450         }
   451     }
   452 
   453  start_of_line_found:
   454 
   455   if (tab_seen)
   456     {
   457       col = ((col + tab_width) / tab_width) * tab_width;
   458       col += post_tab;
   459     }
   460 
   461   last_known_column = col;
   462   last_known_column_point = PT;
   463   last_known_column_modified = MODIFF;
   464 
   465   return col;
   466 }
   467 
   468 
   469 /* Check the presence of a display property and compute its width.
   470    If a property was found and its width was found as well, return
   471    its width (>= 0) and set the position of the end of the property
   472    in ENDPOS.
   473    Otherwise just return -1.  */
   474 static int
   475 check_display_width (ptrdiff_t pos, ptrdiff_t col, ptrdiff_t *endpos)
   476 {
   477   Lisp_Object val, overlay;
   478 
   479   if (!NILP (val = get_char_property_and_overlay (make_fixnum (pos), Qdisplay,
   480                                                   Qnil, &overlay)))
   481     {
   482       int width = -1;
   483       Lisp_Object plist = Qnil;
   484 
   485       /* Handle '(space ...)' display specs.  */
   486       if (CONSP (val) && EQ (Qspace, XCAR (val)))
   487         { /* FIXME: Use calc_pixel_width_or_height.  */
   488           Lisp_Object prop;
   489           EMACS_INT align_to_max =
   490             (col < MOST_POSITIVE_FIXNUM - INT_MAX
   491              ? (EMACS_INT) INT_MAX + col
   492              : MOST_POSITIVE_FIXNUM);
   493 
   494           plist = XCDR (val);
   495           if ((prop = plist_get (plist, QCwidth),
   496                RANGED_FIXNUMP (0, prop, INT_MAX))
   497               || (prop = plist_get (plist, QCrelative_width),
   498                   RANGED_FIXNUMP (0, prop, INT_MAX)))
   499             width = XFIXNUM (prop);
   500           else if (FLOATP (prop) && 0 <= XFLOAT_DATA (prop)
   501                    && XFLOAT_DATA (prop) <= INT_MAX)
   502             width = (int)(XFLOAT_DATA (prop) + 0.5);
   503           else if ((prop = plist_get (plist, QCalign_to),
   504                     RANGED_FIXNUMP (col, prop, align_to_max)))
   505             width = XFIXNUM (prop) - col;
   506           else if (FLOATP (prop) && col <= XFLOAT_DATA (prop)
   507                    && (XFLOAT_DATA (prop) <= align_to_max))
   508             width = (int)(XFLOAT_DATA (prop) + 0.5) - col;
   509         }
   510       /* Handle 'display' strings.   */
   511       else if (STRINGP (val))
   512         width = XFIXNUM (Fstring_width (val, Qnil, Qnil));
   513 
   514       if (width >= 0)
   515         {
   516           ptrdiff_t start;
   517           if (OVERLAYP (overlay))
   518             *endpos = OVERLAY_END (overlay);
   519           else
   520             get_property_and_range (pos, Qdisplay, &val, &start, endpos, Qnil);
   521 
   522           /* For :relative-width, we need to multiply by the column
   523              width of the character at POS, if it is greater than 1.  */
   524           if (!NILP (plist)
   525               && !NILP (plist_get (plist, QCrelative_width))
   526               && !NILP (BVAR (current_buffer, enable_multibyte_characters)))
   527             {
   528               int b, wd;
   529               unsigned char *p = BYTE_POS_ADDR (CHAR_TO_BYTE (pos));
   530 
   531               MULTIBYTE_BYTES_WIDTH (p, buffer_display_table (), b, wd);
   532               width *= wd;
   533             }
   534           return width;
   535         }
   536     }
   537 
   538   return -1;
   539 }
   540 
   541 /* Scanning from the beginning of the current line, stop at the buffer
   542    position ENDPOS or at the column GOALCOL or at the end of line, whichever
   543    comes first.
   544    Return the resulting buffer position and column in ENDPOS and GOALCOL.
   545    PREVCOL gets set to the column of the previous position (it's always
   546    strictly smaller than the goal column), and PREVPOS and PREVBPOS get set
   547    to the corresponding buffer character and byte positions.  */
   548 static void
   549 scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol,
   550                  ptrdiff_t *prevpos, ptrdiff_t *prevbpos, ptrdiff_t *prevcol)
   551 {
   552   int tab_width = SANE_TAB_WIDTH (current_buffer);
   553   bool ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow));
   554   struct Lisp_Char_Table *dp = buffer_display_table ();
   555   bool multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters));
   556   struct composition_it cmp_it;
   557   Lisp_Object window;
   558   struct window *w;
   559 
   560   /* Start the scan at the beginning of this line with column number 0.  */
   561   register ptrdiff_t col = 0, prev_col = 0;
   562   EMACS_INT goal = goalcol ? *goalcol : MOST_POSITIVE_FIXNUM;
   563   ptrdiff_t end = endpos ? *endpos : PT;
   564   ptrdiff_t scan, scan_byte, next_boundary, prev_pos, prev_bpos;
   565 
   566   scan = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &scan_byte, 1);
   567 
   568   window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
   569   w = ! NILP (window) ? XWINDOW (window) : NULL;
   570 
   571   if (current_buffer->long_line_optimizations_p)
   572     {
   573       bool lines_truncated = false;
   574 
   575       if (!NILP (BVAR (current_buffer, truncate_lines)))
   576         lines_truncated = true;
   577       else if (!NILP (Vtruncate_partial_width_windows) && w
   578                && w->total_cols < FRAME_COLS (XFRAME (WINDOW_FRAME (w))))
   579         {
   580           if (FIXNUMP (Vtruncate_partial_width_windows))
   581             lines_truncated =
   582               w->total_cols < XFIXNAT (Vtruncate_partial_width_windows);
   583           else
   584             lines_truncated = true;
   585         }
   586       /* Special optimization for buffers with long and truncated
   587          lines: assumes that each character is a single column.  */
   588       if (lines_truncated)
   589         {
   590           ptrdiff_t bolpos = scan;
   591           /* The newline which ends this line or ZV.  */
   592           ptrdiff_t eolpos =
   593             find_newline (PT, PT_BYTE, ZV, ZV_BYTE, 1, NULL, NULL, 1);
   594 
   595           scan = bolpos + goal;
   596           if (scan > end)
   597             scan = end;
   598           if (scan > eolpos)
   599             scan = (eolpos == ZV ? ZV : eolpos - 1);
   600           col = scan - bolpos;
   601           if (col > large_hscroll_threshold)
   602             {
   603               prev_col = col - 1;
   604               prev_pos = scan - 1;
   605               prev_bpos = CHAR_TO_BYTE (scan);
   606               goto endloop;
   607             }
   608           /* Restore the values we've overwritten above.  */
   609           scan = bolpos;
   610           col = 0;
   611         }
   612     }
   613   next_boundary = scan;
   614   prev_pos = scan;
   615   prev_bpos = scan_byte;
   616 
   617   memset (&cmp_it, 0, sizeof cmp_it);
   618   cmp_it.id = -1;
   619   composition_compute_stop_pos (&cmp_it, scan, scan_byte, end, Qnil, true);
   620 
   621   /* Scan forward to the target position.  */
   622   while (scan < end)
   623     {
   624       int c;
   625 
   626       /* Occasionally we may need to skip invisible text.  */
   627       while (scan == next_boundary)
   628         {
   629           ptrdiff_t old_scan = scan;
   630           /* This updates NEXT_BOUNDARY to the next place
   631              where we might need to skip more invisible text.  */
   632           scan = skip_invisible (scan, &next_boundary, end, Qnil);
   633           if (scan != old_scan)
   634             scan_byte = CHAR_TO_BYTE (scan);
   635           if (scan >= end)
   636             goto endloop;
   637           /* We may have over-stepped cmp_it.stop_pos while skipping
   638              the invisible text.  If so, update cmp_it.stop_pos.  */
   639           if (scan > cmp_it.stop_pos && cmp_it.id < 0)
   640             composition_reseat_it (&cmp_it, scan, scan_byte, end,
   641                                    w, -1, NULL, Qnil);
   642         }
   643 
   644       /* Test reaching the goal column.  We do this after skipping
   645          invisible characters, so that we put point before the
   646          character on which the cursor will appear.  */
   647       if (col >= goal)
   648         break;
   649       prev_col = col;
   650       prev_pos = scan;
   651       prev_bpos = scan_byte;
   652 
   653       { /* Check display property.  */
   654         ptrdiff_t endp;
   655         int width = check_display_width (scan, col, &endp);
   656         if (width >= 0)
   657           {
   658             col += width;
   659             if (endp > scan) /* Avoid infinite loops with 0-width overlays.  */
   660               {
   661                 scan = endp;
   662                 scan_byte = CHAR_TO_BYTE (scan);
   663                 continue;
   664               }
   665           }
   666       }
   667 
   668       /* Check composition sequence.  */
   669       if (cmp_it.id >= 0
   670           || (scan == cmp_it.stop_pos
   671               && composition_reseat_it (&cmp_it, scan, scan_byte, end,
   672                                         w, -1, NULL, Qnil)))
   673         composition_update_it (&cmp_it, scan, scan_byte, Qnil);
   674       if (cmp_it.id >= 0)
   675         {
   676           scan += cmp_it.nchars;
   677           scan_byte += cmp_it.nbytes;
   678           if (scan <= end)
   679             col += cmp_it.width;
   680           if (cmp_it.to == cmp_it.nglyphs)
   681             {
   682               cmp_it.id = -1;
   683               composition_compute_stop_pos (&cmp_it, scan, scan_byte, end,
   684                                             Qnil, true);
   685             }
   686           else
   687             cmp_it.from = cmp_it.to;
   688           continue;
   689         }
   690 
   691       c = FETCH_BYTE (scan_byte);
   692 
   693       /* See if there is a display table and it relates
   694          to this character.  */
   695 
   696       if (dp != 0
   697           && ! (multibyte && LEADING_CODE_P (c))
   698           && VECTORP (DISP_CHAR_VECTOR (dp, c)))
   699         {
   700           Lisp_Object charvec;
   701           ptrdiff_t i, n;
   702 
   703           /* This character is displayed using a vector of glyphs.
   704              Update the column/position based on those glyphs.  */
   705 
   706           charvec = DISP_CHAR_VECTOR (dp, c);
   707           n = ASIZE (charvec);
   708 
   709           for (i = 0; i < n; i++)
   710             {
   711               /* This should be handled the same as
   712                  next_element_from_display_vector does it.  */
   713               Lisp_Object entry = AREF (charvec, i);
   714 
   715               if (GLYPH_CODE_P (entry))
   716                 c = GLYPH_CODE_CHAR (entry);
   717               else
   718                 c = ' ';
   719 
   720               if (c == '\n')
   721                 goto endloop;
   722               if (c == '\r' && EQ (BVAR (current_buffer, selective_display), Qt))
   723                 goto endloop;
   724               if (c == '\t')
   725                 {
   726                   col += tab_width;
   727                   col = col / tab_width * tab_width;
   728                 }
   729               else
   730                 ++col;
   731             }
   732         }
   733       else
   734         {
   735           /* The display table doesn't affect this character;
   736              it displays as itself.  */
   737 
   738           if (c == '\n')
   739             goto endloop;
   740           if (c == '\r' && EQ (BVAR (current_buffer, selective_display), Qt))
   741             goto endloop;
   742           if (c == '\t')
   743             {
   744               col += tab_width;
   745               col = col / tab_width * tab_width;
   746             }
   747           else if (multibyte && LEADING_CODE_P (c))
   748             {
   749               /* Start of multi-byte form.  */
   750               unsigned char *ptr;
   751               int bytes, width;
   752 
   753               ptr = BYTE_POS_ADDR (scan_byte);
   754               MULTIBYTE_BYTES_WIDTH (ptr, dp, bytes, width);
   755               /* Subtract one to compensate for the increment
   756                  that is going to happen below.  */
   757               scan_byte += bytes - 1;
   758               col += width;
   759             }
   760           else if (ctl_arrow && (c < 040 || c == 0177))
   761             col += 2;
   762           else if (c < 040 || c >= 0177)
   763             col += 4;
   764           else
   765             col++;
   766         }
   767       scan++;
   768       scan_byte++;
   769 
   770     }
   771  endloop:
   772 
   773   last_known_column = col;
   774   last_known_column_point = PT;
   775   last_known_column_modified = MODIFF;
   776 
   777   if (goalcol)
   778     *goalcol = col;
   779   if (endpos)
   780     *endpos = scan;
   781   if (prevpos)
   782     *prevpos = prev_pos;
   783   if (prevbpos)
   784     *prevbpos = prev_bpos;
   785   if (prevcol)
   786     *prevcol = prev_col;
   787 }
   788 
   789 /* Return the column number of point
   790    by scanning forward from the beginning of the line.
   791    This function handles characters that are invisible
   792    due to text properties or overlays.  */
   793 
   794 static ptrdiff_t
   795 current_column_1 (void)
   796 {
   797   EMACS_INT col = MOST_POSITIVE_FIXNUM;
   798   ptrdiff_t opoint = PT;
   799 
   800   scan_for_column (&opoint, &col, NULL, NULL, NULL);
   801   return col;
   802 }
   803 
   804 
   805 #if 0 /* Not used.  */
   806 
   807 /* Return the width in columns of the part of STRING from BEG to END.
   808    If BEG is nil, that stands for the beginning of STRING.
   809    If END is nil, that stands for the end of STRING.  */
   810 
   811 static double
   812 string_display_width (Lisp_Object string, Lisp_Object beg, Lisp_Object end)
   813 {
   814   int col;
   815   unsigned char *ptr, *stop;
   816   bool tab_seen;
   817   int post_tab;
   818   int c;
   819   int tab_width = SANE_TAB_WIDTH (current_buffer);
   820   bool ctl_arrow = !NILP (current_buffer->ctl_arrow);
   821   struct Lisp_Char_Table *dp = buffer_display_table ();
   822   int b, e;
   823 
   824   if (NILP (end))
   825     e = SCHARS (string);
   826   else
   827     {
   828       CHECK_FIXNUM (end);
   829       e = XFIXNUM (end);
   830     }
   831 
   832   if (NILP (beg))
   833     b = 0;
   834   else
   835     {
   836       CHECK_FIXNUM (beg);
   837       b = XFIXNUM (beg);
   838     }
   839 
   840   /* Make a pointer for decrementing through the chars before point.  */
   841   ptr = SDATA (string) + e;
   842   /* Make a pointer to where consecutive chars leave off,
   843      going backwards from point.  */
   844   stop = SDATA (string) + b;
   845 
   846   col = 0, tab_seen = 0, post_tab = 0;
   847 
   848   while (1)
   849     {
   850       if (ptr == stop)
   851         break;
   852 
   853       c = *--ptr;
   854       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
   855         col += ASIZE (DISP_CHAR_VECTOR (dp, c));
   856       else if (c >= 040 && c < 0177)
   857         col++;
   858       else if (c == '\n')
   859         break;
   860       else if (c == '\t')
   861         {
   862           if (tab_seen)
   863             col = ((col + tab_width) / tab_width) * tab_width;
   864 
   865           post_tab += col;
   866           col = 0;
   867           tab_seen = 1;
   868         }
   869       else
   870         col += (ctl_arrow && c < 0200) ? 2 : 4;
   871     }
   872 
   873   if (tab_seen)
   874     {
   875       col = ((col + tab_width) / tab_width) * tab_width;
   876       col += post_tab;
   877     }
   878 
   879   return col;
   880 }
   881 
   882 #endif /* 0 */
   883 
   884 
   885 DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
   886        doc: /* Indent from point with tabs and spaces until COLUMN is reached.
   887 Optional second argument MINIMUM says always do at least MINIMUM spaces
   888 even if that goes past COLUMN; by default, MINIMUM is zero.
   889 
   890 Whether this uses tabs or spaces depends on `indent-tabs-mode'.
   891 
   892 The return value is the column where the insertion ends.  */)
   893   (Lisp_Object column, Lisp_Object minimum)
   894 {
   895   EMACS_INT mincol;
   896   register ptrdiff_t fromcol;
   897   int tab_width = SANE_TAB_WIDTH (current_buffer);
   898 
   899   CHECK_FIXNUM (column);
   900   if (NILP (minimum))
   901     XSETFASTINT (minimum, 0);
   902   CHECK_FIXNUM (minimum);
   903 
   904   fromcol = current_column ();
   905   mincol = fromcol + XFIXNUM (minimum);
   906   if (mincol < XFIXNUM (column)) mincol = XFIXNUM (column);
   907 
   908   if (fromcol == mincol)
   909     return make_fixnum (mincol);
   910 
   911   if (indent_tabs_mode)
   912     {
   913       Lisp_Object n;
   914       XSETFASTINT (n, mincol / tab_width - fromcol / tab_width);
   915       if (XFIXNAT (n) != 0)
   916         {
   917           Finsert_char (make_fixnum ('\t'), n, Qt);
   918 
   919           fromcol = (mincol / tab_width) * tab_width;
   920         }
   921     }
   922 
   923   XSETFASTINT (column, mincol - fromcol);
   924   Finsert_char (make_fixnum (' '), column, Qt);
   925 
   926   last_known_column = mincol;
   927   last_known_column_point = PT;
   928   last_known_column_modified = MODIFF;
   929 
   930   XSETINT (column, mincol);
   931   return column;
   932 }
   933 
   934 
   935 DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
   936        0, 0, 0,
   937        doc: /* Return the indentation of the current line.
   938 This is the horizontal position of the character following any initial
   939 whitespace.
   940 Text that has an invisible property is considered as having width 0, unless
   941 `buffer-invisibility-spec' specifies that it is replaced by an ellipsis.  */)
   942   (void)
   943 {
   944   ptrdiff_t posbyte;
   945 
   946   find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &posbyte, 1);
   947   return make_fixnum (position_indentation (posbyte));
   948 }
   949 
   950 static ptrdiff_t
   951 position_indentation (ptrdiff_t pos_byte)
   952 {
   953   register ptrdiff_t column = 0;
   954   int tab_width = SANE_TAB_WIDTH (current_buffer);
   955   register unsigned char *p;
   956   register unsigned char *stop;
   957   unsigned char *start;
   958   ptrdiff_t next_boundary_byte = pos_byte;
   959   ptrdiff_t ceiling = next_boundary_byte;
   960 
   961   p = BYTE_POS_ADDR (pos_byte);
   962   /* STOP records the value of P at which we will need
   963      to think about the gap, or about invisible text,
   964      or about the end of the buffer.  */
   965   stop = p;
   966   /* START records the starting value of P.  */
   967   start = p;
   968   while (1)
   969     {
   970       while (p == stop)
   971         {
   972           ptrdiff_t stop_pos_byte;
   973 
   974           /* If we have updated P, set POS_BYTE to match.
   975              The first time we enter the loop, POS_BYTE is already right.  */
   976           if (p != start)
   977             pos_byte = PTR_BYTE_POS (p);
   978           /* Consider the various reasons STOP might have been set here.  */
   979           if (pos_byte == ZV_BYTE)
   980             return column;
   981           if (pos_byte == next_boundary_byte)
   982             {
   983               ptrdiff_t next_boundary;
   984               ptrdiff_t pos = BYTE_TO_CHAR (pos_byte);
   985               pos = skip_invisible (pos, &next_boundary, ZV, Qnil);
   986               pos_byte = CHAR_TO_BYTE (pos);
   987               next_boundary_byte = CHAR_TO_BYTE (next_boundary);
   988             }
   989           if (pos_byte >= ceiling)
   990             ceiling = BUFFER_CEILING_OF (pos_byte) + 1;
   991           /* Compute the next place we need to stop and think,
   992              and set STOP accordingly.  */
   993           stop_pos_byte = min (ceiling, next_boundary_byte);
   994           /* The -1 and +1 arrange to point at the first byte of gap
   995              (if STOP_POS_BYTE is the position of the gap)
   996              rather than at the data after the gap.  */
   997 
   998           stop = BYTE_POS_ADDR (stop_pos_byte - 1) + 1;
   999           p = BYTE_POS_ADDR (pos_byte);
  1000         }
  1001       switch (*p++)
  1002         {
  1003         case 0240:
  1004           if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
  1005             return column;
  1006           FALLTHROUGH;
  1007         case ' ':
  1008           column++;
  1009           break;
  1010         case '\t':
  1011           column += tab_width - column % tab_width;
  1012           break;
  1013         default:
  1014           if (ASCII_CHAR_P (p[-1])
  1015               || NILP (BVAR (current_buffer, enable_multibyte_characters)))
  1016             return column;
  1017           {
  1018             int c;
  1019             pos_byte = PTR_BYTE_POS (p - 1);
  1020             c = FETCH_MULTIBYTE_CHAR (pos_byte);
  1021             if (CHAR_HAS_CATEGORY (c, ' '))
  1022               {
  1023                 column++;
  1024                 pos_byte += next_char_len (pos_byte);
  1025                 p = BYTE_POS_ADDR (pos_byte);
  1026               }
  1027             else
  1028               return column;
  1029           }
  1030         }
  1031     }
  1032 }
  1033 
  1034 /* Test whether the line beginning at POS is indented beyond COLUMN.
  1035    Blank lines are treated as if they had the same indentation as the
  1036    preceding line.  */
  1037 
  1038 bool
  1039 indented_beyond_p (ptrdiff_t pos, ptrdiff_t pos_byte, EMACS_INT column)
  1040 {
  1041   while (pos > BEGV && FETCH_BYTE (pos_byte) == '\n')
  1042     {
  1043       dec_both (&pos, &pos_byte);
  1044       pos = find_newline (pos, pos_byte, BEGV, BEGV_BYTE,
  1045                           -1, NULL, &pos_byte, 0);
  1046     }
  1047   return position_indentation (pos_byte) >= column;
  1048 }
  1049 
  1050 DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2,
  1051        "NMove to column: ",
  1052        doc: /* Move point to column COLUMN in the current line.
  1053 Interactively, COLUMN is the value of prefix numeric argument.
  1054 The column of a character is calculated by adding together the widths
  1055 as displayed of the previous characters in the line.
  1056 This function ignores line-continuation;
  1057 there is no upper limit on the column number a character can have
  1058 and horizontal scrolling has no effect.
  1059 Text that has an invisible property is considered as having width 0,
  1060 unless `buffer-invisibility-spec' specifies that it is replaced by
  1061 an ellipsis.
  1062 
  1063 If specified column is within a character, point goes after that character.
  1064 If it's past end of line, point goes to end of line.
  1065 
  1066 Optional second argument FORCE non-nil means if COLUMN is in the
  1067 middle of a tab character, either change it to spaces (when
  1068 `indent-tabs-mode' is nil), or insert enough spaces before it to reach
  1069 COLUMN (otherwise).  In addition, if FORCE is t, and the line is too short
  1070 to reach COLUMN, add spaces/tabs to get there.
  1071 
  1072 The return value is the current column.  */)
  1073   (Lisp_Object column, Lisp_Object force)
  1074 {
  1075   ptrdiff_t pos, prev_pos, prev_bpos, prev_col;
  1076   EMACS_INT col;
  1077   EMACS_INT goal;
  1078 
  1079   CHECK_FIXNAT (column);
  1080   goal = XFIXNUM (column);
  1081 
  1082   col = goal;
  1083   pos = ZV;
  1084   scan_for_column (&pos, &col, &prev_pos, &prev_bpos, &prev_col);
  1085 
  1086   SET_PT (pos);
  1087 
  1088   /* If a tab char made us overshoot, change it to spaces
  1089      and scan through it again.  */
  1090   if (!NILP (force) && col > goal)
  1091     {
  1092       int c;
  1093 
  1094       c = FETCH_CHAR (prev_bpos);
  1095       if (c == '\t' && prev_col < goal && prev_bpos < PT_BYTE)
  1096         {
  1097           ptrdiff_t goal_pt, goal_pt_byte;
  1098 
  1099           /* Insert spaces in front of the tab to reach GOAL.  Do this
  1100              first so that a marker at the end of the tab gets
  1101              adjusted.  */
  1102           SET_PT_BOTH (prev_pos, prev_bpos);
  1103           Finsert_char (make_fixnum (' '), make_fixnum (goal - prev_col), Qt);
  1104 
  1105           /* Now delete the tab, and indent to COL.  */
  1106           del_range (PT, PT + 1);
  1107           goal_pt = PT;
  1108           goal_pt_byte = PT_BYTE;
  1109           Findent_to (make_fixnum (col), Qnil);
  1110           SET_PT_BOTH (goal_pt, goal_pt_byte);
  1111 
  1112           /* Set the last_known... vars consistently.  */
  1113           col = goal;
  1114         }
  1115     }
  1116 
  1117   /* If line ends prematurely, add space to the end.  */
  1118   if (col < goal && EQ (force, Qt))
  1119     Findent_to (make_fixnum (col = goal), Qnil);
  1120 
  1121   last_known_column = col;
  1122   last_known_column_point = PT;
  1123   last_known_column_modified = MODIFF;
  1124 
  1125   return make_fixnum (col);
  1126 }
  1127 
  1128 /* compute_motion: compute buffer posn given screen posn and vice versa */
  1129 
  1130 static struct position val_compute_motion;
  1131 
  1132 /* Scan the current buffer forward from offset FROM, pretending that
  1133    this is at line FROMVPOS, column FROMHPOS, until reaching buffer
  1134    offset TO or line TOVPOS, column TOHPOS (whichever comes first),
  1135    and return the ending buffer position and screen location.  If we
  1136    can't hit the requested column exactly (because of a tab or other
  1137    multi-column character), overshoot.
  1138 
  1139    DID_MOTION is true if FROMHPOS has already accounted for overlay strings
  1140    at FROM.  This is the case if FROMVPOS and FROMVPOS came from an
  1141    earlier call to compute_motion.  The other common case is that FROMHPOS
  1142    is zero and FROM is a position that "belongs" at column zero, but might
  1143    be shifted by overlay strings; in this case DID_MOTION should be false.
  1144 
  1145    WIDTH is the number of columns available to display text;
  1146    compute_motion uses this to handle continuation lines and such.
  1147    If WIDTH is -1, use width of window's text area adjusted for
  1148    continuation glyph when needed.
  1149 
  1150    HSCROLL is the number of columns not being displayed at the left
  1151    margin; this is usually taken from a window's hscroll member.
  1152    TAB_OFFSET is the number of columns of the first tab that aren't
  1153    being displayed, perhaps because of a continuation line or
  1154    something.
  1155 
  1156    compute_motion returns a pointer to a struct position.  The bufpos
  1157    member gives the buffer position at the end of the scan, and hpos
  1158    and vpos give its cartesian location.  prevhpos is the column at
  1159    which the character before bufpos started, and contin is non-zero
  1160    if we reached the current line by continuing the previous.
  1161 
  1162    Note that FROMHPOS and TOHPOS should be expressed in real screen
  1163    columns, taking HSCROLL and the truncation glyph at the left margin
  1164    into account.  That is, beginning-of-line moves you to the hpos
  1165    -HSCROLL + (HSCROLL > 0).
  1166 
  1167    For example, to find the buffer position of column COL of line LINE
  1168    of a certain window, pass the window's starting location as FROM
  1169    and the window's upper-left coordinates as FROMVPOS and FROMHPOS.
  1170    Pass the buffer's ZV as TO, to limit the scan to the end of the
  1171    visible section of the buffer, and pass LINE and COL as TOVPOS and
  1172    TOHPOS.
  1173 
  1174    When displaying in window w, a typical formula for WIDTH is:
  1175 
  1176         window_width - 1
  1177          - (has_vertical_scroll_bars
  1178             ? WINDOW_CONFIG_SCROLL_BAR_COLS (window)
  1179             : (window_width + window_left != frame_cols))
  1180 
  1181         where
  1182           window_width is w->total_cols,
  1183           window_left is w->left_col,
  1184           has_vertical_scroll_bars is
  1185             WINDOW_HAS_VERTICAL_SCROLL_BAR (window)
  1186           and frame_cols = FRAME_COLS (XFRAME (window->frame))
  1187 
  1188    Or you can let window_body_cols do this all for you, and write:
  1189         window_body_cols (w) - 1
  1190 
  1191    The `-1' accounts for the continuation-line backslashes; the rest
  1192    accounts for window borders if the window is split horizontally, and
  1193    the scroll bars if they are turned on.  */
  1194 
  1195 struct position *
  1196 compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos,
  1197                 EMACS_INT fromhpos, bool did_motion, ptrdiff_t to,
  1198                 EMACS_INT tovpos, EMACS_INT tohpos, EMACS_INT width,
  1199                 ptrdiff_t hscroll, int tab_offset, struct window *win)
  1200 {
  1201   EMACS_INT hpos = fromhpos;
  1202   EMACS_INT vpos = fromvpos;
  1203 
  1204   ptrdiff_t pos;
  1205   ptrdiff_t pos_byte;
  1206   int c = 0;
  1207   int tab_width = SANE_TAB_WIDTH (current_buffer);
  1208   bool ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow));
  1209   struct Lisp_Char_Table *dp = window_display_table (win);
  1210   EMACS_INT selective
  1211     = (FIXNUMP (BVAR (current_buffer, selective_display))
  1212        ? XFIXNUM (BVAR (current_buffer, selective_display))
  1213        : !NILP (BVAR (current_buffer, selective_display)) ? -1 : 0);
  1214   ptrdiff_t selective_rlen
  1215     = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
  1216        ? ASIZE (DISP_INVIS_VECTOR (dp)) : 0);
  1217   /* The next location where the `invisible' property changes, or an
  1218      overlay starts or ends.  */
  1219   ptrdiff_t next_boundary = from;
  1220 
  1221   /* For computing runs of characters with similar widths.
  1222      Invariant: width_run_width is zero, or all the characters
  1223      from width_run_start to width_run_end have a fixed width of
  1224      width_run_width.  */
  1225   ptrdiff_t width_run_start = from;
  1226   ptrdiff_t width_run_end   = from;
  1227   ptrdiff_t width_run_width = 0;
  1228   Lisp_Object *width_table;
  1229 
  1230   /* The next buffer pos where we should consult the width run cache. */
  1231   ptrdiff_t next_width_run = from;
  1232   Lisp_Object window;
  1233 
  1234   bool multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters));
  1235   /* If previous char scanned was a wide character,
  1236      this is the column where it ended.  Otherwise, this is 0.  */
  1237   EMACS_INT wide_column_end_hpos = 0;
  1238   ptrdiff_t prev_pos;           /* Previous buffer position.  */
  1239   ptrdiff_t prev_pos_byte;      /* Previous buffer position.  */
  1240   EMACS_INT prev_hpos = 0;
  1241   EMACS_INT prev_vpos = 0;
  1242   EMACS_INT contin_hpos;        /* HPOS of last column of continued line.  */
  1243   int prev_tab_offset;          /* Previous tab offset.  */
  1244   int continuation_glyph_width;
  1245   struct buffer *cache_buffer = current_buffer;
  1246   struct region_cache *width_cache = NULL;
  1247 
  1248   struct composition_it cmp_it;
  1249 
  1250   XSETWINDOW (window, win);
  1251 
  1252   if (cache_buffer->base_buffer)
  1253     cache_buffer = cache_buffer->base_buffer;
  1254   if (dp == buffer_display_table ())
  1255     {
  1256       width_table = (VECTORP (BVAR (current_buffer, width_table))
  1257                      ? XVECTOR (BVAR (current_buffer, width_table))->contents
  1258                      : 0);
  1259       if (width_table)
  1260         width_cache = width_run_cache_on_off ();
  1261     }
  1262   else
  1263     /* If the window has its own display table, we can't use the width
  1264        run cache, because that's based on the buffer's display table.  */
  1265     width_table = 0;
  1266 
  1267   /* Negative width means use all available text columns.  */
  1268   if (width < 0)
  1269     {
  1270       width = window_body_width (win, WINDOW_BODY_IN_CANONICAL_CHARS);
  1271       /* We must make room for continuation marks if we don't have fringes.  */
  1272 #ifdef HAVE_WINDOW_SYSTEM
  1273       if (!FRAME_WINDOW_P (XFRAME (win->frame)))
  1274 #endif
  1275         width -= 1;
  1276     }
  1277 
  1278   continuation_glyph_width = 1;
  1279 #ifdef HAVE_WINDOW_SYSTEM
  1280   if (FRAME_WINDOW_P (XFRAME (win->frame)))
  1281     continuation_glyph_width = 0;  /* In the fringe.  */
  1282 #endif
  1283 
  1284   /* It's just impossible to be too paranoid here.  */
  1285   eassert (from == BYTE_TO_CHAR (frombyte) && frombyte == CHAR_TO_BYTE (from));
  1286 
  1287   pos = prev_pos = from;
  1288   pos_byte = prev_pos_byte = frombyte;
  1289   contin_hpos = 0;
  1290   prev_tab_offset = tab_offset;
  1291   memset (&cmp_it, 0, sizeof cmp_it);
  1292   cmp_it.id = -1;
  1293   composition_compute_stop_pos (&cmp_it, pos, pos_byte, to, Qnil, true);
  1294 
  1295   unsigned short int quit_count = 0;
  1296 
  1297   while (true)
  1298     {
  1299       rarely_quit (++quit_count);
  1300 
  1301       while (pos == next_boundary)
  1302         {
  1303           ptrdiff_t pos_here = pos;
  1304           ptrdiff_t newpos;
  1305 
  1306           /* Don't skip invisible if we are already at the margin.  */
  1307           if (vpos > tovpos || (vpos == tovpos && hpos >= tohpos))
  1308             {
  1309               if (contin_hpos && prev_hpos == 0
  1310                   && hpos > tohpos
  1311                   && (contin_hpos == width || wide_column_end_hpos > width))
  1312                 { /* Line breaks because we can't put the character at the
  1313                      previous line any more.  It is not the multi-column
  1314                      character continued in middle.  Go back to previous
  1315                      buffer position, screen position, and set tab offset
  1316                      to previous value.  It's the beginning of the
  1317                      line.  */
  1318                   pos = prev_pos;
  1319                   pos_byte = prev_pos_byte;
  1320                   hpos = prev_hpos;
  1321                   vpos = prev_vpos;
  1322                   tab_offset = prev_tab_offset;
  1323                 }
  1324               break;
  1325             }
  1326 
  1327           /* If the caller says that the screen position came from an earlier
  1328              call to compute_motion, then we've already accounted for the
  1329              overlay strings at point.  This is only true the first time
  1330              through, so clear the flag after testing it.  */
  1331           if (!did_motion)
  1332             /* We need to skip past the overlay strings.  Currently those
  1333                strings must not contain TAB;
  1334                if we want to relax that restriction, something will have
  1335                to be changed here.  */
  1336             {
  1337               unsigned char *ovstr;
  1338               ptrdiff_t ovlen = overlay_strings (pos, win, &ovstr);
  1339               hpos += ((multibyte && ovlen > 0)
  1340                        ? strwidth ((char *) ovstr, ovlen) : ovlen);
  1341             }
  1342           did_motion = 0;
  1343 
  1344           if (pos >= to)
  1345             break;
  1346 
  1347           /* Advance POS past invisible characters
  1348              (but not necessarily all that there are here),
  1349              and store in next_boundary the next position where
  1350              we need to call skip_invisible.  */
  1351           newpos = skip_invisible (pos, &next_boundary, to, window);
  1352 
  1353           if (newpos >= to)
  1354             {
  1355               pos = min (to, newpos);
  1356               pos_byte = CHAR_TO_BYTE (pos);
  1357               goto after_loop;
  1358             }
  1359 
  1360           if (newpos != pos_here)
  1361             {
  1362               pos = newpos;
  1363               pos_byte = CHAR_TO_BYTE (pos);
  1364             }
  1365           if (newpos > cmp_it.stop_pos && cmp_it.id < 0)
  1366             composition_reseat_it (&cmp_it, pos, pos_byte, to,
  1367                                    win, -1, NULL, Qnil);
  1368 
  1369           rarely_quit (++quit_count);
  1370         }
  1371 
  1372       /* Handle right margin.  */
  1373       /* Note on a wide-column character.
  1374 
  1375          Characters are classified into the following three categories
  1376          according to the width (columns occupied on screen).
  1377 
  1378          (1) single-column character: ex. `a'
  1379          (2) multi-column character: ex. `^A', TAB, `\033'
  1380          (3) wide-column character: ex. Japanese character, Chinese character
  1381              (In the following example, `W_' stands for them.)
  1382 
  1383          Multi-column characters can be divided around the right margin,
  1384          but wide-column characters cannot.
  1385 
  1386          NOTE:
  1387 
  1388          (*) The cursor is placed on the next character after the point.
  1389 
  1390              ----------
  1391              abcdefghi\
  1392              j        ^---- next after the point
  1393              ^---  next char. after the point.
  1394              ----------
  1395                       In case of single-column character
  1396 
  1397              ----------
  1398              abcdefgh\\
  1399              033     ^----  next after the point, next char. after the point.
  1400              ----------
  1401                       In case of multi-column character
  1402 
  1403              ----------
  1404              abcdefgh\\
  1405              W_      ^---- next after the point
  1406              ^----  next char. after the point.
  1407              ----------
  1408                       In case of wide-column character
  1409 
  1410          The problem here is continuation at a wide-column character.
  1411          In this case, the line may shorter less than WIDTH.
  1412          And we find the continuation AFTER it occurs.
  1413 
  1414        */
  1415 
  1416       if (hpos > width)
  1417         {
  1418           EMACS_INT total_width = width + continuation_glyph_width;
  1419           bool truncate = 0;
  1420 
  1421           if (!NILP (Vtruncate_partial_width_windows)
  1422               && (total_width < FRAME_COLS (XFRAME (WINDOW_FRAME (win)))))
  1423             {
  1424               if (FIXNUMP (Vtruncate_partial_width_windows))
  1425                 truncate
  1426                   = total_width < XFIXNAT (Vtruncate_partial_width_windows);
  1427               else
  1428                 truncate = 1;
  1429             }
  1430 
  1431           if (hscroll || truncate
  1432               || !NILP (BVAR (current_buffer, truncate_lines)))
  1433             {
  1434               /* Truncating: skip to newline, unless we are already past
  1435                  TO (we need to go back below).  */
  1436               if (pos <= to)
  1437                 {
  1438                   pos = find_before_next_newline (pos, to, 1, &pos_byte);
  1439                   hpos = width;
  1440                   /* If we just skipped next_boundary,
  1441                      loop around in the main while
  1442                      and handle it.  */
  1443                   if (pos >= next_boundary)
  1444                     next_boundary = pos + 1;
  1445                   prev_hpos = width;
  1446                   prev_vpos = vpos;
  1447                   prev_tab_offset = tab_offset;
  1448                 }
  1449             }
  1450           else
  1451             {
  1452               /* Continuing.  */
  1453               /* Remember the previous value.  */
  1454               prev_tab_offset = tab_offset;
  1455 
  1456               if (wide_column_end_hpos > width)
  1457                 {
  1458                   hpos -= prev_hpos;
  1459                   tab_offset += prev_hpos;
  1460                 }
  1461               else
  1462                 {
  1463                   tab_offset += width;
  1464                   hpos -= width;
  1465                 }
  1466               vpos++;
  1467               contin_hpos = prev_hpos;
  1468               prev_hpos = 0;
  1469               prev_vpos = vpos;
  1470             }
  1471         }
  1472 
  1473       /* Stop if past the target buffer position or screen position.  */
  1474       if (pos > to)
  1475         {
  1476           /* Go back to the previous position.  */
  1477           pos = prev_pos;
  1478           pos_byte = prev_pos_byte;
  1479           hpos = prev_hpos;
  1480           vpos = prev_vpos;
  1481           tab_offset = prev_tab_offset;
  1482 
  1483           /* NOTE on contin_hpos, hpos, and prev_hpos.
  1484 
  1485              ----------
  1486              abcdefgh\\
  1487              W_      ^----  contin_hpos
  1488              | ^-----  hpos
  1489              \---- prev_hpos
  1490              ----------
  1491            */
  1492 
  1493           if (contin_hpos && prev_hpos == 0
  1494               && contin_hpos < width && !wide_column_end_hpos)
  1495             {
  1496               /* Line breaking occurs in the middle of multi-column
  1497                  character.  Go back to previous line.  */
  1498               hpos = contin_hpos;
  1499               vpos = vpos - 1;
  1500             }
  1501           break;
  1502         }
  1503 
  1504       if (vpos > tovpos || (vpos == tovpos && hpos >= tohpos))
  1505         {
  1506           if (contin_hpos && prev_hpos == 0
  1507               && hpos > tohpos
  1508               && (contin_hpos == width || wide_column_end_hpos > width))
  1509             { /* Line breaks because we can't put the character at the
  1510                  previous line any more.  It is not the multi-column
  1511                  character continued in middle.  Go back to previous
  1512                  buffer position, screen position, and set tab offset
  1513                  to previous value.  It's the beginning of the
  1514                  line.  */
  1515               pos = prev_pos;
  1516               pos_byte = prev_pos_byte;
  1517               hpos = prev_hpos;
  1518               vpos = prev_vpos;
  1519               tab_offset = prev_tab_offset;
  1520             }
  1521           break;
  1522         }
  1523       if (pos == ZV) /* We cannot go beyond ZV.  Stop here. */
  1524         break;
  1525 
  1526       prev_hpos = hpos;
  1527       prev_vpos = vpos;
  1528       prev_pos = pos;
  1529       prev_pos_byte = pos_byte;
  1530       wide_column_end_hpos = 0;
  1531 
  1532       /* Consult the width run cache to see if we can avoid inspecting
  1533          the text character-by-character.  */
  1534       if (width_cache && pos >= next_width_run)
  1535         {
  1536           ptrdiff_t run_end;
  1537           int common_width
  1538             = region_cache_forward (cache_buffer, width_cache, pos, &run_end);
  1539 
  1540           /* A width of zero means the character's width varies (like
  1541              a tab), is meaningless (like a newline), or we just don't
  1542              want to skip over it for some other reason.  */
  1543           if (common_width != 0)
  1544             {
  1545               ptrdiff_t run_end_hpos;
  1546 
  1547               /* Don't go past the final buffer posn the user
  1548                  requested.  */
  1549               if (run_end > to)
  1550                 run_end = to;
  1551 
  1552               run_end_hpos = hpos + (run_end - pos) * common_width;
  1553 
  1554               /* Don't go past the final horizontal position the user
  1555                  requested.  */
  1556               if (vpos == tovpos && run_end_hpos > tohpos)
  1557                 {
  1558                   run_end      = pos + (tohpos - hpos) / common_width;
  1559                   run_end_hpos = hpos + (run_end - pos) * common_width;
  1560                 }
  1561 
  1562               /* Don't go past the margin.  */
  1563               if (run_end_hpos >= width)
  1564                 {
  1565                   run_end      = pos + (width  - hpos) / common_width;
  1566                   run_end_hpos = hpos + (run_end - pos) * common_width;
  1567                 }
  1568 
  1569               hpos = run_end_hpos;
  1570               if (run_end > pos)
  1571                 prev_hpos = hpos - common_width;
  1572               if (pos != run_end)
  1573                 {
  1574                   pos = run_end;
  1575                   pos_byte = CHAR_TO_BYTE (pos);
  1576                 }
  1577             }
  1578 
  1579           next_width_run = run_end + 1;
  1580         }
  1581 
  1582       /* We have to scan the text character-by-character.  */
  1583       else
  1584         {
  1585           ptrdiff_t i, n;
  1586           Lisp_Object charvec;
  1587 
  1588           /* Check composition sequence.  */
  1589           if (cmp_it.id >= 0
  1590               || (pos == cmp_it.stop_pos
  1591                   && composition_reseat_it (&cmp_it, pos, pos_byte, to, win,
  1592                                             -1, NULL, Qnil)))
  1593             composition_update_it (&cmp_it, pos, pos_byte, Qnil);
  1594           if (cmp_it.id >= 0)
  1595             {
  1596               pos += cmp_it.nchars;
  1597               pos_byte += cmp_it.nbytes;
  1598               hpos += cmp_it.width;
  1599               if (cmp_it.to == cmp_it.nglyphs)
  1600                 {
  1601                   cmp_it.id = -1;
  1602                   composition_compute_stop_pos (&cmp_it, pos, pos_byte, to,
  1603                                                 Qnil, true);
  1604                 }
  1605               else
  1606                 cmp_it.from = cmp_it.to;
  1607               continue;
  1608             }
  1609 
  1610           c = FETCH_BYTE (pos_byte);
  1611           pos++, pos_byte++;
  1612 
  1613           /* Perhaps add some info to the width_run_cache.  */
  1614           if (width_cache)
  1615             {
  1616               /* Is this character part of the current run?  If so, extend
  1617                  the run.  */
  1618               if (pos - 1 == width_run_end
  1619                   && XFIXNAT (width_table[c]) == width_run_width)
  1620                 width_run_end = pos;
  1621 
  1622               /* The previous run is over, since this is a character at a
  1623                  different position, or a different width.  */
  1624               else
  1625                 {
  1626                   /* Have we accumulated a run to put in the cache?
  1627                      (Currently, we only cache runs of width == 1).  */
  1628                   if (width_run_start < width_run_end
  1629                       && width_run_width == 1)
  1630                     know_region_cache (cache_buffer, width_cache,
  1631                                        width_run_start, width_run_end);
  1632 
  1633                   /* Start recording a new width run.  */
  1634                   width_run_width = XFIXNAT (width_table[c]);
  1635                   width_run_start = pos - 1;
  1636                   width_run_end = pos;
  1637                 }
  1638             }
  1639 
  1640           if (dp != 0
  1641               && ! (multibyte && LEADING_CODE_P (c))
  1642               && VECTORP (DISP_CHAR_VECTOR (dp, c)))
  1643             {
  1644               charvec = DISP_CHAR_VECTOR (dp, c);
  1645               n = ASIZE (charvec);
  1646             }
  1647           else
  1648             {
  1649               charvec = Qnil;
  1650               n = 1;
  1651             }
  1652 
  1653           for (i = 0; i < n; ++i)
  1654             {
  1655               if (VECTORP (charvec))
  1656                 {
  1657                   /* This should be handled the same as
  1658                      next_element_from_display_vector does it.  */
  1659                   Lisp_Object entry = AREF (charvec, i);
  1660 
  1661                   if (GLYPH_CODE_P (entry))
  1662                     c = GLYPH_CODE_CHAR (entry);
  1663                   else
  1664                     c = ' ';
  1665                 }
  1666 
  1667               if (c >= 040 && c < 0177)
  1668                 hpos++;
  1669               else if (c == '\t')
  1670                 {
  1671                   int tem = ((hpos + tab_offset + hscroll - (hscroll > 0))
  1672                              % tab_width);
  1673                   if (tem < 0)
  1674                     tem += tab_width;
  1675                   hpos += tab_width - tem;
  1676                 }
  1677               else if (c == '\n')
  1678                 {
  1679                   if (selective > 0
  1680                       && indented_beyond_p (pos, pos_byte, selective))
  1681                     {
  1682                       /* If (pos == to), we don't have to take care of
  1683                          selective display.  */
  1684                       if (pos < to)
  1685                         {
  1686                           /* Skip any number of invisible lines all at once */
  1687                           do
  1688                             {
  1689                               pos = find_before_next_newline (pos, to, 1, &pos_byte);
  1690                               if (pos < to)
  1691                                 inc_both (&pos, &pos_byte);
  1692                               rarely_quit (++quit_count);
  1693                             }
  1694                           while (pos < to
  1695                                  && indented_beyond_p (pos, pos_byte,
  1696                                                        selective));
  1697                           /* Allow for the " ..." that is displayed for them. */
  1698                           if (selective_rlen)
  1699                             {
  1700                               hpos += selective_rlen;
  1701                               if (hpos >= width)
  1702                                 hpos = width;
  1703                             }
  1704                           dec_both (&pos, &pos_byte);
  1705                           /* We have skipped the invis text, but not the
  1706                              newline after.  */
  1707                         }
  1708                     }
  1709                   else
  1710                     {
  1711                       /* A visible line.  */
  1712                       vpos++;
  1713                       hpos = 0;
  1714                       hpos -= hscroll;
  1715                       /* Count the truncation glyph on column 0 */
  1716                       if (hscroll > 0)
  1717                         hpos += continuation_glyph_width;
  1718                       tab_offset = 0;
  1719                     }
  1720                   contin_hpos = 0;
  1721                 }
  1722               else if (c == CR && selective < 0)
  1723                 {
  1724                   /* In selective display mode,
  1725                      everything from a ^M to the end of the line is invisible.
  1726                      Stop *before* the real newline.  */
  1727                   if (pos < to)
  1728                     pos = find_before_next_newline (pos, to, 1, &pos_byte);
  1729                   /* If we just skipped next_boundary,
  1730                      loop around in the main while
  1731                      and handle it.  */
  1732                   if (pos > next_boundary)
  1733                     next_boundary = pos;
  1734                   /* Allow for the " ..." that is displayed for them. */
  1735                   if (selective_rlen)
  1736                     {
  1737                       hpos += selective_rlen;
  1738                       if (hpos >= width)
  1739                         hpos = width;
  1740                     }
  1741                 }
  1742               else if (multibyte && LEADING_CODE_P (c))
  1743                 {
  1744                   /* Start of multi-byte form.  */
  1745                   unsigned char *ptr;
  1746                   int mb_bytes, mb_width;
  1747 
  1748                   pos_byte--;   /* rewind POS_BYTE */
  1749                   ptr = BYTE_POS_ADDR (pos_byte);
  1750                   MULTIBYTE_BYTES_WIDTH (ptr, dp, mb_bytes, mb_width);
  1751                   pos_byte += mb_bytes;
  1752                   if (mb_width > 1 && BYTES_BY_CHAR_HEAD (*ptr) == mb_bytes)
  1753                     wide_column_end_hpos = hpos + mb_width;
  1754                   hpos += mb_width;
  1755                 }
  1756               else if (VECTORP (charvec))
  1757                 ++hpos;
  1758               else
  1759                 hpos += (ctl_arrow && c < 0200) ? 2 : 4;
  1760             }
  1761         }
  1762     }
  1763 
  1764  after_loop:
  1765 
  1766   /* Remember any final width run in the cache.  */
  1767   if (width_cache
  1768       && width_run_width == 1
  1769       && width_run_start < width_run_end)
  1770     know_region_cache (cache_buffer, width_cache,
  1771                        width_run_start, width_run_end);
  1772 
  1773   val_compute_motion.bufpos = pos;
  1774   val_compute_motion.bytepos = pos_byte;
  1775   val_compute_motion.hpos = hpos;
  1776   val_compute_motion.vpos = vpos;
  1777   if (contin_hpos && prev_hpos == 0)
  1778     val_compute_motion.prevhpos = contin_hpos;
  1779   else
  1780     val_compute_motion.prevhpos = prev_hpos;
  1781 
  1782   /* Nonzero if have just continued a line */
  1783   val_compute_motion.contin = (contin_hpos && prev_hpos == 0);
  1784 
  1785   return &val_compute_motion;
  1786 }
  1787 
  1788 
  1789 DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0,
  1790        doc: /* Scan through the current buffer, calculating screen position.
  1791 Scan the current buffer forward from offset FROM,
  1792 assuming it is at position FROMPOS--a cons of the form (HPOS . VPOS)--
  1793 to position TO or position TOPOS--another cons of the form (HPOS . VPOS)--
  1794 and return the ending buffer position and screen location.
  1795 
  1796 If TOPOS is nil, the actual width and height of the window's
  1797 text area are used.
  1798 
  1799 There are three additional arguments:
  1800 
  1801 WIDTH is the number of columns available to display text;
  1802 this affects handling of continuation lines.  A value of nil
  1803 corresponds to the actual number of available text columns.
  1804 
  1805 OFFSETS is either nil or a cons cell (HSCROLL . TAB-OFFSET).
  1806 HSCROLL is the number of columns not being displayed at the left
  1807 margin; this is usually taken from a window's hscroll member.
  1808 TAB-OFFSET is the number of columns of the first tab that aren't
  1809 being displayed, perhaps because the line was continued within it.
  1810 If OFFSETS is nil, HSCROLL and TAB-OFFSET are assumed to be zero.
  1811 
  1812 WINDOW is the window to operate on.  It is used to choose the display table;
  1813 if it is showing the current buffer, it is used also for
  1814 deciding which overlay properties apply.
  1815 Note that `compute-motion' always operates on the current buffer.
  1816 
  1817 The value is a list of five elements:
  1818   (POS HPOS VPOS PREVHPOS CONTIN)
  1819 POS is the buffer position where the scan stopped.
  1820 VPOS is the vertical position where the scan stopped.
  1821 HPOS is the horizontal position where the scan stopped.
  1822 
  1823 PREVHPOS is the horizontal position one character back from POS.
  1824 CONTIN is t if a line was continued after (or within) the previous character.
  1825 
  1826 For example, to find the buffer position of column COL of line LINE
  1827 of a certain window, pass the window's starting location as FROM
  1828 and the window's upper-left coordinates as FROMPOS.
  1829 Pass the buffer's (point-max) as TO, to limit the scan to the end of the
  1830 visible section of the buffer, and pass LINE and COL as TOPOS.  */)
  1831   (Lisp_Object from, Lisp_Object frompos, Lisp_Object to, Lisp_Object topos,
  1832    Lisp_Object width, Lisp_Object offsets, Lisp_Object window)
  1833 {
  1834   struct window *w;
  1835   Lisp_Object bufpos, hpos, vpos, prevhpos;
  1836   struct position *pos;
  1837   ptrdiff_t hscroll;
  1838   int tab_offset;
  1839 
  1840   CHECK_FIXNUM_COERCE_MARKER (from);
  1841   CHECK_CONS (frompos);
  1842   CHECK_FIXNUM (XCAR (frompos));
  1843   CHECK_FIXNUM (XCDR (frompos));
  1844   CHECK_FIXNUM_COERCE_MARKER (to);
  1845   if (!NILP (topos))
  1846     {
  1847       CHECK_CONS (topos);
  1848       CHECK_FIXNUM (XCAR (topos));
  1849       CHECK_FIXNUM (XCDR (topos));
  1850     }
  1851   if (!NILP (width))
  1852     CHECK_FIXNUM (width);
  1853 
  1854   if (!NILP (offsets))
  1855     {
  1856       CHECK_CONS (offsets);
  1857       CHECK_FIXNUM (XCAR (offsets));
  1858       CHECK_FIXNUM (XCDR (offsets));
  1859       if (! (0 <= XFIXNUM (XCAR (offsets)) && XFIXNUM (XCAR (offsets)) <= PTRDIFF_MAX
  1860              && 0 <= XFIXNUM (XCDR (offsets)) && XFIXNUM (XCDR (offsets)) <= INT_MAX))
  1861         args_out_of_range (XCAR (offsets), XCDR (offsets));
  1862       hscroll = XFIXNUM (XCAR (offsets));
  1863       tab_offset = XFIXNUM (XCDR (offsets));
  1864     }
  1865   else
  1866     hscroll = tab_offset = 0;
  1867 
  1868   w = decode_live_window (window);
  1869 
  1870   if (XFIXNUM (from) < BEGV || XFIXNUM (from) > ZV)
  1871     args_out_of_range_3 (from, make_fixnum (BEGV), make_fixnum (ZV));
  1872   if (XFIXNUM (to) < BEGV || XFIXNUM (to) > ZV)
  1873     args_out_of_range_3 (to, make_fixnum (BEGV), make_fixnum (ZV));
  1874 
  1875   pos = compute_motion (XFIXNUM (from), CHAR_TO_BYTE (XFIXNUM (from)),
  1876                         XFIXNUM (XCDR (frompos)),
  1877                         XFIXNUM (XCAR (frompos)), 0,
  1878                         XFIXNUM (to),
  1879                         (NILP (topos)
  1880                          ? window_internal_height (w)
  1881                          : XFIXNUM (XCDR (topos))),
  1882                         (NILP (topos)
  1883                          ? (window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS)
  1884                             - (
  1885 #ifdef HAVE_WINDOW_SYSTEM
  1886                                FRAME_WINDOW_P (XFRAME (w->frame)) ? 0 :
  1887 #endif
  1888                                1))
  1889                          : XFIXNUM (XCAR (topos))),
  1890                         (NILP (width) ? -1 : XFIXNUM (width)),
  1891                         hscroll, tab_offset, w);
  1892 
  1893   XSETFASTINT (bufpos, pos->bufpos);
  1894   XSETINT (hpos, pos->hpos);
  1895   XSETINT (vpos, pos->vpos);
  1896   XSETINT (prevhpos, pos->prevhpos);
  1897 
  1898   return list5 (bufpos, hpos, vpos, prevhpos, pos->contin ? Qt : Qnil);
  1899 }
  1900 
  1901 /* Fvertical_motion and vmotion.  */
  1902 
  1903 static struct position val_vmotion;
  1904 
  1905 struct position *
  1906 vmotion (ptrdiff_t from, ptrdiff_t from_byte,
  1907          EMACS_INT vtarget, struct window *w)
  1908 {
  1909   ptrdiff_t hscroll = w->hscroll;
  1910   struct position pos;
  1911   /* VPOS is cumulative vertical position, changed as from is changed.  */
  1912   register EMACS_INT vpos = 0;
  1913   ptrdiff_t prevline;
  1914   register ptrdiff_t first;
  1915   ptrdiff_t lmargin = hscroll > 0 ? 1 - hscroll : 0;
  1916   ptrdiff_t selective
  1917     = (FIXNUMP (BVAR (current_buffer, selective_display))
  1918        ? clip_to_bounds (-1, XFIXNUM (BVAR (current_buffer, selective_display)),
  1919                          PTRDIFF_MAX)
  1920        : !NILP (BVAR (current_buffer, selective_display)) ? -1 : 0);
  1921   Lisp_Object window;
  1922   bool did_motion;
  1923   /* This is the object we use for fetching character properties.  */
  1924   Lisp_Object text_prop_object;
  1925 
  1926   XSETWINDOW (window, w);
  1927 
  1928   /* If the window contains this buffer, use it for getting text properties.
  1929      Otherwise use the current buffer as arg for doing that.  */
  1930   if (BASE_EQ (w->contents, Fcurrent_buffer ()))
  1931     text_prop_object = window;
  1932   else
  1933     text_prop_object = Fcurrent_buffer ();
  1934 
  1935   if (vpos >= vtarget)
  1936     {
  1937       /* To move upward, go a line at a time until
  1938          we have gone at least far enough.  */
  1939 
  1940       first = 1;
  1941 
  1942       while ((vpos > vtarget || first) && from > BEGV)
  1943         {
  1944           ptrdiff_t bytepos = from_byte;
  1945           Lisp_Object propval;
  1946 
  1947           prevline = from;
  1948           dec_both (&prevline, &bytepos);
  1949           prevline = find_newline_no_quit (prevline, bytepos, -1, &bytepos);
  1950 
  1951           while (prevline > BEGV
  1952                  && ((selective > 0
  1953                       && indented_beyond_p (prevline, bytepos, selective))
  1954                      /* Watch out for newlines with `invisible' property.
  1955                         When moving upward, check the newline before.  */
  1956                      || (propval = Fget_char_property (make_fixnum (prevline - 1),
  1957                                                        Qinvisible,
  1958                                                        text_prop_object),
  1959                          TEXT_PROP_MEANS_INVISIBLE (propval))))
  1960             {
  1961               dec_both (&prevline, &bytepos);
  1962               prevline = find_newline_no_quit (prevline, bytepos, -1, &bytepos);
  1963             }
  1964           pos = *compute_motion (prevline, bytepos, 0, lmargin, 0, from,
  1965                                  /* Don't care for VPOS...  */
  1966                                  1 << (SHRT_WIDTH - 1),
  1967                                  /* ... nor HPOS.  */
  1968                                  1 << (SHRT_WIDTH - 1),
  1969                                  -1, hscroll, 0, w);
  1970           vpos -= pos.vpos;
  1971           first = 0;
  1972           from = prevline;
  1973           from_byte = bytepos;
  1974         }
  1975 
  1976       /* If we made exactly the desired vertical distance, or
  1977          if we hit beginning of buffer, return point found.  */
  1978       if (vpos >= vtarget)
  1979         {
  1980           val_vmotion.bufpos = from;
  1981           val_vmotion.bytepos = from_byte;
  1982           val_vmotion.vpos = vpos;
  1983           val_vmotion.hpos = lmargin;
  1984           val_vmotion.contin = 0;
  1985           val_vmotion.prevhpos = 0;
  1986           return &val_vmotion;
  1987         }
  1988 
  1989       /* Otherwise find the correct spot by moving down.  */
  1990     }
  1991 
  1992   /* Moving downward is simple, but must calculate from
  1993      beg of line to determine hpos of starting point.  */
  1994 
  1995   if (from > BEGV && FETCH_BYTE (from_byte - 1) != '\n')
  1996     {
  1997       ptrdiff_t bytepos;
  1998       Lisp_Object propval;
  1999 
  2000       prevline = find_newline_no_quit (from, from_byte, -1, &bytepos);
  2001       while (prevline > BEGV
  2002              && ((selective > 0
  2003                   && indented_beyond_p (prevline, bytepos, selective))
  2004                  /* Watch out for newlines with `invisible' property.
  2005                     When moving downward, check the newline after.  */
  2006                  || (propval = Fget_char_property (make_fixnum (prevline),
  2007                                                    Qinvisible,
  2008                                                    text_prop_object),
  2009                      TEXT_PROP_MEANS_INVISIBLE (propval))))
  2010         {
  2011           dec_both (&prevline, &bytepos);
  2012           prevline = find_newline_no_quit (prevline, bytepos, -1, &bytepos);
  2013         }
  2014       pos = *compute_motion (prevline, bytepos, 0, lmargin, 0, from,
  2015                              /* Don't care for VPOS...  */
  2016                              1 << (SHRT_WIDTH - 1),
  2017                              /* ... nor HPOS.  */
  2018                              1 << (SHRT_WIDTH - 1),
  2019                              -1, hscroll, 0, w);
  2020       did_motion = 1;
  2021     }
  2022   else
  2023     {
  2024       pos.hpos = lmargin;
  2025       pos.vpos = 0;
  2026       did_motion = 0;
  2027     }
  2028   return compute_motion (from, from_byte, vpos, pos.hpos, did_motion,
  2029                          ZV, vtarget, - (1 << (SHRT_WIDTH - 1)),
  2030                          -1, hscroll, 0, w);
  2031 }
  2032 
  2033 /* Return the width taken by line-number display in window W.  */
  2034 static void
  2035 line_number_display_width (struct window *w, int *width, int *pixel_width)
  2036 {
  2037   if (NILP (Vdisplay_line_numbers))
  2038     {
  2039       *width = 0;
  2040       *pixel_width = 0;
  2041     }
  2042   else
  2043     {
  2044       struct it it;
  2045       struct text_pos startpos;
  2046       bool saved_restriction = false;
  2047       struct buffer *old_buf = current_buffer;
  2048       specpdl_ref count = SPECPDL_INDEX ();
  2049       SET_TEXT_POS_FROM_MARKER (startpos, w->start);
  2050       void *itdata = bidi_shelve_cache ();
  2051 
  2052       /* Make sure W's buffer is the current one.  */
  2053       set_buffer_internal_1 (XBUFFER (w->contents));
  2054       /* We want to start from window's start point, but it could be
  2055          outside the accessible region, in which case we widen the
  2056          buffer temporarily.  It could even be beyond the buffer's end
  2057          (Org mode's display of source code snippets is known to cause
  2058          that) or belong to the wrong buffer, in which cases we just
  2059          punt and start from point instead.  */
  2060       if (startpos.charpos > Z
  2061           || !(BUFFERP (w->contents)
  2062                && XBUFFER (w->contents) == XMARKER (w->start)->buffer))
  2063         SET_TEXT_POS (startpos, PT, PT_BYTE);
  2064       if (startpos.charpos < BEGV || startpos.charpos > ZV)
  2065         {
  2066           record_unwind_protect (save_restriction_restore,
  2067                                  save_restriction_save ());
  2068           labeled_restrictions_remove_in_current_buffer ();
  2069           Fwiden ();
  2070           saved_restriction = true;
  2071         }
  2072       start_display (&it, w, startpos);
  2073       /* The call to move_it_by_lines below will not generate a line
  2074          number if the first line shown in the window is hscrolled
  2075          such that all of its display elements are out of view.  So we
  2076          pretend the hscroll doesn't exist.  */
  2077       it.first_visible_x = 0;
  2078       move_it_by_lines (&it, 1);
  2079       *width = it.lnum_width;
  2080       *pixel_width = it.lnum_pixel_width;
  2081       if (saved_restriction)
  2082         unbind_to (count, Qnil);
  2083       set_buffer_internal_1 (old_buf);
  2084       bidi_unshelve_cache (itdata, 0);
  2085     }
  2086 }
  2087 
  2088 DEFUN ("line-number-display-width", Fline_number_display_width,
  2089        Sline_number_display_width, 0, 1, 0,
  2090        doc: /* Return the width used for displaying line numbers in the selected window.
  2091 If optional argument PIXELWISE is the symbol `columns', return the width
  2092 in units of the frame's canonical character width.  In this case, the
  2093 value is a float.
  2094 If optional argument PIXELWISE is t or any other non-nil value, return
  2095 the width as an integer number of pixels.
  2096 Otherwise return the value as an integer number of columns of the face
  2097 used to display line numbers, `line-number'.  Note that in the latter
  2098 case, the value doesn't include the 2 columns used for padding the
  2099 numbers on display.  */)
  2100   (Lisp_Object pixelwise)
  2101 {
  2102   int width, pixel_width;
  2103   struct window *w = XWINDOW (selected_window);
  2104   line_number_display_width (XWINDOW (selected_window), &width, &pixel_width);
  2105   if (EQ (pixelwise, Qcolumns))
  2106     {
  2107       struct frame *f = XFRAME (w->frame);
  2108       return make_float ((double) pixel_width / FRAME_COLUMN_WIDTH (f));
  2109     }
  2110   else if (!NILP (pixelwise))
  2111     return make_fixnum (pixel_width);
  2112   return make_fixnum (width);
  2113 }
  2114 
  2115 /* In window W (derived from WINDOW), return x coordinate for column
  2116    COL (derived from COLUMN).  */
  2117 static int
  2118 window_column_x (struct window *w, Lisp_Object window,
  2119                  double col, Lisp_Object column)
  2120 {
  2121   double x = col * FRAME_COLUMN_WIDTH (XFRAME (w->frame)) + 0.5;
  2122 
  2123   /* FIXME: Should this be limited to W's dimensions?  */
  2124   if (! (INT_MIN <= x && x <= INT_MAX))
  2125     args_out_of_range (window, column);
  2126 
  2127   return x;
  2128 }
  2129 
  2130 /* Restore window's buffer and point.  */
  2131 
  2132 /* FIXME: Merge with `with_echo_area_buffer_unwind_data`?  */
  2133 static void
  2134 restore_window_buffer (Lisp_Object list)
  2135 {
  2136   struct window *w = decode_live_window (XCAR (list));
  2137   list = XCDR (list);
  2138   wset_buffer (w, XCAR (list));
  2139   list = XCDR (list);
  2140   set_marker_both (w->pointm, w->contents,
  2141                    XFIXNAT (XCAR (list)),
  2142                    XFIXNAT (XCAR (XCDR (list))));
  2143 }
  2144 
  2145 DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 3, 0,
  2146        doc: /* Move point to start of the screen line LINES lines down.
  2147 If LINES is negative, this means moving up.
  2148 
  2149 This function is an ordinary cursor motion function
  2150 which calculates the new position based on how text would be displayed.
  2151 The new position may be the start of a line,
  2152 or the start of a continuation line,
  2153 or the start of the visible portion of a horizontally-scrolled line.
  2154 
  2155 The function returns number of screen lines moved over;
  2156 that usually equals LINES, but may be closer to zero if
  2157 beginning or end of buffer was reached.
  2158 
  2159 The optional second argument WINDOW specifies the window to use for
  2160 parameters such as width, horizontal scrolling, and so on.
  2161 The default is to use the selected window's parameters.
  2162 
  2163 If LINES is zero, point will move to the first visible character on
  2164 the current screen line.
  2165 
  2166 LINES can optionally take the form (COLS . LINES), in which case the
  2167 motion will stop at the COLSth column from the visual start of the
  2168 line (if such column exists on that line, that is).  If the line is
  2169 scrolled horizontally, COLS is interpreted visually, i.e., as addition
  2170 to the columns of text beyond the left edge of the window.
  2171 If LINES is a cons cell, its car COLS can be a float, which allows
  2172 specifying an accurate position of point on a screen line that mixes
  2173 fonts or uses variable-pitch font: COLS is interpreted in units of the
  2174 canonical character width, and is internally converted to pixel units;
  2175 point will then stop at the position closest to that pixel coordinate.
  2176 The cdr of the cons, LINES, must be an integer; if it is zero, this
  2177 function moves point horizontally in the current screen line, to the
  2178 position specified by COLS.
  2179 
  2180 The optional third argument CUR-COL specifies the horizontal
  2181 window-relative coordinate of point, in units of frame's canonical
  2182 character width, where the function is invoked.  If this argument is
  2183 omitted or nil, the function will determine the point coordinate by
  2184 going back to the beginning of the line.
  2185 
  2186 `vertical-motion' always uses the current buffer, regardless of which
  2187 buffer is displayed in WINDOW.  This is consistent with other cursor
  2188 motion functions and makes it possible to use `vertical-motion' in any
  2189 buffer, whether or not it is currently displayed in some window.  */)
  2190   (Lisp_Object lines, Lisp_Object window, Lisp_Object cur_col)
  2191 {
  2192   struct it it;
  2193   struct text_pos pt;
  2194   struct window *w;
  2195   Lisp_Object lcols = Qnil;
  2196   void *itdata = NULL;
  2197   specpdl_ref count = SPECPDL_INDEX ();
  2198 
  2199   /* Allow LINES to be of the form (HPOS . VPOS) aka (COLUMNS . LINES).  */
  2200   if (CONSP (lines))
  2201     {
  2202       lcols = XCAR (lines);
  2203       CHECK_NUMBER (lcols);
  2204       lines = XCDR (lines);
  2205     }
  2206 
  2207   CHECK_FIXNUM (lines);
  2208   w = decode_live_window (window);
  2209 
  2210   if (XBUFFER (w->contents) != current_buffer)
  2211     {
  2212       /* Set the window's buffer temporarily to the current buffer.  */
  2213       Lisp_Object old = list4 (window, w->contents,
  2214                                make_fixnum (marker_position (w->pointm)),
  2215                                make_fixnum (marker_byte_position (w->pointm)));
  2216       record_unwind_protect (restore_window_buffer, old);
  2217       wset_buffer (w, Fcurrent_buffer ());
  2218       set_marker_both (w->pointm, w->contents,
  2219                        BUF_PT (current_buffer), BUF_PT_BYTE (current_buffer));
  2220     }
  2221 
  2222   if (noninteractive)
  2223     {
  2224       struct position pos;
  2225       pos = *vmotion (PT, PT_BYTE, XFIXNUM (lines), w);
  2226       SET_PT_BOTH (pos.bufpos, pos.bytepos);
  2227       it.vpos = pos.vpos;
  2228     }
  2229   else
  2230     {
  2231       ptrdiff_t it_start, it_overshoot_count = 0;
  2232       int first_x;
  2233       bool overshoot_handled = 0;
  2234       bool disp_string_at_start_p = 0;
  2235       ptrdiff_t nlines = XFIXNUM (lines);
  2236       int vpos_init = 0;
  2237       double start_col UNINIT;
  2238       int start_x UNINIT;
  2239       int to_x = -1;
  2240 
  2241       bool start_x_given = !NILP (cur_col);
  2242       if (start_x_given)
  2243         {
  2244           start_col = extract_float (cur_col);
  2245           start_x = window_column_x (w, window, start_col, cur_col);
  2246         }
  2247 
  2248       /* When displaying line numbers, we need to prime IT's
  2249          lnum_width with the value calculated at window's start, since
  2250          that's what normal window redisplay does.  Otherwise C-n/C-p
  2251          will sometimes err by one column.  */
  2252       int lnum_width = 0;
  2253       int lnum_pixel_width = 0;
  2254       if (!NILP (Vdisplay_line_numbers))
  2255         line_number_display_width (w, &lnum_width, &lnum_pixel_width);
  2256       SET_TEXT_POS (pt, PT, PT_BYTE);
  2257       itdata = bidi_shelve_cache ();
  2258       record_unwind_protect_void (unwind_display_working_on_window);
  2259       display_working_on_window_p = true;
  2260       start_display (&it, w, pt);
  2261       it.lnum_width = lnum_width;
  2262       first_x = it.first_visible_x;
  2263       it_start = IT_CHARPOS (it);
  2264 
  2265       /* See comments below for why we calculate this.  */
  2266       if (it.cmp_it.id >= 0)
  2267         it_overshoot_count = 0;
  2268       else if (it.method == GET_FROM_STRING)
  2269         {
  2270           const char *s = SSDATA (it.string);
  2271           const char *e = s + SBYTES (it.string);
  2272 
  2273           disp_string_at_start_p =
  2274           /* If it.area is anything but TEXT_AREA, we need not bother
  2275              about the display string, as it doesn't affect cursor
  2276              positioning.  */
  2277             it.area == TEXT_AREA
  2278             && it.string_from_display_prop_p
  2279             /* A display string on anything but buffer text (e.g., on
  2280                an overlay string) doesn't affect cursor positioning.  */
  2281             && (it.sp > 0 && it.stack[it.sp - 1].method == GET_FROM_BUFFER);
  2282           while (s < e)
  2283             {
  2284               if (*s++ == '\n')
  2285                 it_overshoot_count++;
  2286             }
  2287           if (!it_overshoot_count)
  2288             it_overshoot_count = -1;
  2289         }
  2290       else
  2291         it_overshoot_count =
  2292           /* If image_id is negative, it's a fringe bitmap, which by
  2293              definition doesn't affect display in the text area.  */
  2294           !((it.method == GET_FROM_IMAGE && it.image_id >= 0)
  2295             || it.method == GET_FROM_STRETCH);
  2296 
  2297       if (start_x_given)
  2298         {
  2299           it.hpos = start_col;
  2300           it.current_x = start_x;
  2301         }
  2302       else
  2303         {
  2304           /* Scan from the start of the line containing PT.  If we don't
  2305              do this, we start moving with IT->current_x == 0, while PT is
  2306              really at some x > 0.  */
  2307           reseat_at_previous_visible_line_start (&it);
  2308           it.current_x = it.hpos = 0;
  2309         }
  2310       if (IT_CHARPOS (it) != PT)
  2311         /* We used to temporarily disable selective display here; the
  2312            comment said this is "so we don't move too far" (2005-01-19
  2313            checkin by kfs).  But this does nothing useful that I can
  2314            tell, and it causes Bug#2694 .  -- cyd */
  2315         /* When the position we started from is covered by a display
  2316            string, move_it_to will overshoot it, while vertical-motion
  2317            wants to put the cursor _before_ the display string.  So in
  2318            that case, we move to buffer position before the display
  2319            string, and avoid overshooting.  But if the position before
  2320            the display string is a newline, we don't do this, because
  2321            otherwise we will end up in a screen line that is one too
  2322            far back.  */
  2323         move_it_to (&it,
  2324                     (!disp_string_at_start_p
  2325                      || FETCH_BYTE (IT_BYTEPOS (it)) == '\n')
  2326                     ? PT
  2327                     : PT - 1,
  2328                     -1, -1, -1, MOVE_TO_POS);
  2329 
  2330       /* IT may move too far if truncate-lines is on and PT lies
  2331          beyond the right margin.  IT may also move too far if the
  2332          starting point is on a Lisp string that has embedded
  2333          newlines, or spans several screen lines.  In these cases,
  2334          backtrack.  */
  2335       if (IT_CHARPOS (it) > it_start)
  2336         {
  2337           /* We need to backtrack also if the Lisp string contains no
  2338              newlines, but there is a newline right after it.  In this
  2339              case, IT overshoots if there is an after-string just
  2340              before the newline.  */
  2341           if (it_overshoot_count < 0
  2342               && it.method == GET_FROM_BUFFER
  2343               && it.c == '\n')
  2344             it_overshoot_count = 1;
  2345           else if (it_overshoot_count == 1 && it.vpos == 0
  2346                    && it.current_x < it.last_visible_x)
  2347             {
  2348               /* If we came to the same screen line as the one where
  2349                  we started, we didn't overshoot the line, and won't
  2350                  need to backtrack after all.  This happens, for
  2351                  example, when PT is in the middle of a composition.  */
  2352               it_overshoot_count = 0;
  2353             }
  2354           else if (disp_string_at_start_p && it.vpos > 0)
  2355             {
  2356               /* This is the case of a display string that spans
  2357                  several screen lines.  In that case, we end up at the
  2358                  end of the string, and it.vpos tells us how many
  2359                  screen lines we need to backtrack.  */
  2360               it_overshoot_count = it.vpos;
  2361             }
  2362           /* We might overshoot if lines are truncated and point lies
  2363              beyond the right margin of the window.  */
  2364           if (it.line_wrap == TRUNCATE && it.current_x >= it.last_visible_x
  2365               && it_overshoot_count == 0 && it.vpos > 0)
  2366             it_overshoot_count = 1;
  2367           if (it_overshoot_count > 0)
  2368             move_it_by_lines (&it, -it_overshoot_count);
  2369 
  2370           overshoot_handled = 1;
  2371         }
  2372       else if (IT_CHARPOS (it) == PT - 1
  2373                && FETCH_BYTE (PT_BYTE - 1) == '\n'
  2374                && nlines <= 0)
  2375         {
  2376           /* The position we started from was covered by a display
  2377              property, so we moved to position before the string, and
  2378              backed up one line, because the character at PT - 1 is
  2379              a newline.  So we need one less line to go up (or exactly
  2380              one line to go down if nlines == 0).  */
  2381           nlines++;
  2382           /* But we still need to record that one line, in order to
  2383              return the correct value to the caller.  */
  2384           vpos_init = -1;
  2385 
  2386           overshoot_handled = 1;
  2387         }
  2388       if (!NILP (lcols))
  2389         to_x =
  2390           window_column_x (w, window, XFLOATINT (lcols), lcols)
  2391           + lnum_pixel_width;
  2392       if (nlines <= 0)
  2393         {
  2394           it.vpos = vpos_init;
  2395           it.current_y = 0;
  2396           /* Do this even if LINES is 0, so that we move back to the
  2397              beginning of the current line as we ought.  */
  2398           if ((nlines < 0 && IT_CHARPOS (it) > BEGV)
  2399               || (nlines == 0 && !(start_x_given && start_x <= to_x)))
  2400             move_it_by_lines (&it, max (PTRDIFF_MIN, nlines));
  2401         }
  2402       else if (overshoot_handled)
  2403         {
  2404           it.vpos = vpos_init;
  2405           it.current_y = 0;
  2406           move_it_by_lines (&it, min (PTRDIFF_MAX, nlines));
  2407         }
  2408       else
  2409         {
  2410           /* Otherwise, we are at the first row occupied by PT, which
  2411              might span multiple screen lines (e.g., if it's on a
  2412              multi-line display string).  We want to start from the
  2413              last line that it occupies.  */
  2414           if (it_start < ZV)
  2415             {
  2416               if ((it.bidi_it.scan_dir >= 0 || it.vpos == vpos_init)
  2417                   ? IT_CHARPOS (it) < it_start
  2418                   : IT_CHARPOS (it) > it_start)
  2419                 {
  2420                   it.vpos = 0;
  2421                   it.current_y = 0;
  2422                   move_it_by_lines (&it, 1);
  2423                 }
  2424               while (IT_CHARPOS (it) == it_start)
  2425                 {
  2426                   it.vpos = 0;
  2427                   it.current_y = 0;
  2428                   move_it_by_lines (&it, 1);
  2429                 }
  2430               if (nlines > 1)
  2431                 move_it_by_lines (&it, min (PTRDIFF_MAX, nlines - 1));
  2432             }
  2433           else  /* it_start = ZV */
  2434             {
  2435               it.vpos = 0;
  2436               it.current_y = 0;
  2437               move_it_by_lines (&it, min (PTRDIFF_MAX, nlines));
  2438               /* We could have some display or overlay string at ZV,
  2439                  in which case it.vpos will be nonzero now, while
  2440                  actually we didn't move vertically at all.  */
  2441               if (IT_CHARPOS (it) == CHARPOS (pt) && CHARPOS (pt) == it_start)
  2442                 it.vpos = 0;
  2443             }
  2444         }
  2445 
  2446       /* Move to the goal column, if one was specified.  If the window
  2447          was originally hscrolled, the goal column is interpreted as
  2448          an addition to the hscroll amount.  */
  2449       if (!NILP (lcols))
  2450         {
  2451           move_it_in_display_line (&it, ZV, first_x + to_x, MOVE_TO_X);
  2452           /* If we find ourselves in the middle of an overlay string
  2453              which includes a newline after current string position,
  2454              we need to move by lines until we get out of the string,
  2455              and then reposition point at the requested X coordinate;
  2456              if we don't, the cursor will be placed just after the
  2457              string, which might not be the requested column.  */
  2458           if (nlines >= 0 && it.area == TEXT_AREA)
  2459             {
  2460               while (it.method == GET_FROM_STRING
  2461                      && !it.string_from_display_prop_p
  2462                      && memchr (SSDATA (it.string) + IT_STRING_BYTEPOS (it),
  2463                                 '\n',
  2464                                 SBYTES (it.string) - IT_STRING_BYTEPOS (it)))
  2465                 {
  2466                   move_it_by_lines (&it, 1);
  2467                   move_it_in_display_line (&it, ZV, first_x + to_x, MOVE_TO_X);
  2468                 }
  2469             }
  2470         }
  2471 
  2472       SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
  2473       bidi_unshelve_cache (itdata, 0);
  2474     }
  2475 
  2476   return unbind_to (count, make_fixnum (it.vpos));
  2477 }
  2478 
  2479 
  2480 
  2481 /* File's initialization.  */
  2482 
  2483 void
  2484 syms_of_indent (void)
  2485 {
  2486   DEFVAR_BOOL ("indent-tabs-mode", indent_tabs_mode,
  2487                doc: /* Indentation can insert tabs if this is non-nil.  */);
  2488   indent_tabs_mode = 1;
  2489 
  2490   DEFSYM (Qcolumns, "columns");
  2491 
  2492   defsubr (&Scurrent_indentation);
  2493   defsubr (&Sindent_to);
  2494   defsubr (&Scurrent_column);
  2495   defsubr (&Smove_to_column);
  2496   defsubr (&Sline_number_display_width);
  2497   defsubr (&Svertical_motion);
  2498   defsubr (&Scompute_motion);
  2499 }

/* [<][>][^][v][top][bottom][index][help] */