Install some window-size related functions and window-list-1.
[bpt/emacs.git] / src / indent.c
CommitLineData
993b6404 1/* Indentation functions.
73b0cd50 2 Copyright (C) 1985-1988, 1993-1995, 1998, 2000-2011
8cabe764 3 Free Software Foundation, Inc.
993b6404
JB
4
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
993b6404 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
993b6404
JB
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
993b6404 19
18160b98 20#include <config.h>
4d553a13 21#include <stdio.h>
d7306fe6 22#include <setjmp.h>
4d553a13 23
993b6404
JB
24#include "lisp.h"
25#include "buffer.h"
f6ed712f 26#include "character.h"
fb911777 27#include "category.h"
d6721dda 28#include "composite.h"
993b6404 29#include "indent.h"
2538fae4 30#include "keyboard.h"
502b9b64 31#include "frame.h"
993b6404
JB
32#include "window.h"
33#include "termchar.h"
34#include "termopts.h"
35#include "disptab.h"
5a05d3d2 36#include "intervals.h"
d6721dda 37#include "dispextern.h"
0aa01123 38#include "region-cache.h"
993b6404 39
993b6404
JB
40#define CR 015
41
79c2a4fc 42/* These three values memorize the current column to avoid recalculation. */
88c6e37e
GM
43
44/* Last value returned by current_column.
45 Some things in set last_known_column_point to -1
79c2a4fc 46 to mark the memorized value as invalid. */
88c6e37e 47
7831777b 48static EMACS_INT last_known_column;
88c6e37e
GM
49
50/* Value of point when current_column was called. */
51
83155776 52EMACS_INT last_known_column_point;
88c6e37e
GM
53
54/* Value of MODIFF when current_column was called. */
55
c86f7377 56static int last_known_column_modified;
993b6404 57
7831777b
PE
58static EMACS_INT current_column_1 (void);
59static EMACS_INT position_indentation (int);
82d593eb 60
a997a7ca
KH
61/* Cache of beginning of line found by the last call of
62 current_column. */
88c6e37e 63
83155776 64static EMACS_INT current_column_bol_cache;
a997a7ca 65
993b6404
JB
66/* Get the display table to use for the current buffer. */
67
d44f12b4 68struct Lisp_Char_Table *
971de7fb 69buffer_display_table (void)
993b6404
JB
70{
71 Lisp_Object thisbuf;
72
4b4deea2 73 thisbuf = BVAR (current_buffer, display_table);
d44f12b4
RS
74 if (DISP_TABLE_P (thisbuf))
75 return XCHAR_TABLE (thisbuf);
76 if (DISP_TABLE_P (Vstandard_display_table))
77 return XCHAR_TABLE (Vstandard_display_table);
993b6404
JB
78 return 0;
79}
80\f
0aa01123
JB
81/* Width run cache considerations. */
82
83/* Return the width of character C under display table DP. */
f845b8b2 84
0aa01123 85static int
971de7fb 86character_width (int c, struct Lisp_Char_Table *dp)
0aa01123
JB
87{
88 Lisp_Object elt;
89
90 /* These width computations were determined by examining the cases
91 in display_text_line. */
92
f845b8b2 93 /* Everything can be handled by the display table, if it's
0aa01123 94 present and the element is right. */
f845b8b2 95 if (dp && (elt = DISP_CHAR_VECTOR (dp, c), VECTORP (elt)))
77b37c05 96 return ASIZE (elt);
0aa01123 97
f845b8b2
RS
98 /* Some characters are special. */
99 if (c == '\n' || c == '\t' || c == '\015')
100 return 0;
101
102 /* Printing characters have width 1. */
0aa01123
JB
103 else if (c >= 040 && c < 0177)
104 return 1;
105
106 /* Everybody else (control characters, metacharacters) has other
107 widths. We could return their actual widths here, but they
108 depend on things like ctl_arrow and crud like that, and they're
109 not very common at all. So we'll just claim we don't know their
110 widths. */
111 else
112 return 0;
113}
114
e0f24100 115/* Return true if the display table DISPTAB specifies the same widths
0aa01123
JB
116 for characters as WIDTHTAB. We use this to decide when to
117 invalidate the buffer's width_run_cache. */
88c6e37e 118
0aa01123 119int
971de7fb 120disptab_matches_widthtab (struct Lisp_Char_Table *disptab, struct Lisp_Vector *widthtab)
0aa01123
JB
121{
122 int i;
123
eab3844f 124 if (widthtab->header.size != 256)
0aa01123
JB
125 abort ();
126
127 for (i = 0; i < 256; i++)
128 if (character_width (i, disptab)
129 != XFASTINT (widthtab->contents[i]))
130 return 0;
131
132 return 1;
2ff4775b 133}
0aa01123
JB
134
135/* Recompute BUF's width table, using the display table DISPTAB. */
88c6e37e 136
0aa01123 137void
971de7fb 138recompute_width_table (struct buffer *buf, struct Lisp_Char_Table *disptab)
0aa01123
JB
139{
140 int i;
228a2e1a 141 struct Lisp_Vector *widthtab;
0aa01123 142
4b4deea2
TT
143 if (!VECTORP (BVAR (buf, width_table)))
144 BVAR (buf, width_table) = Fmake_vector (make_number (256), make_number (0));
145 widthtab = XVECTOR (BVAR (buf, width_table));
eab3844f 146 if (widthtab->header.size != 256)
0aa01123
JB
147 abort ();
148
149 for (i = 0; i < 256; i++)
228a2e1a 150 XSETFASTINT (widthtab->contents[i], character_width (i, disptab));
0aa01123
JB
151}
152
153/* Allocate or free the width run cache, as requested by the current
154 state of current_buffer's cache_long_line_scans variable. */
88c6e37e 155
0aa01123 156static void
971de7fb 157width_run_cache_on_off (void)
0aa01123 158{
4b4deea2 159 if (NILP (BVAR (current_buffer, cache_long_line_scans))
a997a7ca
KH
160 /* And, for the moment, this feature doesn't work on multibyte
161 characters. */
4b4deea2 162 || !NILP (BVAR (current_buffer, enable_multibyte_characters)))
0aa01123
JB
163 {
164 /* It should be off. */
165 if (current_buffer->width_run_cache)
166 {
167 free_region_cache (current_buffer->width_run_cache);
168 current_buffer->width_run_cache = 0;
4b4deea2 169 BVAR (current_buffer, width_table) = Qnil;
0aa01123
JB
170 }
171 }
172 else
173 {
174 /* It should be on. */
175 if (current_buffer->width_run_cache == 0)
2ff4775b 176 {
0aa01123 177 current_buffer->width_run_cache = new_region_cache ();
0aa01123
JB
178 recompute_width_table (current_buffer, buffer_display_table ());
179 }
180 }
181}
182
183\f
9a21bb64
RS
184/* Skip some invisible characters starting from POS.
185 This includes characters invisible because of text properties
186 and characters invisible because of overlays.
187
188 If position POS is followed by invisible characters,
189 skip some of them and return the position after them.
190 Otherwise return POS itself.
191
192 Set *NEXT_BOUNDARY_P to the next position at which
193 it will be necessary to call this function again.
194
195 Don't scan past TO, and don't set *NEXT_BOUNDARY_P
196 to a value greater than TO.
197
198 If WINDOW is non-nil, and this buffer is displayed in WINDOW,
199 take account of overlays that apply only in WINDOW.
200
201 We don't necessarily skip all the invisible characters after POS
202 because that could take a long time. We skip a reasonable number
203 which can be skipped quickly. If there might be more invisible
204 characters immediately following, then *NEXT_BOUNDARY_P
205 will equal the return value. */
206
83155776 207EMACS_INT
971de7fb 208skip_invisible (EMACS_INT pos, EMACS_INT *next_boundary_p, EMACS_INT to, Lisp_Object window)
9a21bb64 209{
2e34157c 210 Lisp_Object prop, position, overlay_limit, proplimit;
2ca8b6c2 211 Lisp_Object buffer, tmp;
83155776
SM
212 EMACS_INT end;
213 int inv_p;
9a21bb64
RS
214
215 XSETFASTINT (position, pos);
216 XSETBUFFER (buffer, current_buffer);
217
218 /* Give faster response for overlay lookup near POS. */
219 recenter_overlay_lists (current_buffer, pos);
220
221 /* We must not advance farther than the next overlay change.
222 The overlay change might change the invisible property;
223 or there might be overlay strings to be displayed there. */
224 overlay_limit = Fnext_overlay_change (position);
225 /* As for text properties, this gives a lower bound
226 for where the invisible text property could change. */
227 proplimit = Fnext_property_change (position, buffer, Qt);
228 if (XFASTINT (overlay_limit) < XFASTINT (proplimit))
229 proplimit = overlay_limit;
230 /* PROPLIMIT is now a lower bound for the next change
231 in invisible status. If that is plenty far away,
232 use that lower bound. */
233 if (XFASTINT (proplimit) > pos + 100 || XFASTINT (proplimit) >= to)
234 *next_boundary_p = XFASTINT (proplimit);
235 /* Otherwise, scan for the next `invisible' property change. */
236 else
237 {
238 /* Don't scan terribly far. */
239 XSETFASTINT (proplimit, min (pos + 100, to));
b55fa3c0 240 /* No matter what, don't go past next overlay change. */
9a21bb64
RS
241 if (XFASTINT (overlay_limit) < XFASTINT (proplimit))
242 proplimit = overlay_limit;
2ca8b6c2
SM
243 tmp = Fnext_single_property_change (position, Qinvisible,
244 buffer, proplimit);
245 end = XFASTINT (tmp);
fe0066f5 246#if 0
a997a7ca
KH
247 /* Don't put the boundary in the middle of multibyte form if
248 there is no actual property change. */
249 if (end == pos + 100
250 && !NILP (current_buffer->enable_multibyte_characters)
251 && end < ZV)
252 while (pos < end && !CHAR_HEAD_P (POS_ADDR (end)))
253 end--;
fe0066f5 254#endif
2e34157c 255 *next_boundary_p = end;
9a21bb64
RS
256 }
257 /* if the `invisible' property is set, we can skip to
258 the next property change */
662152dd
SM
259 prop = Fget_char_property (position, Qinvisible,
260 (!NILP (window)
261 && EQ (XWINDOW (window)->buffer, buffer))
262 ? window : buffer);
263 inv_p = TEXT_PROP_MEANS_INVISIBLE (prop);
264 /* When counting columns (window == nil), don't skip over ellipsis text. */
265 if (NILP (window) ? inv_p == 1 : inv_p)
9a21bb64
RS
266 return *next_boundary_p;
267 return pos;
268}
269\f
c9c0f7cf
KH
270/* Set variables WIDTH and BYTES for a multibyte sequence starting at P.
271
c9c0f7cf
KH
272 DP is a display table or NULL.
273
c59478bc 274 This macro is used in scan_for_column and in
c9c0f7cf
KH
275 compute_motion. */
276
85f24f61 277#define MULTIBYTE_BYTES_WIDTH(p, dp, bytes, width) \
012fd715 278 do { \
85f24f61 279 int ch; \
012fd715 280 \
85f24f61 281 ch = STRING_CHAR_AND_LENGTH (p, bytes); \
012fd715
KH
282 if (BYTES_BY_CHAR_HEAD (*p) != bytes) \
283 width = bytes * 4; \
284 else \
285 { \
85f24f61 286 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, ch))) \
77b37c05 287 width = ASIZE (DISP_CHAR_VECTOR (dp, ch)); \
012fd715 288 else \
85f24f61 289 width = CHAR_WIDTH (ch); \
012fd715 290 } \
c9c0f7cf
KH
291 } while (0)
292
097812fb 293
993b6404 294DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
8c1a1077
PJ
295 doc: /* Return the horizontal position of point. Beginning of line is column 0.
296This is calculated by adding together the widths of all the displayed
297representations of the character between the start of the previous line
7bf120f1
JB
298and point (eg. control characters will have a width of 2 or 4, tabs
299will have a variable width).
8c1a1077
PJ
300Ignores finite width of frame, which means that this function may return
301values greater than (frame-width).
302Whether the line is visible (if `selective-display' is t) has no effect;
e01732fa
SM
303however, ^M is treated as end of line when `selective-display' is t.
304Text that has an invisible property is considered as having width 0, unless
305`buffer-invisibility-spec' specifies that it is replaced by an ellipsis. */)
5842a27b 306 (void)
993b6404
JB
307{
308 Lisp_Object temp;
7831777b 309 XSETFASTINT (temp, current_column ());
993b6404
JB
310 return temp;
311}
312
e74928fc
JB
313/* Cancel any recorded value of the horizontal position. */
314
c9667ae1 315void
971de7fb 316invalidate_current_column (void)
e74928fc
JB
317{
318 last_known_column_point = 0;
319}
320
7831777b 321EMACS_INT
971de7fb 322current_column (void)
993b6404 323{
7831777b 324 register EMACS_INT col;
993b6404
JB
325 register unsigned char *ptr, *stop;
326 register int tab_seen;
7831777b 327 EMACS_INT post_tab;
993b6404 328 register int c;
7831777b 329 register EMACS_INT tab_width = XINT (BVAR (current_buffer, tab_width));
4b4deea2 330 int ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow));
d44f12b4 331 register struct Lisp_Char_Table *dp = buffer_display_table ();
993b6404 332
6ec8bbd2 333 if (PT == last_known_column_point
993b6404
JB
334 && MODIFF == last_known_column_modified)
335 return last_known_column;
336
813b81b3
RS
337 /* If the buffer has overlays, text properties,
338 or multibyte characters, use a more general algorithm. */
9a21bb64 339 if (BUF_INTERVALS (current_buffer)
3ea2f6f3
SM
340 || current_buffer->overlays_before
341 || current_buffer->overlays_after
813b81b3
RS
342 || Z != Z_BYTE)
343 return current_column_1 ();
9a21bb64
RS
344
345 /* Scan backwards from point to the previous newline,
346 counting width. Tab characters are the only complicated case. */
347
993b6404 348 /* Make a pointer for decrementing through the chars before point. */
fe0066f5 349 ptr = BYTE_POS_ADDR (PT_BYTE - 1) + 1;
993b6404
JB
350 /* Make a pointer to where consecutive chars leave off,
351 going backwards from point. */
6ec8bbd2 352 if (PT == BEGV)
993b6404 353 stop = ptr;
6ec8bbd2 354 else if (PT <= GPT || BEGV > GPT)
993b6404
JB
355 stop = BEGV_ADDR;
356 else
357 stop = GAP_END_ADDR;
358
88c6e37e
GM
359 if (tab_width <= 0 || tab_width > 1000)
360 tab_width = 8;
993b6404
JB
361
362 col = 0, tab_seen = 0, post_tab = 0;
363
364 while (1)
365 {
88c6e37e
GM
366 EMACS_INT i, n;
367 Lisp_Object charvec;
097812fb 368
993b6404
JB
369 if (ptr == stop)
370 {
371 /* We stopped either for the beginning of the buffer
372 or for the gap. */
373 if (ptr == BEGV_ADDR)
374 break;
097812fb 375
993b6404
JB
376 /* It was the gap. Jump back over it. */
377 stop = BEGV_ADDR;
378 ptr = GPT_ADDR;
097812fb 379
993b6404 380 /* Check whether that brings us to beginning of buffer. */
88c6e37e
GM
381 if (BEGV >= GPT)
382 break;
993b6404
JB
383 }
384
385 c = *--ptr;
097812fb 386
88c6e37e 387 if (dp && VECTORP (DISP_CHAR_VECTOR (dp, c)))
7050d530 388 {
88c6e37e
GM
389 charvec = DISP_CHAR_VECTOR (dp, c);
390 n = ASIZE (charvec);
7050d530 391 }
88c6e37e 392 else
993b6404 393 {
88c6e37e
GM
394 charvec = Qnil;
395 n = 1;
396 }
097812fb 397
88c6e37e
GM
398 for (i = n - 1; i >= 0; --i)
399 {
400 if (VECTORP (charvec))
401 {
402 /* This should be handled the same as
403 next_element_from_display_vector does it. */
404 Lisp_Object entry = AREF (charvec, i);
097812fb 405
f59836fe
KS
406 if (GLYPH_CODE_P (entry)
407 && GLYPH_CODE_CHAR_VALID_P (entry))
408 c = GLYPH_CODE_CHAR (entry);
88c6e37e
GM
409 else
410 c = ' ';
411 }
097812fb 412
88c6e37e
GM
413 if (c >= 040 && c < 0177)
414 col++;
415 else if (c == '\n'
416 || (c == '\r'
4b4deea2 417 && EQ (BVAR (current_buffer, selective_display), Qt)))
88c6e37e
GM
418 {
419 ptr++;
420 goto start_of_line_found;
421 }
422 else if (c == '\t')
423 {
424 if (tab_seen)
425 col = ((col + tab_width) / tab_width) * tab_width;
097812fb 426
88c6e37e
GM
427 post_tab += col;
428 col = 0;
429 tab_seen = 1;
430 }
f1004faf
GM
431 else if (VECTORP (charvec))
432 /* With a display table entry, C is displayed as is, and
433 not displayed as \NNN or as ^N. If C is a single-byte
434 character, it takes one column. If C is multi-byte in
435 an unibyte buffer, it's translated to unibyte, so it
436 also takes one column. */
437 ++col;
88c6e37e
GM
438 else
439 col += (ctl_arrow && c < 0200) ? 2 : 4;
993b6404 440 }
993b6404
JB
441 }
442
88c6e37e
GM
443 start_of_line_found:
444
993b6404
JB
445 if (tab_seen)
446 {
447 col = ((col + tab_width) / tab_width) * tab_width;
448 col += post_tab;
449 }
450
a997a7ca
KH
451 if (ptr == BEGV_ADDR)
452 current_column_bol_cache = BEGV;
453 else
fe0066f5
RS
454 current_column_bol_cache = BYTE_TO_CHAR (PTR_BYTE_POS (ptr));
455
993b6404 456 last_known_column = col;
6ec8bbd2 457 last_known_column_point = PT;
993b6404
JB
458 last_known_column_modified = MODIFF;
459
460 return col;
461}
462\f
80e3db56
SM
463
464/* Check the presence of a display property and compute its width.
465 If a property was found and its width was found as well, return
466 its width (>= 0) and set the position of the end of the property
467 in ENDPOS.
468 Otherwise just return -1. */
469static int
470check_display_width (EMACS_INT pos, EMACS_INT col, EMACS_INT *endpos)
471{
472 Lisp_Object val, overlay;
473
474 if (CONSP (val = get_char_property_and_overlay
475 (make_number (pos), Qdisplay, Qnil, &overlay))
476 && EQ (Qspace, XCAR (val)))
477 { /* FIXME: Use calc_pixel_width_or_height, as in term.c. */
478 Lisp_Object plist = XCDR (val), prop;
479 int width = -1;
480
481 if ((prop = Fplist_get (plist, QCwidth), NATNUMP (prop)))
482 width = XINT (prop);
483 else if (FLOATP (prop))
484 width = (int)(XFLOAT_DATA (prop) + 0.5);
485 else if ((prop = Fplist_get (plist, QCalign_to), NATNUMP (prop)))
486 width = XINT (prop) - col;
487 else if (FLOATP (prop))
488 width = (int)(XFLOAT_DATA (prop) + 0.5) - col;
409f2919 489
80e3db56
SM
490 if (width >= 0)
491 {
492 EMACS_INT start;
493 if (OVERLAYP (overlay))
494 *endpos = OVERLAY_POSITION (OVERLAY_END (overlay));
495 else
496 get_property_and_range (pos, Qdisplay, &val, &start, endpos, Qnil);
497 return width;
498 }
499 }
500 return -1;
501}
502
ef6f5c0e
SM
503/* Scanning from the beginning of the current line, stop at the buffer
504 position ENDPOS or at the column GOALCOL or at the end of line, whichever
505 comes first.
506 Return the resulting buffer position and column in ENDPOS and GOALCOL.
507 PREVCOL gets set to the column of the previous position (it's always
508 strictly smaller than the goal column). */
509static void
510scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
9a21bb64 511{
4b4deea2
TT
512 register EMACS_INT tab_width = XINT (BVAR (current_buffer, tab_width));
513 register int ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow));
9a21bb64 514 register struct Lisp_Char_Table *dp = buffer_display_table ();
4b4deea2 515 int multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters));
d6721dda 516 struct composition_it cmp_it;
fc88345b
KH
517 Lisp_Object window;
518 struct window *w;
9a21bb64
RS
519
520 /* Start the scan at the beginning of this line with column number 0. */
ef6f5c0e
SM
521 register EMACS_INT col = 0, prev_col = 0;
522 EMACS_INT goal = goalcol ? *goalcol : MOST_POSITIVE_FIXNUM;
523 EMACS_INT end = endpos ? *endpos : PT;
83155776
SM
524 EMACS_INT scan, scan_byte;
525 EMACS_INT next_boundary;
ef6f5c0e 526 {
83155776 527 EMACS_INT opoint = PT, opoint_byte = PT_BYTE;
813b81b3 528 scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1);
fe0066f5
RS
529 current_column_bol_cache = PT;
530 scan = PT, scan_byte = PT_BYTE;
531 SET_PT_BOTH (opoint, opoint_byte);
532 next_boundary = scan;
ef6f5c0e 533 }
9a21bb64 534
fc88345b
KH
535 window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
536 w = ! NILP (window) ? XWINDOW (window) : NULL;
537
9a21bb64 538 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
72af86bd 539 memset (&cmp_it, 0, sizeof cmp_it);
d6721dda
KH
540 cmp_it.id = -1;
541 composition_compute_stop_pos (&cmp_it, scan, scan_byte, end, Qnil);
9a21bb64
RS
542
543 /* Scan forward to the target position. */
ef6f5c0e 544 while (scan < end)
9a21bb64
RS
545 {
546 int c;
547
548 /* Occasionally we may need to skip invisible text. */
549 while (scan == next_boundary)
550 {
ef6f5c0e 551 EMACS_INT old_scan = scan;
9a21bb64
RS
552 /* This updates NEXT_BOUNDARY to the next place
553 where we might need to skip more invisible text. */
ef6f5c0e 554 scan = skip_invisible (scan, &next_boundary, end, Qnil);
fe0066f5
RS
555 if (scan != old_scan)
556 scan_byte = CHAR_TO_BYTE (scan);
ef6f5c0e
SM
557 if (scan >= end)
558 goto endloop;
9a21bb64
RS
559 }
560
ef6f5c0e
SM
561 /* Test reaching the goal column. We do this after skipping
562 invisible characters, so that we put point before the
563 character on which the cursor will appear. */
564 if (col >= goal)
565 break;
566 prev_col = col;
567
80e3db56 568 { /* Check display property. */
85f24f61
PE
569 EMACS_INT endp;
570 int width = check_display_width (scan, col, &endp);
80e3db56
SM
571 if (width >= 0)
572 {
573 col += width;
85f24f61 574 if (endp > scan) /* Avoid infinite loops with 0-width overlays. */
80e3db56 575 {
85f24f61 576 scan = endp; scan_byte = charpos_to_bytepos (scan);
80e3db56
SM
577 continue;
578 }
579 }
580 }
581
d6721dda
KH
582 /* Check composition sequence. */
583 if (cmp_it.id >= 0
584 || (scan == cmp_it.stop_pos
585 && composition_reseat_it (&cmp_it, scan, scan_byte, end,
fc88345b 586 w, NULL, Qnil)))
d6721dda
KH
587 composition_update_it (&cmp_it, scan, scan_byte, Qnil);
588 if (cmp_it.id >= 0)
589 {
590 scan += cmp_it.nchars;
591 scan_byte += cmp_it.nbytes;
592 if (scan <= end)
593 col += cmp_it.width;
594 if (cmp_it.to == cmp_it.nglyphs)
595 {
596 cmp_it.id = -1;
597 composition_compute_stop_pos (&cmp_it, scan, scan_byte, end,
598 Qnil);
599 }
600 else
601 cmp_it.from = cmp_it.to;
602 continue;
603 }
604
813b81b3 605 c = FETCH_BYTE (scan_byte);
88c6e37e 606
ef6f5c0e
SM
607 /* See if there is a display table and it relates
608 to this character. */
609
c9c0f7cf 610 if (dp != 0
409f2919 611 && ! (multibyte && LEADING_CODE_P (c))
c9c0f7cf 612 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
9a21bb64 613 {
d6e483a4
RS
614 Lisp_Object charvec;
615 EMACS_INT i, n;
616
617 /* This character is displayed using a vector of glyphs.
ef6f5c0e 618 Update the column/position based on those glyphs. */
d6e483a4 619
88c6e37e
GM
620 charvec = DISP_CHAR_VECTOR (dp, c);
621 n = ASIZE (charvec);
88c6e37e 622
d6e483a4 623 for (i = 0; i < n; i++)
88c6e37e
GM
624 {
625 /* This should be handled the same as
626 next_element_from_display_vector does it. */
f59836fe 627 Lisp_Object entry = AREF (charvec, i);
d6e483a4 628
f59836fe
KS
629 if (GLYPH_CODE_P (entry)
630 && GLYPH_CODE_CHAR_VALID_P (entry))
631 c = GLYPH_CODE_CHAR (entry);
88c6e37e
GM
632 else
633 c = ' ';
d6e483a4
RS
634
635 if (c == '\n')
636 goto endloop;
4b4deea2 637 if (c == '\r' && EQ (BVAR (current_buffer, selective_display), Qt))
d6e483a4
RS
638 goto endloop;
639 if (c == '\t')
640 {
d6e483a4
RS
641 col += tab_width;
642 col = col / tab_width * tab_width;
643 }
644 else
645 ++col;
88c6e37e 646 }
d6e483a4
RS
647 }
648 else
649 {
ef6f5c0e
SM
650 /* The display table doesn't affect this character;
651 it displays as itself. */
d6e483a4 652
88c6e37e
GM
653 if (c == '\n')
654 goto endloop;
4b4deea2 655 if (c == '\r' && EQ (BVAR (current_buffer, selective_display), Qt))
88c6e37e 656 goto endloop;
88c6e37e
GM
657 if (c == '\t')
658 {
88c6e37e
GM
659 col += tab_width;
660 col = col / tab_width * tab_width;
661 }
409f2919 662 else if (multibyte && LEADING_CODE_P (c))
88c6e37e 663 {
ef6f5c0e 664 /* Start of multi-byte form. */
88c6e37e 665 unsigned char *ptr;
c59478bc 666 int bytes, width;
097812fb 667
88c6e37e 668 ptr = BYTE_POS_ADDR (scan_byte);
85f24f61 669 MULTIBYTE_BYTES_WIDTH (ptr, dp, bytes, width);
36974b5e
RS
670 /* Subtract one to compensate for the increment
671 that is going to happen below. */
ef6f5c0e 672 scan_byte += bytes - 1;
88c6e37e
GM
673 col += width;
674 }
675 else if (ctl_arrow && (c < 040 || c == 0177))
676 col += 2;
677 else if (c < 040 || c >= 0177)
678 col += 4;
679 else
680 col++;
a997a7ca 681 }
d6e483a4
RS
682 scan++;
683 scan_byte++;
684
9a21bb64
RS
685 }
686 endloop:
687
688 last_known_column = col;
6ec8bbd2 689 last_known_column_point = PT;
9a21bb64
RS
690 last_known_column_modified = MODIFF;
691
ef6f5c0e
SM
692 if (goalcol)
693 *goalcol = col;
694 if (endpos)
695 *endpos = scan;
696 if (prevcol)
697 *prevcol = prev_col;
698}
699
700/* Return the column number of position POS
701 by scanning forward from the beginning of the line.
702 This function handles characters that are invisible
703 due to text properties or overlays. */
704
7831777b 705static EMACS_INT
971de7fb 706current_column_1 (void)
ef6f5c0e
SM
707{
708 EMACS_INT col = MOST_POSITIVE_FIXNUM;
709 EMACS_INT opoint = PT;
710
711 scan_for_column (&opoint, &col, NULL);
9a21bb64
RS
712 return col;
713}
714\f
f4a6687d
GM
715
716#if 0 /* Not used. */
717
c412c808
RS
718/* Return the width in columns of the part of STRING from BEG to END.
719 If BEG is nil, that stands for the beginning of STRING.
720 If END is nil, that stands for the end of STRING. */
721
76e20cb0 722static double
382ac0bd 723string_display_width (string, beg, end)
c412c808
RS
724 Lisp_Object string, beg, end;
725{
726 register int col;
727 register unsigned char *ptr, *stop;
728 register int tab_seen;
729 int post_tab;
730 register int c;
731 register int tab_width = XINT (current_buffer->tab_width);
732 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
d44f12b4 733 register struct Lisp_Char_Table *dp = buffer_display_table ();
c412c808
RS
734 int b, e;
735
736 if (NILP (end))
d5db4077 737 e = SCHARS (string);
c412c808
RS
738 else
739 {
b7826503 740 CHECK_NUMBER (end);
c412c808
RS
741 e = XINT (end);
742 }
743
744 if (NILP (beg))
745 b = 0;
746 else
747 {
b7826503 748 CHECK_NUMBER (beg);
c412c808
RS
749 b = XINT (beg);
750 }
751
752 /* Make a pointer for decrementing through the chars before point. */
d5db4077 753 ptr = SDATA (string) + e;
c412c808
RS
754 /* Make a pointer to where consecutive chars leave off,
755 going backwards from point. */
d5db4077 756 stop = SDATA (string) + b;
c412c808
RS
757
758 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
759
760 col = 0, tab_seen = 0, post_tab = 0;
761
762 while (1)
763 {
764 if (ptr == stop)
765 break;
766
767 c = *--ptr;
768 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
77b37c05 769 col += ASIZE (DISP_CHAR_VECTOR (dp, c));
c412c808
RS
770 else if (c >= 040 && c < 0177)
771 col++;
772 else if (c == '\n')
773 break;
774 else if (c == '\t')
775 {
776 if (tab_seen)
777 col = ((col + tab_width) / tab_width) * tab_width;
778
779 post_tab += col;
780 col = 0;
781 tab_seen = 1;
782 }
783 else
784 col += (ctl_arrow && c < 0200) ? 2 : 4;
785 }
786
787 if (tab_seen)
788 {
789 col = ((col + tab_width) / tab_width) * tab_width;
790 col += post_tab;
791 }
792
793 return col;
794}
f4a6687d
GM
795
796#endif /* 0 */
797
c412c808 798\f
a7ca3326 799DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
8c1a1077 800 doc: /* Indent from point with tabs and spaces until COLUMN is reached.
7bf120f1 801Optional second argument MINIMUM says always do at least MINIMUM spaces
f64f035e
EZ
802even if that goes past COLUMN; by default, MINIMUM is zero.
803
804The return value is COLUMN. */)
5842a27b 805 (Lisp_Object column, Lisp_Object minimum)
993b6404 806{
7831777b
PE
807 EMACS_INT mincol;
808 register EMACS_INT fromcol;
809 register EMACS_INT tab_width = XINT (BVAR (current_buffer, tab_width));
993b6404 810
b7826503 811 CHECK_NUMBER (column);
56a98455 812 if (NILP (minimum))
94d92e9c 813 XSETFASTINT (minimum, 0);
b7826503 814 CHECK_NUMBER (minimum);
993b6404
JB
815
816 fromcol = current_column ();
817 mincol = fromcol + XINT (minimum);
04c98432 818 if (mincol < XINT (column)) mincol = XINT (column);
993b6404
JB
819
820 if (fromcol == mincol)
821 return make_number (mincol);
822
ccdcf1f5 823 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
993b6404
JB
824
825 if (indent_tabs_mode)
826 {
827 Lisp_Object n;
94d92e9c 828 XSETFASTINT (n, mincol / tab_width - fromcol / tab_width);
993b6404
JB
829 if (XFASTINT (n) != 0)
830 {
6d1bd1a5 831 Finsert_char (make_number ('\t'), n, Qt);
993b6404
JB
832
833 fromcol = (mincol / tab_width) * tab_width;
834 }
835 }
836
04c98432
EN
837 XSETFASTINT (column, mincol - fromcol);
838 Finsert_char (make_number (' '), column, Qt);
993b6404
JB
839
840 last_known_column = mincol;
6ec8bbd2 841 last_known_column_point = PT;
993b6404
JB
842 last_known_column_modified = MODIFF;
843
04c98432
EN
844 XSETINT (column, mincol);
845 return column;
993b6404 846}
0aa01123 847
993b6404
JB
848\f
849DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
8c1a1077
PJ
850 0, 0, 0,
851 doc: /* Return the indentation of the current line.
852This is the horizontal position of the character
853following any initial whitespace. */)
5842a27b 854 (void)
993b6404
JB
855{
856 Lisp_Object val;
5816888b 857 EMACS_INT opoint = PT, opoint_byte = PT_BYTE;
fe0066f5
RS
858
859 scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1);
993b6404 860
7831777b 861 XSETFASTINT (val, position_indentation (PT_BYTE));
fe0066f5 862 SET_PT_BOTH (opoint, opoint_byte);
993b6404
JB
863 return val;
864}
865
7831777b 866static EMACS_INT
971de7fb 867position_indentation (register int pos_byte)
993b6404 868{
83155776 869 register EMACS_INT column = 0;
4b4deea2 870 register EMACS_INT tab_width = XINT (BVAR (current_buffer, tab_width));
993b6404
JB
871 register unsigned char *p;
872 register unsigned char *stop;
9a21bb64 873 unsigned char *start;
83155776
SM
874 EMACS_INT next_boundary_byte = pos_byte;
875 EMACS_INT ceiling = next_boundary_byte;
2ff4775b 876
ccdcf1f5 877 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
2ff4775b 878
fe0066f5 879 p = BYTE_POS_ADDR (pos_byte);
9a21bb64
RS
880 /* STOP records the value of P at which we will need
881 to think about the gap, or about invisible text,
882 or about the end of the buffer. */
883 stop = p;
884 /* START records the starting value of P. */
885 start = p;
993b6404
JB
886 while (1)
887 {
888 while (p == stop)
889 {
83155776 890 EMACS_INT stop_pos_byte;
9a21bb64 891
fe0066f5
RS
892 /* If we have updated P, set POS_BYTE to match.
893 The first time we enter the loop, POS_BYTE is already right. */
9a21bb64 894 if (p != start)
fe0066f5 895 pos_byte = PTR_BYTE_POS (p);
9a21bb64 896 /* Consider the various reasons STOP might have been set here. */
fe0066f5 897 if (pos_byte == ZV_BYTE)
993b6404 898 return column;
fe0066f5
RS
899 if (pos_byte == next_boundary_byte)
900 {
83155776
SM
901 EMACS_INT next_boundary;
902 EMACS_INT pos = BYTE_TO_CHAR (pos_byte);
fe0066f5
RS
903 pos = skip_invisible (pos, &next_boundary, ZV, Qnil);
904 pos_byte = CHAR_TO_BYTE (pos);
905 next_boundary_byte = CHAR_TO_BYTE (next_boundary);
906 }
907 if (pos_byte >= ceiling)
908 ceiling = BUFFER_CEILING_OF (pos_byte) + 1;
9a21bb64
RS
909 /* Compute the next place we need to stop and think,
910 and set STOP accordingly. */
fe0066f5 911 stop_pos_byte = min (ceiling, next_boundary_byte);
9a21bb64 912 /* The -1 and +1 arrange to point at the first byte of gap
fe0066f5 913 (if STOP_POS_BYTE is the position of the gap)
9a21bb64 914 rather than at the data after the gap. */
097812fb 915
fe0066f5
RS
916 stop = BYTE_POS_ADDR (stop_pos_byte - 1) + 1;
917 p = BYTE_POS_ADDR (pos_byte);
993b6404
JB
918 }
919 switch (*p++)
920 {
fb911777 921 case 0240:
4b4deea2 922 if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
fb911777 923 return column;
993b6404
JB
924 case ' ':
925 column++;
926 break;
927 case '\t':
928 column += tab_width - column % tab_width;
929 break;
930 default:
fb911777 931 if (ASCII_BYTE_P (p[-1])
4b4deea2 932 || NILP (BVAR (current_buffer, enable_multibyte_characters)))
fb911777
KH
933 return column;
934 {
fe0066f5
RS
935 int c;
936 pos_byte = PTR_BYTE_POS (p - 1);
937 c = FETCH_MULTIBYTE_CHAR (pos_byte);
fb911777
KH
938 if (CHAR_HAS_CATEGORY (c, ' '))
939 {
940 column++;
fe0066f5
RS
941 INC_POS (pos_byte);
942 p = BYTE_POS_ADDR (pos_byte);
fb911777
KH
943 }
944 else
945 return column;
946 }
993b6404
JB
947 }
948 }
949}
1b15e576
KH
950
951/* Test whether the line beginning at POS is indented beyond COLUMN.
952 Blank lines are treated as if they had the same indentation as the
953 preceding line. */
fe0066f5 954
1b15e576 955int
7831777b 956indented_beyond_p (EMACS_INT pos, EMACS_INT pos_byte, EMACS_INT column)
1b15e576 957{
7831777b 958 EMACS_INT val;
5816888b 959 EMACS_INT opoint = PT, opoint_byte = PT_BYTE;
fe0066f5
RS
960
961 SET_PT_BOTH (pos, pos_byte);
962 while (PT > BEGV && FETCH_BYTE (PT_BYTE) == '\n')
963 scan_newline (PT - 1, PT_BYTE - 1, BEGV, BEGV_BYTE, -1, 0);
964
d5d6f706 965 val = position_indentation (PT_BYTE);
fe0066f5 966 SET_PT_BOTH (opoint, opoint_byte);
7831777b 967 return val >= column;
1b15e576 968}
993b6404 969\f
a7ca3326 970DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, "p",
8c1a1077 971 doc: /* Move point to column COLUMN in the current line.
3c860543 972Interactively, COLUMN is the value of prefix numeric argument.
8c1a1077
PJ
973The column of a character is calculated by adding together the widths
974as displayed of the previous characters in the line.
975This function ignores line-continuation;
976there is no upper limit on the column number a character can have
977and horizontal scrolling has no effect.
978
979If specified column is within a character, point goes after that character.
980If it's past end of line, point goes to end of line.
981
3c860543
EZ
982Optional second argument FORCE non-nil means if COLUMN is in the
983middle of a tab character, change it to spaces.
984In addition, if FORCE is t, and the line is too short to reach
985COLUMN, add spaces/tabs to get there.
8c1a1077
PJ
986
987The return value is the current column. */)
5842a27b 988 (Lisp_Object column, Lisp_Object force)
993b6404 989{
ef6f5c0e
SM
990 EMACS_INT pos;
991 EMACS_INT col, prev_col;
992 EMACS_INT goal;
fe0066f5 993
b7826503 994 CHECK_NATNUM (column);
993b6404
JB
995 goal = XINT (column);
996
ef6f5c0e
SM
997 col = goal;
998 pos = ZV;
999 scan_for_column (&pos, &col, &prev_col);
993b6404 1000
ef6f5c0e 1001 SET_PT (pos);
4c669c09 1002
ef6f5c0e
SM
1003 /* If a tab char made us overshoot, change it to spaces
1004 and scan through it again. */
1005 if (!NILP (force) && col > goal)
993b6404 1006 {
4c92f429 1007 int c;
ef6f5c0e 1008 EMACS_INT pos_byte = PT_BYTE;
d6e483a4 1009
4c92f429
AS
1010 DEC_POS (pos_byte);
1011 c = FETCH_CHAR (pos_byte);
ef6f5c0e 1012 if (c == '\t' && prev_col < goal)
d6e483a4 1013 {
ef6f5c0e
SM
1014 EMACS_INT goal_pt, goal_pt_byte;
1015
1016 /* Insert spaces in front of the tab to reach GOAL. Do this
1017 first so that a marker at the end of the tab gets
1018 adjusted. */
1019 SET_PT_BOTH (PT - 1, PT_BYTE - 1);
1020 Finsert_char (make_number (' '), make_number (goal - prev_col), Qt);
1021
1022 /* Now delete the tab, and indent to COL. */
1023 del_range (PT, PT + 1);
1024 goal_pt = PT;
1025 goal_pt_byte = PT_BYTE;
1026 Findent_to (make_number (col), Qnil);
1027 SET_PT_BOTH (goal_pt, goal_pt_byte);
1028
1029 /* Set the last_known... vars consistently. */
1030 col = goal;
a997a7ca 1031 }
993b6404
JB
1032 }
1033
1034 /* If line ends prematurely, add space to the end. */
de4075cf 1035 if (col < goal && EQ (force, Qt))
230a4cbd 1036 Findent_to (make_number (col = goal), Qnil);
993b6404
JB
1037
1038 last_known_column = col;
6ec8bbd2 1039 last_known_column_point = PT;
993b6404
JB
1040 last_known_column_modified = MODIFF;
1041
ef6f5c0e 1042 return make_number (col);
993b6404
JB
1043}
1044\f
0aa01123
JB
1045/* compute_motion: compute buffer posn given screen posn and vice versa */
1046
9306c32e 1047static struct position val_compute_motion;
993b6404
JB
1048
1049/* Scan the current buffer forward from offset FROM, pretending that
1050 this is at line FROMVPOS, column FROMHPOS, until reaching buffer
1051 offset TO or line TOVPOS, column TOHPOS (whichever comes first),
0aa01123
JB
1052 and return the ending buffer position and screen location. If we
1053 can't hit the requested column exactly (because of a tab or other
1054 multi-column character), overshoot.
993b6404 1055
2ab90d49
KH
1056 DID_MOTION is 1 if FROMHPOS has already accounted for overlay strings
1057 at FROM. This is the case if FROMVPOS and FROMVPOS came from an
1058 earlier call to compute_motion. The other common case is that FROMHPOS
1059 is zero and FROM is a position that "belongs" at column zero, but might
1060 be shifted by overlay strings; in this case DID_MOTION should be 0.
1061
993b6404
JB
1062 WIDTH is the number of columns available to display text;
1063 compute_motion uses this to handle continuation lines and such.
361f14bf
KS
1064 If WIDTH is -1, use width of window's text area adjusted for
1065 continuation glyph when needed.
1066
993b6404
JB
1067 HSCROLL is the number of columns not being displayed at the left
1068 margin; this is usually taken from a window's hscroll member.
a9764248
JB
1069 TAB_OFFSET is the number of columns of the first tab that aren't
1070 being displayed, perhaps because of a continuation line or
1071 something.
993b6404
JB
1072
1073 compute_motion returns a pointer to a struct position. The bufpos
1074 member gives the buffer position at the end of the scan, and hpos
0aa01123
JB
1075 and vpos give its cartesian location. prevhpos is the column at
1076 which the character before bufpos started, and contin is non-zero
1077 if we reached the current line by continuing the previous.
1078
1079 Note that FROMHPOS and TOHPOS should be expressed in real screen
1080 columns, taking HSCROLL and the truncation glyph at the left margin
1081 into account. That is, beginning-of-line moves you to the hpos
1082 -HSCROLL + (HSCROLL > 0).
993b6404
JB
1083
1084 For example, to find the buffer position of column COL of line LINE
1085 of a certain window, pass the window's starting location as FROM
1086 and the window's upper-left coordinates as FROMVPOS and FROMHPOS.
1087 Pass the buffer's ZV as TO, to limit the scan to the end of the
1088 visible section of the buffer, and pass LINE and COL as TOVPOS and
2ff4775b 1089 TOHPOS.
993b6404
JB
1090
1091 When displaying in window w, a typical formula for WIDTH is:
1092
1093 window_width - 1
a3c87d4e 1094 - (has_vertical_scroll_bars
90022f5a
KS
1095 ? WINDOW_CONFIG_SCROLL_BAR_COLS (window)
1096 : (window_width + window_left != frame_cols))
993b6404
JB
1097
1098 where
90022f5a
KS
1099 window_width is XFASTINT (w->total_cols),
1100 window_left is XFASTINT (w->left_col),
a3c87d4e 1101 has_vertical_scroll_bars is
90022f5a
KS
1102 WINDOW_HAS_VERTICAL_SCROLL_BAR (window)
1103 and frame_cols = FRAME_COLS (XFRAME (window->frame))
993b6404 1104
abde8f8c
MR
1105 Or you can let window_body_cols do this all for you, and write:
1106 window_body_cols (w) - 1
fa61c701
JB
1107
1108 The `-1' accounts for the continuation-line backslashes; the rest
7e7a76b5 1109 accounts for window borders if the window is split horizontally, and
1827d036 1110 the scroll bars if they are turned on. */
993b6404
JB
1111
1112struct position *
971de7fb 1113compute_motion (EMACS_INT from, EMACS_INT fromvpos, EMACS_INT fromhpos, int did_motion, EMACS_INT to, EMACS_INT tovpos, EMACS_INT tohpos, EMACS_INT width, EMACS_INT hscroll, EMACS_INT tab_offset, struct window *win)
993b6404 1114{
83155776
SM
1115 register EMACS_INT hpos = fromhpos;
1116 register EMACS_INT vpos = fromvpos;
cde9337b 1117
83155776
SM
1118 register EMACS_INT pos;
1119 EMACS_INT pos_byte;
6bbd7a29 1120 register int c = 0;
4b4deea2
TT
1121 register EMACS_INT tab_width = XFASTINT (BVAR (current_buffer, tab_width));
1122 register int ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow));
d44f12b4 1123 register struct Lisp_Char_Table *dp = window_display_table (win);
7831777b 1124 EMACS_INT selective
4b4deea2
TT
1125 = (INTEGERP (BVAR (current_buffer, selective_display))
1126 ? XINT (BVAR (current_buffer, selective_display))
1127 : !NILP (BVAR (current_buffer, selective_display)) ? -1 : 0);
993b6404 1128 int selective_rlen
eeaafd4f 1129 = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
77b37c05 1130 ? ASIZE (DISP_INVIS_VECTOR (dp)) : 0);
2ab90d49
KH
1131 /* The next location where the `invisible' property changes, or an
1132 overlay starts or ends. */
83155776 1133 EMACS_INT next_boundary = from;
993b6404 1134
0aa01123
JB
1135 /* For computing runs of characters with similar widths.
1136 Invariant: width_run_width is zero, or all the characters
2ff4775b 1137 from width_run_start to width_run_end have a fixed width of
0aa01123 1138 width_run_width. */
83155776
SM
1139 EMACS_INT width_run_start = from;
1140 EMACS_INT width_run_end = from;
1141 EMACS_INT width_run_width = 0;
0aa01123 1142 Lisp_Object *width_table;
66c75ca5 1143 Lisp_Object buffer;
0aa01123
JB
1144
1145 /* The next buffer pos where we should consult the width run cache. */
83155776 1146 EMACS_INT next_width_run = from;
0e435804 1147 Lisp_Object window;
0aa01123 1148
4b4deea2 1149 int multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters));
c71c19f4
RS
1150 /* If previous char scanned was a wide character,
1151 this is the column where it ended. Otherwise, this is 0. */
83155776
SM
1152 EMACS_INT wide_column_end_hpos = 0;
1153 EMACS_INT prev_pos; /* Previous buffer position. */
1154 EMACS_INT prev_pos_byte; /* Previous buffer position. */
1155 EMACS_INT prev_hpos = 0;
1156 EMACS_INT prev_vpos = 0;
1157 EMACS_INT contin_hpos; /* HPOS of last column of continued line. */
1158 EMACS_INT prev_tab_offset; /* Previous tab offset. */
1159 EMACS_INT continuation_glyph_width;
a997a7ca 1160
d6721dda
KH
1161 struct composition_it cmp_it;
1162
66c75ca5 1163 XSETBUFFER (buffer, current_buffer);
0e435804 1164 XSETWINDOW (window, win);
66c75ca5 1165
0aa01123
JB
1166 width_run_cache_on_off ();
1167 if (dp == buffer_display_table ())
4b4deea2
TT
1168 width_table = (VECTORP (BVAR (current_buffer, width_table))
1169 ? XVECTOR (BVAR (current_buffer, width_table))->contents
0aa01123
JB
1170 : 0);
1171 else
1172 /* If the window has its own display table, we can't use the width
1173 run cache, because that's based on the buffer's display table. */
1174 width_table = 0;
1175
e4500116
GM
1176 if (tab_width <= 0 || tab_width > 1000)
1177 tab_width = 8;
1178
361f14bf
KS
1179 /* Negative width means use all available text columns. */
1180 if (width < 0)
1181 {
abde8f8c 1182 width = window_body_cols (win);
361f14bf
KS
1183 /* We must make room for continuation marks if we don't have fringes. */
1184#ifdef HAVE_WINDOW_SYSTEM
1185 if (!FRAME_WINDOW_P (XFRAME (win->frame)))
1186#endif
1187 width -= 1;
1188 }
1189
8cc08515 1190 continuation_glyph_width = 1;
ed5c373c 1191#ifdef HAVE_WINDOW_SYSTEM
8cc08515
KS
1192 if (FRAME_WINDOW_P (XFRAME (win->frame)))
1193 continuation_glyph_width = 0; /* In the fringe. */
ed5c373c
KS
1194#endif
1195
e4500116
GM
1196 immediate_quit = 1;
1197 QUIT;
cde9337b 1198
a997a7ca 1199 pos = prev_pos = from;
fe0066f5 1200 pos_byte = prev_pos_byte = CHAR_TO_BYTE (from);
a997a7ca
KH
1201 contin_hpos = 0;
1202 prev_tab_offset = tab_offset;
72af86bd 1203 memset (&cmp_it, 0, sizeof cmp_it);
d6721dda
KH
1204 cmp_it.id = -1;
1205 composition_compute_stop_pos (&cmp_it, pos, pos_byte, to, Qnil);
1206
2ab90d49
KH
1207 while (1)
1208 {
1209 while (pos == next_boundary)
f75c0f8a 1210 {
83155776
SM
1211 EMACS_INT pos_here = pos;
1212 EMACS_INT newpos;
98136db3 1213
f9ba10b0 1214 /* Don't skip invisible if we are already at the margin. */
8a00d895 1215 if (vpos > tovpos || (vpos == tovpos && hpos >= tohpos))
f9ba10b0
RS
1216 {
1217 if (contin_hpos && prev_hpos == 0
1218 && hpos > tohpos
1219 && (contin_hpos == width || wide_column_end_hpos > width))
1220 { /* Line breaks because we can't put the character at the
1221 previous line any more. It is not the multi-column
1222 character continued in middle. Go back to previous
1223 buffer position, screen position, and set tab offset
1224 to previous value. It's the beginning of the
1225 line. */
1226 pos = prev_pos;
1227 pos_byte = prev_pos_byte;
1228 hpos = prev_hpos;
6b61353c 1229 vpos = prev_vpos;
f9ba10b0
RS
1230 tab_offset = prev_tab_offset;
1231 }
1232 break;
1233 }
1234
2ab90d49
KH
1235 /* If the caller says that the screen position came from an earlier
1236 call to compute_motion, then we've already accounted for the
1237 overlay strings at point. This is only true the first time
1238 through, so clear the flag after testing it. */
1239 if (!did_motion)
1240 /* We need to skip past the overlay strings. Currently those
a997a7ca 1241 strings must not contain TAB;
2ab90d49
KH
1242 if we want to relax that restriction, something will have
1243 to be changed here. */
a997a7ca
KH
1244 {
1245 unsigned char *ovstr;
5816888b 1246 EMACS_INT ovlen = overlay_strings (pos, win, &ovstr);
4116deee 1247 hpos += ((multibyte && ovlen > 0)
7469ef5d 1248 ? strwidth ((char *) ovstr, ovlen) : ovlen);
a997a7ca 1249 }
2ab90d49
KH
1250 did_motion = 0;
1251
1252 if (pos >= to)
1253 break;
66c75ca5 1254
9a21bb64
RS
1255 /* Advance POS past invisible characters
1256 (but not necessarily all that there are here),
1257 and store in next_boundary the next position where
1258 we need to call skip_invisible. */
98136db3
RS
1259 newpos = skip_invisible (pos, &next_boundary, to, window);
1260
1261 if (newpos >= to)
e8cb089b
RS
1262 {
1263 pos = min (to, newpos);
bcfbd63d 1264 pos_byte = CHAR_TO_BYTE (pos);
e8cb089b
RS
1265 goto after_loop;
1266 }
98136db3 1267
fe0066f5
RS
1268 if (newpos != pos_here)
1269 {
1270 pos = newpos;
1271 pos_byte = CHAR_TO_BYTE (pos);
1272 }
f75c0f8a 1273 }
2ab90d49
KH
1274
1275 /* Handle right margin. */
a997a7ca
KH
1276 /* Note on a wide-column character.
1277
1278 Characters are classified into the following three categories
1279 according to the width (columns occupied on screen).
1280
1281 (1) single-column character: ex. `a'
1282 (2) multi-column character: ex. `^A', TAB, `\033'
1283 (3) wide-column character: ex. Japanese character, Chinese character
1284 (In the following example, `W_' stands for them.)
1285
1286 Multi-column characters can be divided around the right margin,
1287 but wide-column characters cannot.
1288
1289 NOTE:
1290
1291 (*) The cursor is placed on the next character after the point.
1292
1293 ----------
1294 abcdefghi\
1295 j ^---- next after the point
1296 ^--- next char. after the point.
1297 ----------
1298 In case of sigle-column character
1299
1300 ----------
1301 abcdefgh\\
1302 033 ^---- next after the point, next char. after the point.
1303 ----------
1304 In case of multi-column character
1305
1306 ----------
1307 abcdefgh\\
1308 W_ ^---- next after the point
1309 ^---- next char. after the point.
1310 ----------
097812fb 1311 In case of wide-column character
a997a7ca
KH
1312
1313 The problem here is continuation at a wide-column character.
1314 In this case, the line may shorter less than WIDTH.
1315 And we find the continuation AFTER it occurs.
1316
1317 */
1318
1319 if (hpos > width)
2ab90d49 1320 {
81b6a665
CY
1321 int total_width = width + continuation_glyph_width;
1322 int truncate = 0;
1323
1324 if (!NILP (Vtruncate_partial_width_windows)
1325 && (total_width < FRAME_COLS (XFRAME (WINDOW_FRAME (win)))))
1326 {
1327 if (INTEGERP (Vtruncate_partial_width_windows))
1328 truncate
1329 = total_width < XFASTINT (Vtruncate_partial_width_windows);
1330 else
1331 truncate = 1;
1332 }
1333
1334 if (hscroll || truncate
4b4deea2 1335 || !NILP (BVAR (current_buffer, truncate_lines)))
2ab90d49 1336 {
529724fe
AS
1337 /* Truncating: skip to newline, unless we are already past
1338 TO (we need to go back below). */
1339 if (pos <= to)
fe0066f5
RS
1340 {
1341 pos = find_before_next_newline (pos, to, 1);
1342 pos_byte = CHAR_TO_BYTE (pos);
529724fe
AS
1343 hpos = width;
1344 /* If we just skipped next_boundary,
1345 loop around in the main while
1346 and handle it. */
1347 if (pos >= next_boundary)
1348 next_boundary = pos + 1;
1349 prev_hpos = width;
6b61353c 1350 prev_vpos = vpos;
529724fe 1351 prev_tab_offset = tab_offset;
fe0066f5 1352 }
2ab90d49
KH
1353 }
1354 else
1355 {
1356 /* Continuing. */
a997a7ca
KH
1357 /* Remember the previous value. */
1358 prev_tab_offset = tab_offset;
1359
c9c0f7cf 1360 if (wide_column_end_hpos > width)
a997a7ca
KH
1361 {
1362 hpos -= prev_hpos;
1363 tab_offset += prev_hpos;
1364 }
1365 else
1366 {
1367 tab_offset += width;
1368 hpos -= width;
1369 }
1370 vpos++;
1371 contin_hpos = prev_hpos;
1372 prev_hpos = 0;
6cbc951e 1373 prev_vpos = vpos;
2ab90d49
KH
1374 }
1375 }
1376
1377 /* Stop if past the target buffer position or screen position. */
33fe7d20 1378 if (pos > to)
a997a7ca
KH
1379 {
1380 /* Go back to the previous position. */
1381 pos = prev_pos;
fe0066f5 1382 pos_byte = prev_pos_byte;
a997a7ca 1383 hpos = prev_hpos;
6b61353c 1384 vpos = prev_vpos;
a997a7ca
KH
1385 tab_offset = prev_tab_offset;
1386
1387 /* NOTE on contin_hpos, hpos, and prev_hpos.
1388
1389 ----------
1390 abcdefgh\\
1391 W_ ^---- contin_hpos
1392 | ^----- hpos
1393 \---- prev_hpos
1394 ----------
1395 */
1396
1397 if (contin_hpos && prev_hpos == 0
c9c0f7cf 1398 && contin_hpos < width && !wide_column_end_hpos)
a997a7ca
KH
1399 {
1400 /* Line breaking occurs in the middle of multi-column
1401 character. Go back to previous line. */
1402 hpos = contin_hpos;
1403 vpos = vpos - 1;
1404 }
a997a7ca
KH
1405 break;
1406 }
1407
8a00d895 1408 if (vpos > tovpos || (vpos == tovpos && hpos >= tohpos))
33fe7d20
RS
1409 {
1410 if (contin_hpos && prev_hpos == 0
9129bcc3
KH
1411 && hpos > tohpos
1412 && (contin_hpos == width || wide_column_end_hpos > width))
33fe7d20
RS
1413 { /* Line breaks because we can't put the character at the
1414 previous line any more. It is not the multi-column
1415 character continued in middle. Go back to previous
1416 buffer position, screen position, and set tab offset
1417 to previous value. It's the beginning of the
1418 line. */
1419 pos = prev_pos;
1420 pos_byte = prev_pos_byte;
1421 hpos = prev_hpos;
6b61353c 1422 vpos = prev_vpos;
33fe7d20
RS
1423 tab_offset = prev_tab_offset;
1424 }
1425 break;
1426 }
a997a7ca 1427 if (pos == ZV) /* We cannot go beyond ZV. Stop here. */
2ab90d49
KH
1428 break;
1429
2ab90d49 1430 prev_hpos = hpos;
6b61353c 1431 prev_vpos = vpos;
a997a7ca 1432 prev_pos = pos;
fe0066f5 1433 prev_pos_byte = pos_byte;
c9c0f7cf 1434 wide_column_end_hpos = 0;
0aa01123
JB
1435
1436 /* Consult the width run cache to see if we can avoid inspecting
1437 the text character-by-character. */
1438 if (current_buffer->width_run_cache && pos >= next_width_run)
1439 {
c098fdb8 1440 EMACS_INT run_end;
0aa01123
JB
1441 int common_width
1442 = region_cache_forward (current_buffer,
1443 current_buffer->width_run_cache,
1444 pos, &run_end);
1445
1446 /* A width of zero means the character's width varies (like
1447 a tab), is meaningless (like a newline), or we just don't
1448 want to skip over it for some other reason. */
1449 if (common_width != 0)
1450 {
5816888b 1451 EMACS_INT run_end_hpos;
0aa01123
JB
1452
1453 /* Don't go past the final buffer posn the user
1454 requested. */
1455 if (run_end > to)
1456 run_end = to;
1457
1458 run_end_hpos = hpos + (run_end - pos) * common_width;
1459
1460 /* Don't go past the final horizontal position the user
1461 requested. */
1462 if (vpos == tovpos && run_end_hpos > tohpos)
1463 {
1464 run_end = pos + (tohpos - hpos) / common_width;
1465 run_end_hpos = hpos + (run_end - pos) * common_width;
1466 }
2ff4775b 1467
0aa01123
JB
1468 /* Don't go past the margin. */
1469 if (run_end_hpos >= width)
1470 {
1471 run_end = pos + (width - hpos) / common_width;
1472 run_end_hpos = hpos + (run_end - pos) * common_width;
1473 }
1474
1475 hpos = run_end_hpos;
1476 if (run_end > pos)
1477 prev_hpos = hpos - common_width;
fe0066f5
RS
1478 if (pos != run_end)
1479 {
1480 pos = run_end;
1481 pos_byte = CHAR_TO_BYTE (pos);
1482 }
0aa01123
JB
1483 }
1484
1485 next_width_run = run_end + 1;
1486 }
1487
1488 /* We have to scan the text character-by-character. */
993b6404 1489 else
2ab90d49 1490 {
88c6e37e
GM
1491 EMACS_INT i, n;
1492 Lisp_Object charvec;
097812fb 1493
012fd715 1494 /* Check composition sequence. */
d6721dda
KH
1495 if (cmp_it.id >= 0
1496 || (pos == cmp_it.stop_pos
1497 && composition_reseat_it (&cmp_it, pos, pos_byte, to, win,
1498 NULL, Qnil)))
1499 composition_update_it (&cmp_it, pos, pos_byte, Qnil);
1500 if (cmp_it.id >= 0)
1501 {
1502 pos += cmp_it.nchars;
1503 pos_byte += cmp_it.nbytes;
1504 hpos += cmp_it.width;
1505 if (cmp_it.to == cmp_it.nglyphs)
1506 {
1507 cmp_it.id = -1;
1508 composition_compute_stop_pos (&cmp_it, pos, pos_byte, to,
1509 Qnil);
1510 }
1511 else
1512 cmp_it.from = cmp_it.to;
1513 continue;
1514 }
012fd715 1515
d6721dda 1516 c = FETCH_BYTE (pos_byte);
fe0066f5 1517 pos++, pos_byte++;
0aa01123 1518
2ab90d49
KH
1519 /* Perhaps add some info to the width_run_cache. */
1520 if (current_buffer->width_run_cache)
1521 {
1522 /* Is this character part of the current run? If so, extend
1523 the run. */
1524 if (pos - 1 == width_run_end
5db0afb7 1525 && XFASTINT (width_table[c]) == width_run_width)
2ab90d49
KH
1526 width_run_end = pos;
1527
1528 /* The previous run is over, since this is a character at a
1529 different position, or a different width. */
1530 else
1531 {
1532 /* Have we accumulated a run to put in the cache?
1533 (Currently, we only cache runs of width == 1). */
1534 if (width_run_start < width_run_end
1535 && width_run_width == 1)
1536 know_region_cache (current_buffer,
1537 current_buffer->width_run_cache,
1538 width_run_start, width_run_end);
1539
1540 /* Start recording a new width run. */
5db0afb7 1541 width_run_width = XFASTINT (width_table[c]);
2ab90d49
KH
1542 width_run_start = pos - 1;
1543 width_run_end = pos;
1544 }
1545 }
993b6404 1546
c9c0f7cf 1547 if (dp != 0
409f2919 1548 && ! (multibyte && LEADING_CODE_P (c))
c9c0f7cf 1549 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
993b6404 1550 {
88c6e37e
GM
1551 charvec = DISP_CHAR_VECTOR (dp, c);
1552 n = ASIZE (charvec);
993b6404 1553 }
88c6e37e 1554 else
993b6404 1555 {
88c6e37e
GM
1556 charvec = Qnil;
1557 n = 1;
1558 }
1559
1560 for (i = n - 1; i >= 0; --i)
1561 {
1562 if (VECTORP (charvec))
2ab90d49 1563 {
88c6e37e
GM
1564 /* This should be handled the same as
1565 next_element_from_display_vector does it. */
1566 Lisp_Object entry = AREF (charvec, i);
097812fb 1567
f59836fe
KS
1568 if (GLYPH_CODE_P (entry)
1569 && GLYPH_CODE_CHAR_VALID_P (entry))
1570 c = GLYPH_CODE_CHAR (entry);
88c6e37e
GM
1571 else
1572 c = ' ';
1573 }
097812fb 1574
88c6e37e
GM
1575 if (c >= 040 && c < 0177)
1576 hpos++;
1577 else if (c == '\t')
1578 {
1579 int tem = ((hpos + tab_offset + hscroll - (hscroll > 0))
1580 % tab_width);
1581 if (tem < 0)
1582 tem += tab_width;
1583 hpos += tab_width - tem;
1584 }
1585 else if (c == '\n')
1586 {
1587 if (selective > 0
7831777b 1588 && indented_beyond_p (pos, pos_byte, selective))
2ab90d49 1589 {
88c6e37e
GM
1590 /* If (pos == to), we don't have to take care of
1591 selective display. */
1592 if (pos < to)
fe0066f5 1593 {
88c6e37e
GM
1594 /* Skip any number of invisible lines all at once */
1595 do
1596 {
1597 pos = find_before_next_newline (pos, to, 1);
1598 if (pos < to)
1599 pos++;
1600 pos_byte = CHAR_TO_BYTE (pos);
1601 }
1602 while (pos < to
097812fb 1603 && indented_beyond_p (pos, pos_byte,
7831777b 1604 selective));
88c6e37e
GM
1605 /* Allow for the " ..." that is displayed for them. */
1606 if (selective_rlen)
1607 {
1608 hpos += selective_rlen;
1609 if (hpos >= width)
1610 hpos = width;
1611 }
1612 DEC_BOTH (pos, pos_byte);
1613 /* We have skipped the invis text, but not the
1614 newline after. */
fe0066f5 1615 }
2ab90d49 1616 }
88c6e37e
GM
1617 else
1618 {
1619 /* A visible line. */
1620 vpos++;
1621 hpos = 0;
1622 hpos -= hscroll;
1623 /* Count the truncation glyph on column 0 */
1624 if (hscroll > 0)
ed5c373c 1625 hpos += continuation_glyph_width;
88c6e37e
GM
1626 tab_offset = 0;
1627 }
1628 contin_hpos = 0;
2ab90d49 1629 }
88c6e37e 1630 else if (c == CR && selective < 0)
fe0066f5 1631 {
88c6e37e
GM
1632 /* In selective display mode,
1633 everything from a ^M to the end of the line is invisible.
1634 Stop *before* the real newline. */
1635 if (pos < to)
1636 {
1637 pos = find_before_next_newline (pos, to, 1);
1638 pos_byte = CHAR_TO_BYTE (pos);
1639 }
1640 /* If we just skipped next_boundary,
1641 loop around in the main while
1642 and handle it. */
1643 if (pos > next_boundary)
1644 next_boundary = pos;
1645 /* Allow for the " ..." that is displayed for them. */
1646 if (selective_rlen)
1647 {
1648 hpos += selective_rlen;
1649 if (hpos >= width)
1650 hpos = width;
1651 }
fe0066f5 1652 }
409f2919 1653 else if (multibyte && LEADING_CODE_P (c))
2ab90d49 1654 {
88c6e37e
GM
1655 /* Start of multi-byte form. */
1656 unsigned char *ptr;
c59478bc 1657 int mb_bytes, mb_width;
88c6e37e
GM
1658
1659 pos_byte--; /* rewind POS_BYTE */
1660 ptr = BYTE_POS_ADDR (pos_byte);
85f24f61
PE
1661 MULTIBYTE_BYTES_WIDTH (ptr, dp, mb_bytes, mb_width);
1662 pos_byte += mb_bytes;
c59478bc
PE
1663 if (mb_width > 1 && BYTES_BY_CHAR_HEAD (*ptr) == mb_bytes)
1664 wide_column_end_hpos = hpos + mb_width;
85f24f61 1665 hpos += mb_width;
2ab90d49 1666 }
f1004faf
GM
1667 else if (VECTORP (charvec))
1668 ++hpos;
88c6e37e
GM
1669 else
1670 hpos += (ctl_arrow && c < 0200) ? 2 : 4;
2ab90d49 1671 }
993b6404
JB
1672 }
1673 }
1674
98136db3
RS
1675 after_loop:
1676
0aa01123
JB
1677 /* Remember any final width run in the cache. */
1678 if (current_buffer->width_run_cache
1679 && width_run_width == 1
1680 && width_run_start < width_run_end)
1681 know_region_cache (current_buffer, current_buffer->width_run_cache,
1682 width_run_start, width_run_end);
1683
993b6404 1684 val_compute_motion.bufpos = pos;
fe0066f5 1685 val_compute_motion.bytepos = pos_byte;
cde9337b
JB
1686 val_compute_motion.hpos = hpos;
1687 val_compute_motion.vpos = vpos;
ef3af330
AS
1688 if (contin_hpos && prev_hpos == 0)
1689 val_compute_motion.prevhpos = contin_hpos;
1690 else
1691 val_compute_motion.prevhpos = prev_hpos;
927b5a55
RS
1692 /* We alalways handle all of them here; none of them remain to do. */
1693 val_compute_motion.ovstring_chars_done = 0;
993b6404
JB
1694
1695 /* Nonzero if have just continued a line */
a997a7ca 1696 val_compute_motion.contin = (contin_hpos && prev_hpos == 0);
993b6404 1697
e4500116 1698 immediate_quit = 0;
993b6404
JB
1699 return &val_compute_motion;
1700}
993b6404 1701
8720a429 1702
88af3af4 1703DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0,
8c1a1077
PJ
1704 doc: /* Scan through the current buffer, calculating screen position.
1705Scan the current buffer forward from offset FROM,
1706assuming it is at position FROMPOS--a cons of the form (HPOS . VPOS)--
1707to position TO or position TOPOS--another cons of the form (HPOS . VPOS)--
1708and return the ending buffer position and screen location.
1709
361f14bf
KS
1710If TOPOS is nil, the actual width and height of the window's
1711text area are used.
1712
8c1a1077
PJ
1713There are three additional arguments:
1714
1715WIDTH is the number of columns available to display text;
361f14bf
KS
1716this affects handling of continuation lines. A value of nil
1717corresponds to the actual number of available text columns.
8c1a1077
PJ
1718
1719OFFSETS is either nil or a cons cell (HSCROLL . TAB-OFFSET).
1720HSCROLL is the number of columns not being displayed at the left
1721margin; this is usually taken from a window's hscroll member.
1722TAB-OFFSET is the number of columns of the first tab that aren't
1723being displayed, perhaps because the line was continued within it.
1724If OFFSETS is nil, HSCROLL and TAB-OFFSET are assumed to be zero.
1725
1726WINDOW is the window to operate on. It is used to choose the display table;
1727if it is showing the current buffer, it is used also for
1728deciding which overlay properties apply.
1729Note that `compute-motion' always operates on the current buffer.
1730
1731The value is a list of five elements:
1732 (POS HPOS VPOS PREVHPOS CONTIN)
1733POS is the buffer position where the scan stopped.
1734VPOS is the vertical position where the scan stopped.
1735HPOS is the horizontal position where the scan stopped.
1736
1737PREVHPOS is the horizontal position one character back from POS.
1738CONTIN is t if a line was continued after (or within) the previous character.
1739
1740For example, to find the buffer position of column COL of line LINE
1741of a certain window, pass the window's starting location as FROM
1742and the window's upper-left coordinates as FROMPOS.
1743Pass the buffer's (point-max) as TO, to limit the scan to the end of the
1744visible section of the buffer, and pass LINE and COL as TOPOS. */)
5842a27b 1745 (Lisp_Object from, Lisp_Object frompos, Lisp_Object to, Lisp_Object topos, Lisp_Object width, Lisp_Object offsets, Lisp_Object window)
42918ba5 1746{
361f14bf 1747 struct window *w;
8798a92b 1748 Lisp_Object bufpos, hpos, vpos, prevhpos;
42918ba5
RS
1749 struct position *pos;
1750 int hscroll, tab_offset;
1751
b7826503
PJ
1752 CHECK_NUMBER_COERCE_MARKER (from);
1753 CHECK_CONS (frompos);
1754 CHECK_NUMBER_CAR (frompos);
1755 CHECK_NUMBER_CDR (frompos);
1756 CHECK_NUMBER_COERCE_MARKER (to);
361f14bf
KS
1757 if (!NILP (topos))
1758 {
1759 CHECK_CONS (topos);
1760 CHECK_NUMBER_CAR (topos);
1761 CHECK_NUMBER_CDR (topos);
1762 }
1763 if (!NILP (width))
1764 CHECK_NUMBER (width);
1765
42918ba5
RS
1766 if (!NILP (offsets))
1767 {
b7826503
PJ
1768 CHECK_CONS (offsets);
1769 CHECK_NUMBER_CAR (offsets);
1770 CHECK_NUMBER_CDR (offsets);
70949dac
KR
1771 hscroll = XINT (XCAR (offsets));
1772 tab_offset = XINT (XCDR (offsets));
42918ba5
RS
1773 }
1774 else
1775 hscroll = tab_offset = 0;
1776
88af3af4
KH
1777 if (NILP (window))
1778 window = Fselected_window ();
1779 else
b7826503 1780 CHECK_LIVE_WINDOW (window);
361f14bf 1781 w = XWINDOW (window);
88af3af4 1782
9fdae274
KH
1783 if (XINT (from) < BEGV || XINT (from) > ZV)
1784 args_out_of_range_3 (from, make_number (BEGV), make_number (ZV));
1785 if (XINT (to) < BEGV || XINT (to) > ZV)
1786 args_out_of_range_3 (to, make_number (BEGV), make_number (ZV));
1787
70949dac
KR
1788 pos = compute_motion (XINT (from), XINT (XCDR (frompos)),
1789 XINT (XCAR (frompos)), 0,
361f14bf
KS
1790 XINT (to),
1791 (NILP (topos)
1792 ? window_internal_height (w)
1793 : XINT (XCDR (topos))),
1794 (NILP (topos)
abde8f8c 1795 ? (window_body_cols (w)
361f14bf
KS
1796 - (
1797#ifdef HAVE_WINDOW_SYSTEM
1798 FRAME_WINDOW_P (XFRAME (w->frame)) ? 0 :
1799#endif
1800 1))
1801 : XINT (XCAR (topos))),
1802 (NILP (width) ? -1 : XINT (width)),
1803 hscroll, tab_offset,
88af3af4 1804 XWINDOW (window));
42918ba5 1805
94d92e9c 1806 XSETFASTINT (bufpos, pos->bufpos);
f8f645a1
KH
1807 XSETINT (hpos, pos->hpos);
1808 XSETINT (vpos, pos->vpos);
1809 XSETINT (prevhpos, pos->prevhpos);
42918ba5
RS
1810
1811 return Fcons (bufpos,
1812 Fcons (hpos,
1813 Fcons (vpos,
1814 Fcons (prevhpos,
1815 Fcons (pos->contin ? Qt : Qnil, Qnil)))));
1816
1817}
993b6404 1818\f
0aa01123 1819/* Fvertical_motion and vmotion */
88c6e37e 1820
9306c32e 1821static struct position val_vmotion;
993b6404
JB
1822
1823struct position *
971de7fb 1824vmotion (register EMACS_INT from, register EMACS_INT vtarget, struct window *w)
993b6404 1825{
83155776 1826 EMACS_INT hscroll = XINT (w->hscroll);
993b6404
JB
1827 struct position pos;
1828 /* vpos is cumulative vertical position, changed as from is changed */
1829 register int vpos = 0;
83155776
SM
1830 EMACS_INT prevline;
1831 register EMACS_INT first;
1832 EMACS_INT from_byte;
1833 EMACS_INT lmargin = hscroll > 0 ? 1 - hscroll : 0;
7831777b 1834 EMACS_INT selective
4b4deea2
TT
1835 = (INTEGERP (BVAR (current_buffer, selective_display))
1836 ? XINT (BVAR (current_buffer, selective_display))
1837 : !NILP (BVAR (current_buffer, selective_display)) ? -1 : 0);
99ce22d5 1838 Lisp_Object window;
83155776 1839 EMACS_INT start_hpos = 0;
2ab90d49 1840 int did_motion;
7ac57cb3
RS
1841 /* This is the object we use for fetching character properties. */
1842 Lisp_Object text_prop_object;
99ce22d5
KH
1843
1844 XSETWINDOW (window, w);
1845
7ac57cb3
RS
1846 /* If the window contains this buffer, use it for getting text properties.
1847 Otherwise use the current buffer as arg for doing that. */
1848 if (EQ (w->buffer, Fcurrent_buffer ()))
1849 text_prop_object = window;
1850 else
1851 text_prop_object = Fcurrent_buffer ();
1852
99ce22d5 1853 if (vpos >= vtarget)
993b6404 1854 {
99ce22d5 1855 /* To move upward, go a line at a time until
fe0066f5 1856 we have gone at least far enough. */
99ce22d5
KH
1857
1858 first = 1;
1859
1860 while ((vpos > vtarget || first) && from > BEGV)
993b6404 1861 {
66c75ca5
RS
1862 Lisp_Object propval;
1863
2965dff9
RS
1864 prevline = find_next_newline_no_quit (from - 1, -1);
1865 while (prevline > BEGV
5a05d3d2 1866 && ((selective > 0
2965dff9
RS
1867 && indented_beyond_p (prevline,
1868 CHAR_TO_BYTE (prevline),
7831777b 1869 selective))
2965dff9
RS
1870 /* Watch out for newlines with `invisible' property.
1871 When moving upward, check the newline before. */
1872 || (propval = Fget_char_property (make_number (prevline - 1),
66c75ca5 1873 Qinvisible,
7ac57cb3 1874 text_prop_object),
339ee979 1875 TEXT_PROP_MEANS_INVISIBLE (propval))))
2965dff9
RS
1876 prevline = find_next_newline_no_quit (prevline - 1, -1);
1877 pos = *compute_motion (prevline, 0,
1878 lmargin + (prevline == BEG ? start_hpos : 0),
2ab90d49 1879 0,
097812fb 1880 from,
a997a7ca
KH
1881 /* Don't care for VPOS... */
1882 1 << (BITS_PER_SHORT - 1),
1883 /* ... nor HPOS. */
1884 1 << (BITS_PER_SHORT - 1),
361f14bf 1885 -1, hscroll,
2dd4e608
RS
1886 /* This compensates for start_hpos
1887 so that a tab as first character
1888 still occupies 8 columns. */
2965dff9 1889 (prevline == BEG ? -start_hpos : 0),
2dd4e608 1890 w);
99ce22d5
KH
1891 vpos -= pos.vpos;
1892 first = 0;
2965dff9 1893 from = prevline;
993b6404 1894 }
99ce22d5
KH
1895
1896 /* If we made exactly the desired vertical distance,
1897 or if we hit beginning of buffer,
1898 return point found */
1899 if (vpos >= vtarget)
993b6404 1900 {
99ce22d5 1901 val_vmotion.bufpos = from;
fe0066f5 1902 val_vmotion.bytepos = CHAR_TO_BYTE (from);
99ce22d5
KH
1903 val_vmotion.vpos = vpos;
1904 val_vmotion.hpos = lmargin;
1905 val_vmotion.contin = 0;
1906 val_vmotion.prevhpos = 0;
927b5a55 1907 val_vmotion.ovstring_chars_done = 0;
a997a7ca 1908 val_vmotion.tab_offset = 0; /* For accumulating tab offset. */
99ce22d5 1909 return &val_vmotion;
993b6404 1910 }
993b6404 1911
99ce22d5
KH
1912 /* Otherwise find the correct spot by moving down */
1913 }
1914 /* Moving downward is simple, but must calculate from beg of line
1915 to determine hpos of starting point */
fe0066f5
RS
1916 from_byte = CHAR_TO_BYTE (from);
1917 if (from > BEGV && FETCH_BYTE (from_byte - 1) != '\n')
993b6404 1918 {
2ab90d49 1919 Lisp_Object propval;
66c75ca5 1920
2965dff9
RS
1921 prevline = find_next_newline_no_quit (from, -1);
1922 while (prevline > BEGV
99ce22d5 1923 && ((selective > 0
2965dff9
RS
1924 && indented_beyond_p (prevline,
1925 CHAR_TO_BYTE (prevline),
7831777b 1926 selective))
2965dff9
RS
1927 /* Watch out for newlines with `invisible' property.
1928 When moving downward, check the newline after. */
1929 || (propval = Fget_char_property (make_number (prevline),
1930 Qinvisible,
7ac57cb3 1931 text_prop_object),
339ee979 1932 TEXT_PROP_MEANS_INVISIBLE (propval))))
2965dff9
RS
1933 prevline = find_next_newline_no_quit (prevline - 1, -1);
1934 pos = *compute_motion (prevline, 0,
1935 lmargin + (prevline == BEG
92992c7e 1936 ? start_hpos : 0),
2ab90d49 1937 0,
097812fb 1938 from,
a997a7ca
KH
1939 /* Don't care for VPOS... */
1940 1 << (BITS_PER_SHORT - 1),
1941 /* ... nor HPOS. */
1942 1 << (BITS_PER_SHORT - 1),
361f14bf 1943 -1, hscroll,
2965dff9 1944 (prevline == BEG ? -start_hpos : 0),
2dd4e608 1945 w);
2ab90d49 1946 did_motion = 1;
993b6404 1947 }
99ce22d5 1948 else
993b6404 1949 {
99ce22d5
KH
1950 pos.hpos = lmargin + (from == BEG ? start_hpos : 0);
1951 pos.vpos = 0;
a997a7ca 1952 pos.tab_offset = 0;
2ab90d49 1953 did_motion = 0;
993b6404 1954 }
2ab90d49 1955 return compute_motion (from, vpos, pos.hpos, did_motion,
a997a7ca 1956 ZV, vtarget, - (1 << (BITS_PER_SHORT - 1)),
361f14bf 1957 -1, hscroll,
a997a7ca 1958 pos.tab_offset - (from == BEG ? start_hpos : 0),
2dd4e608 1959 w);
993b6404
JB
1960}
1961
a7ca3326 1962DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 2, 0,
8c1a1077
PJ
1963 doc: /* Move point to start of the screen line LINES lines down.
1964If LINES is negative, this means moving up.
1965
1966This function is an ordinary cursor motion function
1967which calculates the new position based on how text would be displayed.
1968The new position may be the start of a line,
1969or just the start of a continuation line.
1970The function returns number of screen lines moved over;
1971that usually equals LINES, but may be closer to zero
1972if beginning or end of buffer was reached.
1973
1974The optional second argument WINDOW specifies the window to use for
1975parameters such as width, horizontal scrolling, and so on.
1976The default is to use the selected window's parameters.
1977
c876b227
SM
1978LINES can optionally take the form (COLS . LINES), in which case
1979the motion will not stop at the start of a screen line but on
1980its column COLS (if such exists on that line, that is).
1981
8c1a1077
PJ
1982`vertical-motion' always uses the current buffer,
1983regardless of which buffer is displayed in WINDOW.
1984This is consistent with other cursor motion functions
1985and makes it possible to use `vertical-motion' in any buffer,
1986whether or not it is currently displayed in some window. */)
5842a27b 1987 (Lisp_Object lines, Lisp_Object window)
993b6404 1988{
8720a429
GM
1989 struct it it;
1990 struct text_pos pt;
8720a429 1991 struct window *w;
39210e90
GM
1992 Lisp_Object old_buffer;
1993 struct gcpro gcpro1;
baed8445 1994 Lisp_Object lcols = Qnil;
5671df8f 1995 double cols IF_LINT (= 0);
c876b227
SM
1996
1997 /* Allow LINES to be of the form (HPOS . VPOS) aka (COLUMNS . LINES). */
1998 if (CONSP (lines) && (NUMBERP (XCAR (lines))))
1999 {
baed8445
SM
2000 lcols = XCAR (lines);
2001 cols = INTEGERP (lcols) ? (double) XINT (lcols) : XFLOAT_DATA (lcols);
c876b227
SM
2002 lines = XCDR (lines);
2003 }
993b6404 2004
b7826503 2005 CHECK_NUMBER (lines);
f1ecfe9b 2006 if (! NILP (window))
b7826503 2007 CHECK_WINDOW (window);
f1ecfe9b 2008 else
92992c7e 2009 window = selected_window;
8720a429 2010 w = XWINDOW (window);
39210e90
GM
2011
2012 old_buffer = Qnil;
2013 GCPRO1 (old_buffer);
2014 if (XBUFFER (w->buffer) != current_buffer)
8720a429 2015 {
39210e90
GM
2016 /* Set the window's buffer temporarily to the current buffer. */
2017 old_buffer = w->buffer;
2018 XSETBUFFER (w->buffer, current_buffer);
8720a429 2019 }
097812fb 2020
6df71429 2021 if (noninteractive)
9305b0e7 2022 {
6df71429
RS
2023 struct position pos;
2024 pos = *vmotion (PT, XINT (lines), w);
2025 SET_PT_BOTH (pos.bufpos, pos.bytepos);
9305b0e7
KS
2026 }
2027 else
6df71429 2028 {
d1dfb56c
EZ
2029 EMACS_INT it_start;
2030 int first_x, it_overshoot_expected IF_LINT (= 0);
24a06d04 2031
6df71429
RS
2032 SET_TEXT_POS (pt, PT, PT_BYTE);
2033 start_display (&it, w, pt);
2f4ec7ce 2034 first_x = it.first_visible_x;
24a06d04 2035 it_start = IT_CHARPOS (it);
14a7cabf 2036
48cdfb4b
CY
2037 /* See comments below for why we calculate this. */
2038 if (XINT (lines) > 0)
14a7cabf 2039 {
d6721dda
KH
2040 if (it.cmp_it.id >= 0)
2041 it_overshoot_expected = 1;
187bc86f 2042 else if (it.method == GET_FROM_STRING)
48cdfb4b 2043 {
42a5b22f 2044 const char *s = SSDATA (it.string);
48cdfb4b
CY
2045 const char *e = s + SBYTES (it.string);
2046 while (s < e && *s != '\n')
2047 ++s;
2048 it_overshoot_expected = (s == e) ? -1 : 0;
2049 }
2050 else
2051 it_overshoot_expected = (it.method == GET_FROM_IMAGE
d6721dda 2052 || it.method == GET_FROM_STRETCH);
14a7cabf 2053 }
14a7cabf 2054
48cdfb4b
CY
2055 /* Scan from the start of the line containing PT. If we don't
2056 do this, we start moving with IT->current_x == 0, while PT is
2057 really at some x > 0. */
b54a7539
KS
2058 reseat_at_previous_visible_line_start (&it);
2059 it.current_x = it.hpos = 0;
af2be002 2060 if (IT_CHARPOS (it) != PT)
11fb10de
CY
2061 /* We used to temporarily disable selective display here; the
2062 comment said this is "so we don't move too far" (2005-01-19
2063 checkin by kfs). But this does nothing useful that I can
2064 tell, and it causes Bug#2694 . -- cyd */
2065 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
b54a7539 2066
48cdfb4b 2067 if (XINT (lines) <= 0)
72ad106b 2068 {
48cdfb4b
CY
2069 it.vpos = 0;
2070 /* Do this even if LINES is 0, so that we move back to the
2071 beginning of the current line as we ought. */
2072 if (XINT (lines) == 0 || IT_CHARPOS (it) > 0)
e4cc2dfc 2073 move_it_by_lines (&it, XINT (lines));
48cdfb4b
CY
2074 }
2075 else
2076 {
2421af7e 2077 if (IT_CHARPOS (it) > it_start)
48cdfb4b
CY
2078 {
2079 /* IT may move too far if truncate-lines is on and PT
2080 lies beyond the right margin. In that case,
2081 backtrack unless the starting point is on an image,
2082 stretch glyph, composition, or Lisp string. */
2083 if (!it_overshoot_expected
2084 /* Also, backtrack if the Lisp string contains no
2085 newline, but there is a newline right after it.
2086 In this case, IT overshoots if there is an
2087 after-string just before the newline. */
2088 || (it_overshoot_expected < 0
2089 && it.method == GET_FROM_BUFFER
2090 && it.c == '\n'))
e4cc2dfc 2091 move_it_by_lines (&it, -1);
48cdfb4b 2092 it.vpos = 0;
e4cc2dfc 2093 move_it_by_lines (&it, XINT (lines));
48cdfb4b
CY
2094 }
2095 else
2096 {
2097 /* Otherwise, we are at the first row occupied by PT,
2098 which might span multiple screen lines (e.g., if it's
2099 on a multi-line display string). We want to start
2100 from the last line that it occupies. */
051facec 2101 if (it_start < ZV)
48cdfb4b 2102 {
2421af7e 2103 while (IT_CHARPOS (it) <= it_start)
d8a7e7fc
CY
2104 {
2105 it.vpos = 0;
e4cc2dfc 2106 move_it_by_lines (&it, 1);
d8a7e7fc
CY
2107 }
2108 if (XINT (lines) > 1)
e4cc2dfc 2109 move_it_by_lines (&it, XINT (lines) - 1);
48cdfb4b
CY
2110 }
2111 else
d8a7e7fc
CY
2112 {
2113 it.vpos = 0;
e4cc2dfc 2114 move_it_by_lines (&it, XINT (lines));
d8a7e7fc 2115 }
48cdfb4b 2116 }
72ad106b 2117 }
097812fb 2118
2f4ec7ce 2119 /* Move to the goal column, if one was specified. */
baed8445 2120 if (!NILP (lcols))
2f4ec7ce
CY
2121 {
2122 /* If the window was originally hscrolled, move forward by
2123 the hscrolled amount first. */
2124 if (first_x > 0)
2125 {
2126 move_it_in_display_line (&it, ZV, first_x, MOVE_TO_X);
2127 it.current_x = 0;
2128 }
2129 move_it_in_display_line
2130 (&it, ZV,
2131 (int)(cols * FRAME_COLUMN_WIDTH (XFRAME (w->frame)) + 0.5),
2132 MOVE_TO_X);
2133 }
c876b227 2134
6df71429
RS
2135 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
2136 }
8720a429 2137
39210e90
GM
2138 if (BUFFERP (old_buffer))
2139 w->buffer = old_buffer;
097812fb 2140
39210e90 2141 RETURN_UNGCPRO (make_number (it.vpos));
993b6404 2142}
8720a429
GM
2143
2144
993b6404 2145\f
88c6e37e 2146/* File's initialization. */
0aa01123 2147
dfcf069d 2148void
971de7fb 2149syms_of_indent (void)
993b6404 2150{
29208e82 2151 DEFVAR_BOOL ("indent-tabs-mode", indent_tabs_mode,
c86f7377 2152 doc: /* *Indentation can insert tabs if this is non-nil. */);
993b6404
JB
2153 indent_tabs_mode = 1;
2154
2155 defsubr (&Scurrent_indentation);
2156 defsubr (&Sindent_to);
2157 defsubr (&Scurrent_column);
2158 defsubr (&Smove_to_column);
2159 defsubr (&Svertical_motion);
42918ba5 2160 defsubr (&Scompute_motion);
993b6404 2161}