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