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