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