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