(echo-area-clear-hook): Undo Oct 29 change.
[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 330DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
8c1a1077
PJ
331 doc: /* Return the horizontal position of point. Beginning of line is column 0.
332This is calculated by adding together the widths of all the displayed
333representations of the character between the start of the previous line
334and point. (eg control characters will have a width of 2 or 4, tabs
335will have a variable width)
336Ignores finite width of frame, which means that this function may return
337values greater than (frame-width).
338Whether the line is visible (if `selective-display' is t) has no effect;
339however, ^M is treated as end of line when `selective-display' is t. */)
340 ()
993b6404
JB
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;
529
530 /* Occasionally we may need to skip invisible text. */
531 while (scan == next_boundary)
532 {
fe0066f5 533 int old_scan = scan;
9a21bb64
RS
534 /* This updates NEXT_BOUNDARY to the next place
535 where we might need to skip more invisible text. */
813b81b3
RS
536 scan = skip_invisible (scan, &next_boundary, opoint, Qnil);
537 if (scan >= opoint)
9a21bb64 538 goto endloop;
fe0066f5
RS
539 if (scan != old_scan)
540 scan_byte = CHAR_TO_BYTE (scan);
541 next_boundary_byte = CHAR_TO_BYTE (next_boundary);
9a21bb64
RS
542 }
543
012fd715
KH
544 /* Check composition sequence. */
545 {
546 int len, len_byte, width;
547
548 if (check_composition (scan, scan_byte, opoint,
549 &len, &len_byte, &width))
550 {
551 scan += len;
552 scan_byte += len_byte;
553 if (scan <= opoint)
554 col += width;
555 continue;
556 }
557 }
558
813b81b3 559 c = FETCH_BYTE (scan_byte);
88c6e37e 560
c9c0f7cf
KH
561 if (dp != 0
562 && ! (multibyte && BASE_LEADING_CODE_P (c))
563 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
9a21bb64 564 {
d6e483a4
RS
565 Lisp_Object charvec;
566 EMACS_INT i, n;
567
568 /* This character is displayed using a vector of glyphs.
569 Update the column based on those glyphs. */
570
88c6e37e
GM
571 charvec = DISP_CHAR_VECTOR (dp, c);
572 n = ASIZE (charvec);
88c6e37e 573
d6e483a4 574 for (i = 0; i < n; i++)
88c6e37e
GM
575 {
576 /* This should be handled the same as
577 next_element_from_display_vector does it. */
d6e483a4
RS
578 Lisp_Object entry;
579 entry = AREF (charvec, i);
580
88c6e37e
GM
581 if (INTEGERP (entry)
582 && GLYPH_CHAR_VALID_P (XFASTINT (entry)))
583 c = FAST_GLYPH_CHAR (XFASTINT (entry));
584 else
585 c = ' ';
d6e483a4
RS
586
587 if (c == '\n')
588 goto endloop;
589 if (c == '\r' && EQ (current_buffer->selective_display, Qt))
590 goto endloop;
591 if (c == '\t')
592 {
593 int prev_col = col;
594 col += tab_width;
595 col = col / tab_width * tab_width;
596 }
597 else
598 ++col;
88c6e37e 599 }
d6e483a4
RS
600 }
601 else
602 {
603 /* The display table says nothing for this character.
604 Display it as itself. */
605
88c6e37e
GM
606 if (c == '\n')
607 goto endloop;
608 if (c == '\r' && EQ (current_buffer->selective_display, Qt))
609 goto endloop;
88c6e37e
GM
610 if (c == '\t')
611 {
612 int prev_col = col;
613 col += tab_width;
614 col = col / tab_width * tab_width;
615 }
616 else if (multibyte && BASE_LEADING_CODE_P (c))
617 {
618 unsigned char *ptr;
619 int bytes, width, wide_column;
620
621 scan_byte--;
622 ptr = BYTE_POS_ADDR (scan_byte);
623 MULTIBYTE_BYTES_WIDTH (ptr, dp);
624 scan_byte += bytes;
625 col += width;
626 }
627 else if (ctl_arrow && (c < 040 || c == 0177))
628 col += 2;
629 else if (c < 040 || c >= 0177)
630 col += 4;
631 else
632 col++;
a997a7ca 633 }
d6e483a4
RS
634 scan++;
635 scan_byte++;
636
9a21bb64
RS
637 }
638 endloop:
639
640 last_known_column = col;
6ec8bbd2 641 last_known_column_point = PT;
9a21bb64
RS
642 last_known_column_modified = MODIFF;
643
644 return col;
645}
646\f
f4a6687d
GM
647
648#if 0 /* Not used. */
649
c412c808
RS
650/* Return the width in columns of the part of STRING from BEG to END.
651 If BEG is nil, that stands for the beginning of STRING.
652 If END is nil, that stands for the end of STRING. */
653
654static int
382ac0bd 655string_display_width (string, beg, end)
c412c808
RS
656 Lisp_Object string, beg, end;
657{
658 register int col;
659 register unsigned char *ptr, *stop;
660 register int tab_seen;
661 int post_tab;
662 register int c;
663 register int tab_width = XINT (current_buffer->tab_width);
664 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
d44f12b4 665 register struct Lisp_Char_Table *dp = buffer_display_table ();
c412c808
RS
666 int b, e;
667
668 if (NILP (end))
669 e = XSTRING (string)->size;
670 else
671 {
b7826503 672 CHECK_NUMBER (end);
c412c808
RS
673 e = XINT (end);
674 }
675
676 if (NILP (beg))
677 b = 0;
678 else
679 {
b7826503 680 CHECK_NUMBER (beg);
c412c808
RS
681 b = XINT (beg);
682 }
683
684 /* Make a pointer for decrementing through the chars before point. */
685 ptr = XSTRING (string)->data + e;
686 /* Make a pointer to where consecutive chars leave off,
687 going backwards from point. */
688 stop = XSTRING (string)->data + b;
689
690 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
691
692 col = 0, tab_seen = 0, post_tab = 0;
693
694 while (1)
695 {
696 if (ptr == stop)
697 break;
698
699 c = *--ptr;
700 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
701 col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
702 else if (c >= 040 && c < 0177)
703 col++;
704 else if (c == '\n')
705 break;
706 else if (c == '\t')
707 {
708 if (tab_seen)
709 col = ((col + tab_width) / tab_width) * tab_width;
710
711 post_tab += col;
712 col = 0;
713 tab_seen = 1;
714 }
715 else
716 col += (ctl_arrow && c < 0200) ? 2 : 4;
717 }
718
719 if (tab_seen)
720 {
721 col = ((col + tab_width) / tab_width) * tab_width;
722 col += post_tab;
723 }
724
725 return col;
726}
f4a6687d
GM
727
728#endif /* 0 */
729
c412c808 730\f
993b6404 731DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
8c1a1077
PJ
732 doc: /* Indent from point with tabs and spaces until COLUMN is reached.
733Optional second argument MININUM says always do at least MININUM spaces
734even if that goes past COLUMN; by default, MININUM is zero. */)
735 (column, minimum)
04c98432 736 Lisp_Object column, minimum;
993b6404
JB
737{
738 int mincol;
739 register int fromcol;
740 register int tab_width = XINT (current_buffer->tab_width);
741
b7826503 742 CHECK_NUMBER (column);
56a98455 743 if (NILP (minimum))
94d92e9c 744 XSETFASTINT (minimum, 0);
b7826503 745 CHECK_NUMBER (minimum);
993b6404
JB
746
747 fromcol = current_column ();
748 mincol = fromcol + XINT (minimum);
04c98432 749 if (mincol < XINT (column)) mincol = XINT (column);
993b6404
JB
750
751 if (fromcol == mincol)
752 return make_number (mincol);
753
ccdcf1f5 754 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
993b6404
JB
755
756 if (indent_tabs_mode)
757 {
758 Lisp_Object n;
94d92e9c 759 XSETFASTINT (n, mincol / tab_width - fromcol / tab_width);
993b6404
JB
760 if (XFASTINT (n) != 0)
761 {
6d1bd1a5 762 Finsert_char (make_number ('\t'), n, Qt);
993b6404
JB
763
764 fromcol = (mincol / tab_width) * tab_width;
765 }
766 }
767
04c98432
EN
768 XSETFASTINT (column, mincol - fromcol);
769 Finsert_char (make_number (' '), column, Qt);
993b6404
JB
770
771 last_known_column = mincol;
6ec8bbd2 772 last_known_column_point = PT;
993b6404
JB
773 last_known_column_modified = MODIFF;
774
04c98432
EN
775 XSETINT (column, mincol);
776 return column;
993b6404 777}
0aa01123 778
993b6404 779\f
dfcf069d
AS
780static int position_indentation P_ ((int));
781
993b6404 782DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
8c1a1077
PJ
783 0, 0, 0,
784 doc: /* Return the indentation of the current line.
785This is the horizontal position of the character
786following any initial whitespace. */)
787 ()
993b6404
JB
788{
789 Lisp_Object val;
fe0066f5
RS
790 int opoint = PT, opoint_byte = PT_BYTE;
791
792 scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1);
993b6404 793
fe0066f5
RS
794 XSETFASTINT (val, position_indentation (PT_BYTE));
795 SET_PT_BOTH (opoint, opoint_byte);
993b6404
JB
796 return val;
797}
798
fe0066f5
RS
799static int
800position_indentation (pos_byte)
801 register int pos_byte;
993b6404
JB
802{
803 register int column = 0;
804 register int tab_width = XINT (current_buffer->tab_width);
805 register unsigned char *p;
806 register unsigned char *stop;
9a21bb64 807 unsigned char *start;
fe0066f5
RS
808 int next_boundary_byte = pos_byte;
809 int ceiling = next_boundary_byte;
2ff4775b 810
ccdcf1f5 811 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
2ff4775b 812
fe0066f5 813 p = BYTE_POS_ADDR (pos_byte);
9a21bb64
RS
814 /* STOP records the value of P at which we will need
815 to think about the gap, or about invisible text,
816 or about the end of the buffer. */
817 stop = p;
818 /* START records the starting value of P. */
819 start = p;
993b6404
JB
820 while (1)
821 {
822 while (p == stop)
823 {
fe0066f5 824 int stop_pos_byte;
9a21bb64 825
fe0066f5
RS
826 /* If we have updated P, set POS_BYTE to match.
827 The first time we enter the loop, POS_BYTE is already right. */
9a21bb64 828 if (p != start)
fe0066f5 829 pos_byte = PTR_BYTE_POS (p);
9a21bb64 830 /* Consider the various reasons STOP might have been set here. */
fe0066f5 831 if (pos_byte == ZV_BYTE)
993b6404 832 return column;
fe0066f5
RS
833 if (pos_byte == next_boundary_byte)
834 {
835 int next_boundary;
836 int pos = BYTE_TO_CHAR (pos_byte);
837 pos = skip_invisible (pos, &next_boundary, ZV, Qnil);
838 pos_byte = CHAR_TO_BYTE (pos);
839 next_boundary_byte = CHAR_TO_BYTE (next_boundary);
840 }
841 if (pos_byte >= ceiling)
842 ceiling = BUFFER_CEILING_OF (pos_byte) + 1;
9a21bb64
RS
843 /* Compute the next place we need to stop and think,
844 and set STOP accordingly. */
fe0066f5 845 stop_pos_byte = min (ceiling, next_boundary_byte);
9a21bb64 846 /* The -1 and +1 arrange to point at the first byte of gap
fe0066f5 847 (if STOP_POS_BYTE is the position of the gap)
9a21bb64
RS
848 rather than at the data after the gap. */
849
fe0066f5
RS
850 stop = BYTE_POS_ADDR (stop_pos_byte - 1) + 1;
851 p = BYTE_POS_ADDR (pos_byte);
993b6404
JB
852 }
853 switch (*p++)
854 {
fb911777
KH
855 case 0240:
856 if (! NILP (current_buffer->enable_multibyte_characters))
857 return column;
993b6404
JB
858 case ' ':
859 column++;
860 break;
861 case '\t':
862 column += tab_width - column % tab_width;
863 break;
864 default:
fb911777
KH
865 if (ASCII_BYTE_P (p[-1])
866 || NILP (current_buffer->enable_multibyte_characters))
867 return column;
868 {
fe0066f5
RS
869 int c;
870 pos_byte = PTR_BYTE_POS (p - 1);
871 c = FETCH_MULTIBYTE_CHAR (pos_byte);
fb911777
KH
872 if (CHAR_HAS_CATEGORY (c, ' '))
873 {
874 column++;
fe0066f5
RS
875 INC_POS (pos_byte);
876 p = BYTE_POS_ADDR (pos_byte);
fb911777
KH
877 }
878 else
879 return column;
880 }
993b6404
JB
881 }
882 }
883}
1b15e576
KH
884
885/* Test whether the line beginning at POS is indented beyond COLUMN.
886 Blank lines are treated as if they had the same indentation as the
887 preceding line. */
fe0066f5 888
1b15e576 889int
fe0066f5
RS
890indented_beyond_p (pos, pos_byte, column)
891 int pos, pos_byte, column;
1b15e576 892{
d5d6f706 893 int val;
fe0066f5
RS
894 int opoint = PT, opoint_byte = PT_BYTE;
895
896 SET_PT_BOTH (pos, pos_byte);
897 while (PT > BEGV && FETCH_BYTE (PT_BYTE) == '\n')
898 scan_newline (PT - 1, PT_BYTE - 1, BEGV, BEGV_BYTE, -1, 0);
899
d5d6f706 900 val = position_indentation (PT_BYTE);
fe0066f5 901 SET_PT_BOTH (opoint, opoint_byte);
8f9db2b7 902 return val >= column;
1b15e576 903}
993b6404 904\f
782d260e 905DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, "p",
8c1a1077
PJ
906 doc: /* Move point to column COLUMN in the current line.
907The column of a character is calculated by adding together the widths
908as displayed of the previous characters in the line.
909This function ignores line-continuation;
910there is no upper limit on the column number a character can have
911and horizontal scrolling has no effect.
912
913If specified column is within a character, point goes after that character.
914If it's past end of line, point goes to end of line.
915
916A non-nil second (optional) argument FORCE means,
917if COLUMN is in the middle of a tab character, change it to spaces.
918In addition, if FORCE is t, and the line is too short
919to reach column COLUMN, add spaces/tabs to get there.
920
921The return value is the current column. */)
922 (column, force)
993b6404
JB
923 Lisp_Object column, force;
924{
925 register int pos;
926 register int col = current_column ();
927 register int goal;
928 register int end;
929 register int tab_width = XINT (current_buffer->tab_width);
56a98455 930 register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
d44f12b4 931 register struct Lisp_Char_Table *dp = buffer_display_table ();
a997a7ca 932 register int multibyte = !NILP (current_buffer->enable_multibyte_characters);
993b6404
JB
933
934 Lisp_Object val;
6bbd7a29
GM
935 int prev_col = 0;
936 int c = 0;
9a21bb64
RS
937 int next_boundary;
938
fe0066f5
RS
939 int pos_byte, end_byte, next_boundary_byte;
940
ccdcf1f5 941 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
b7826503 942 CHECK_NATNUM (column);
993b6404
JB
943 goal = XINT (column);
944
6ec8bbd2 945 pos = PT;
fe0066f5 946 pos_byte = PT_BYTE;
993b6404 947 end = ZV;
fe0066f5 948 end_byte = ZV_BYTE;
9a21bb64 949 next_boundary = pos;
fe0066f5 950 next_boundary_byte = PT_BYTE;
993b6404
JB
951
952 /* If we're starting past the desired column,
953 back up to beginning of line and scan from there. */
954 if (col > goal)
955 {
9a21bb64 956 end = pos;
a997a7ca 957 pos = current_column_bol_cache;
fe0066f5 958 pos_byte = CHAR_TO_BYTE (pos);
993b6404
JB
959 col = 0;
960 }
961
8861f16f 962 while (pos < end)
993b6404 963 {
9a21bb64
RS
964 while (pos == next_boundary)
965 {
fe0066f5 966 int prev = pos;
9a21bb64 967 pos = skip_invisible (pos, &next_boundary, end, Qnil);
fe0066f5
RS
968 if (pos != prev)
969 pos_byte = CHAR_TO_BYTE (pos);
970 next_boundary_byte = CHAR_TO_BYTE (next_boundary);
9a21bb64
RS
971 if (pos >= end)
972 goto endloop;
973 }
974
8861f16f
RS
975 /* Test reaching the goal column. We do this after skipping
976 invisible characters, so that we put point before the
977 character on which the cursor will appear. */
978 if (col >= goal)
979 break;
980
012fd715
KH
981 /* Check composition sequence. */
982 {
983 int len, len_byte, width;
984
985 if (check_composition (pos, pos_byte, Z, &len, &len_byte, &width))
986 {
987 pos += len;
988 pos_byte += len_byte;
989 col += width;
990 continue;
991 }
992 }
993
fe0066f5 994 c = FETCH_BYTE (pos_byte);
88c6e37e 995
d6e483a4
RS
996 /* See if there is a display table and it relates
997 to this character. */
998
c9c0f7cf
KH
999 if (dp != 0
1000 && ! (multibyte && BASE_LEADING_CODE_P (c))
1001 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
f845b8b2 1002 {
d6e483a4
RS
1003 Lisp_Object charvec;
1004 EMACS_INT i, n;
1005
1006 /* This character is displayed using a vector of glyphs.
1007 Update the position based on those glyphs. */
1008
88c6e37e
GM
1009 charvec = DISP_CHAR_VECTOR (dp, c);
1010 n = ASIZE (charvec);
88c6e37e 1011
d6e483a4 1012 for (i = 0; i < n; i++)
88c6e37e
GM
1013 {
1014 /* This should be handled the same as
1015 next_element_from_display_vector does it. */
d6e483a4
RS
1016
1017 Lisp_Object entry;
1018 entry = AREF (charvec, i);
1019
88c6e37e
GM
1020 if (INTEGERP (entry)
1021 && GLYPH_CHAR_VALID_P (XFASTINT (entry)))
1022 c = FAST_GLYPH_CHAR (XFASTINT (entry));
1023 else
1024 c = ' ';
d6e483a4
RS
1025
1026 if (c == '\n')
1027 goto endloop;
1028 if (c == '\r' && EQ (current_buffer->selective_display, Qt))
1029 goto endloop;
1030 if (c == '\t')
1031 {
1032 prev_col = col;
1033 col += tab_width;
1034 col = col / tab_width * tab_width;
1035 }
1036 else
1037 ++col;
88c6e37e 1038 }
d6e483a4
RS
1039 }
1040 else
1041 {
1042 /* The display table doesn't affect this character;
1043 it displays as itself. */
88c6e37e 1044
88c6e37e
GM
1045 if (c == '\n')
1046 goto endloop;
1047 if (c == '\r' && EQ (current_buffer->selective_display, Qt))
1048 goto endloop;
88c6e37e
GM
1049 if (c == '\t')
1050 {
1051 prev_col = col;
1052 col += tab_width;
1053 col = col / tab_width * tab_width;
1054 }
1055 else if (ctl_arrow && (c < 040 || c == 0177))
1056 col += 2;
1057 else if (c < 040 || c == 0177)
1058 col += 4;
1059 else if (c < 0177)
1060 col++;
1061 else if (multibyte && BASE_LEADING_CODE_P (c))
1062 {
1063 /* Start of multi-byte form. */
1064 unsigned char *ptr;
1065 int bytes, width, wide_column;
1066
88c6e37e
GM
1067 ptr = BYTE_POS_ADDR (pos_byte);
1068 MULTIBYTE_BYTES_WIDTH (ptr, dp);
d6e483a4 1069 pos_byte += bytes - 1;
88c6e37e
GM
1070 col += width;
1071 }
1072 else
1073 col += 4;
a997a7ca 1074 }
d6e483a4
RS
1075
1076 pos++;
1077 pos_byte++;
993b6404 1078 }
9a21bb64 1079 endloop:
993b6404 1080
fe0066f5 1081 SET_PT_BOTH (pos, pos_byte);
993b6404
JB
1082
1083 /* If a tab char made us overshoot, change it to spaces
1084 and scan through it again. */
56a98455 1085 if (!NILP (force) && col > goal && c == '\t' && prev_col < goal)
993b6404 1086 {
154a424a
GM
1087 int goal_pt, goal_pt_byte;
1088
1089 /* Insert spaces in front of the tab to reach GOAL. Do this
1090 first so that a marker at the end of the tab gets
1091 adjusted. */
1092 SET_PT_BOTH (PT - 1, PT_BYTE - 1);
1093 Finsert_char (make_number (' '), make_number (goal - prev_col), Qt);
1094
1095 /* Now delete the tab, and indent to COL. */
1096 del_range (PT, PT + 1);
1097 goal_pt = PT;
1098 goal_pt_byte = PT_BYTE;
70ee42f7 1099 Findent_to (make_number (col), Qnil);
154a424a
GM
1100 SET_PT_BOTH (goal_pt, goal_pt_byte);
1101
5a05d3d2
RS
1102 /* Set the last_known... vars consistently. */
1103 col = goal;
993b6404
JB
1104 }
1105
1106 /* If line ends prematurely, add space to the end. */
de4075cf 1107 if (col < goal && EQ (force, Qt))
230a4cbd 1108 Findent_to (make_number (col = goal), Qnil);
993b6404
JB
1109
1110 last_known_column = col;
6ec8bbd2 1111 last_known_column_point = PT;
993b6404
JB
1112 last_known_column_modified = MODIFF;
1113
94d92e9c 1114 XSETFASTINT (val, col);
993b6404
JB
1115 return val;
1116}
1117\f
0aa01123
JB
1118/* compute_motion: compute buffer posn given screen posn and vice versa */
1119
993b6404
JB
1120struct position val_compute_motion;
1121
1122/* Scan the current buffer forward from offset FROM, pretending that
1123 this is at line FROMVPOS, column FROMHPOS, until reaching buffer
1124 offset TO or line TOVPOS, column TOHPOS (whichever comes first),
0aa01123
JB
1125 and return the ending buffer position and screen location. If we
1126 can't hit the requested column exactly (because of a tab or other
1127 multi-column character), overshoot.
993b6404 1128
2ab90d49
KH
1129 DID_MOTION is 1 if FROMHPOS has already accounted for overlay strings
1130 at FROM. This is the case if FROMVPOS and FROMVPOS came from an
1131 earlier call to compute_motion. The other common case is that FROMHPOS
1132 is zero and FROM is a position that "belongs" at column zero, but might
1133 be shifted by overlay strings; in this case DID_MOTION should be 0.
1134
993b6404
JB
1135 WIDTH is the number of columns available to display text;
1136 compute_motion uses this to handle continuation lines and such.
1137 HSCROLL is the number of columns not being displayed at the left
1138 margin; this is usually taken from a window's hscroll member.
a9764248
JB
1139 TAB_OFFSET is the number of columns of the first tab that aren't
1140 being displayed, perhaps because of a continuation line or
1141 something.
993b6404
JB
1142
1143 compute_motion returns a pointer to a struct position. The bufpos
1144 member gives the buffer position at the end of the scan, and hpos
0aa01123
JB
1145 and vpos give its cartesian location. prevhpos is the column at
1146 which the character before bufpos started, and contin is non-zero
1147 if we reached the current line by continuing the previous.
1148
1149 Note that FROMHPOS and TOHPOS should be expressed in real screen
1150 columns, taking HSCROLL and the truncation glyph at the left margin
1151 into account. That is, beginning-of-line moves you to the hpos
1152 -HSCROLL + (HSCROLL > 0).
993b6404
JB
1153
1154 For example, to find the buffer position of column COL of line LINE
1155 of a certain window, pass the window's starting location as FROM
1156 and the window's upper-left coordinates as FROMVPOS and FROMHPOS.
1157 Pass the buffer's ZV as TO, to limit the scan to the end of the
1158 visible section of the buffer, and pass LINE and COL as TOVPOS and
2ff4775b 1159 TOHPOS.
993b6404
JB
1160
1161 When displaying in window w, a typical formula for WIDTH is:
1162
1163 window_width - 1
a3c87d4e 1164 - (has_vertical_scroll_bars
40284d6b 1165 ? FRAME_SCROLL_BAR_COLS (XFRAME (window->frame))
fa61c701 1166 : (window_width + window_left != frame_width))
993b6404
JB
1167
1168 where
1169 window_width is XFASTINT (w->width),
1170 window_left is XFASTINT (w->left),
a3c87d4e
JB
1171 has_vertical_scroll_bars is
1172 FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (WINDOW_FRAME (window)))
fa61c701 1173 and frame_width = FRAME_WIDTH (XFRAME (window->frame))
993b6404 1174
1827d036
KH
1175 Or you can let window_internal_width do this all for you, and write:
1176 window_internal_width (w) - 1
fa61c701
JB
1177
1178 The `-1' accounts for the continuation-line backslashes; the rest
7e7a76b5 1179 accounts for window borders if the window is split horizontally, and
1827d036 1180 the scroll bars if they are turned on. */
993b6404
JB
1181
1182struct position *
2ab90d49 1183compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, hscroll, tab_offset, win)
993b6404 1184 int from, fromvpos, fromhpos, to, tovpos, tohpos;
2ab90d49 1185 int did_motion;
993b6404
JB
1186 register int width;
1187 int hscroll, tab_offset;
88af3af4 1188 struct window *win;
993b6404 1189{
cde9337b
JB
1190 register int hpos = fromhpos;
1191 register int vpos = fromvpos;
1192
993b6404 1193 register int pos;
fe0066f5 1194 int pos_byte;
6bbd7a29 1195 register int c = 0;
993b6404 1196 register int tab_width = XFASTINT (current_buffer->tab_width);
56a98455 1197 register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
d44f12b4 1198 register struct Lisp_Char_Table *dp = window_display_table (win);
993b6404 1199 int selective
eeaafd4f 1200 = (INTEGERP (current_buffer->selective_display)
69eaf10d
RS
1201 ? XINT (current_buffer->selective_display)
1202 : !NILP (current_buffer->selective_display) ? -1 : 0);
a997a7ca 1203 int prev_hpos = 0;
993b6404 1204 int selective_rlen
eeaafd4f 1205 = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
dea4d2e6 1206 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0);
2ab90d49
KH
1207 /* The next location where the `invisible' property changes, or an
1208 overlay starts or ends. */
1209 int next_boundary = from;
993b6404 1210
0aa01123
JB
1211 /* For computing runs of characters with similar widths.
1212 Invariant: width_run_width is zero, or all the characters
2ff4775b 1213 from width_run_start to width_run_end have a fixed width of
0aa01123
JB
1214 width_run_width. */
1215 int width_run_start = from;
1216 int width_run_end = from;
1217 int width_run_width = 0;
1218 Lisp_Object *width_table;
66c75ca5 1219 Lisp_Object buffer;
0aa01123
JB
1220
1221 /* The next buffer pos where we should consult the width run cache. */
1222 int next_width_run = from;
0e435804 1223 Lisp_Object window;
0aa01123 1224
a997a7ca 1225 int multibyte = !NILP (current_buffer->enable_multibyte_characters);
c71c19f4
RS
1226 /* If previous char scanned was a wide character,
1227 this is the column where it ended. Otherwise, this is 0. */
1228 int wide_column_end_hpos = 0;
a997a7ca 1229 int prev_pos; /* Previous buffer position. */
fe0066f5 1230 int prev_pos_byte; /* Previous buffer position. */
a997a7ca
KH
1231 int contin_hpos; /* HPOS of last column of continued line. */
1232 int prev_tab_offset; /* Previous tab offset. */
1233
66c75ca5 1234 XSETBUFFER (buffer, current_buffer);
0e435804 1235 XSETWINDOW (window, win);
66c75ca5 1236
0aa01123
JB
1237 width_run_cache_on_off ();
1238 if (dp == buffer_display_table ())
1239 width_table = (VECTORP (current_buffer->width_table)
1240 ? XVECTOR (current_buffer->width_table)->contents
1241 : 0);
1242 else
1243 /* If the window has its own display table, we can't use the width
1244 run cache, because that's based on the buffer's display table. */
1245 width_table = 0;
1246
e4500116
GM
1247 if (tab_width <= 0 || tab_width > 1000)
1248 tab_width = 8;
1249
1250 immediate_quit = 1;
1251 QUIT;
cde9337b 1252
a997a7ca 1253 pos = prev_pos = from;
fe0066f5 1254 pos_byte = prev_pos_byte = CHAR_TO_BYTE (from);
a997a7ca
KH
1255 contin_hpos = 0;
1256 prev_tab_offset = tab_offset;
2ab90d49
KH
1257 while (1)
1258 {
1259 while (pos == next_boundary)
f75c0f8a 1260 {
fe0066f5 1261 int pos_here = pos;
98136db3
RS
1262 int newpos;
1263
f9ba10b0
RS
1264 /* Don't skip invisible if we are already at the margin. */
1265 if (vpos > tovpos || vpos == tovpos && hpos >= tohpos)
1266 {
1267 if (contin_hpos && prev_hpos == 0
1268 && hpos > tohpos
1269 && (contin_hpos == width || wide_column_end_hpos > width))
1270 { /* Line breaks because we can't put the character at the
1271 previous line any more. It is not the multi-column
1272 character continued in middle. Go back to previous
1273 buffer position, screen position, and set tab offset
1274 to previous value. It's the beginning of the
1275 line. */
1276 pos = prev_pos;
1277 pos_byte = prev_pos_byte;
1278 hpos = prev_hpos;
1279 tab_offset = prev_tab_offset;
1280 }
1281 break;
1282 }
1283
2ab90d49
KH
1284 /* If the caller says that the screen position came from an earlier
1285 call to compute_motion, then we've already accounted for the
1286 overlay strings at point. This is only true the first time
1287 through, so clear the flag after testing it. */
1288 if (!did_motion)
1289 /* We need to skip past the overlay strings. Currently those
a997a7ca 1290 strings must not contain TAB;
2ab90d49
KH
1291 if we want to relax that restriction, something will have
1292 to be changed here. */
a997a7ca
KH
1293 {
1294 unsigned char *ovstr;
1295 int ovlen = overlay_strings (pos, win, &ovstr);
4116deee
KH
1296 hpos += ((multibyte && ovlen > 0)
1297 ? strwidth (ovstr, ovlen) : ovlen);
a997a7ca 1298 }
2ab90d49
KH
1299 did_motion = 0;
1300
1301 if (pos >= to)
1302 break;
66c75ca5 1303
9a21bb64
RS
1304 /* Advance POS past invisible characters
1305 (but not necessarily all that there are here),
1306 and store in next_boundary the next position where
1307 we need to call skip_invisible. */
98136db3
RS
1308 newpos = skip_invisible (pos, &next_boundary, to, window);
1309
1310 if (newpos >= to)
e8cb089b
RS
1311 {
1312 pos = min (to, newpos);
bcfbd63d 1313 pos_byte = CHAR_TO_BYTE (pos);
e8cb089b
RS
1314 goto after_loop;
1315 }
98136db3 1316
fe0066f5
RS
1317 if (newpos != pos_here)
1318 {
1319 pos = newpos;
1320 pos_byte = CHAR_TO_BYTE (pos);
1321 }
f75c0f8a 1322 }
2ab90d49
KH
1323
1324 /* Handle right margin. */
a997a7ca
KH
1325 /* Note on a wide-column character.
1326
1327 Characters are classified into the following three categories
1328 according to the width (columns occupied on screen).
1329
1330 (1) single-column character: ex. `a'
1331 (2) multi-column character: ex. `^A', TAB, `\033'
1332 (3) wide-column character: ex. Japanese character, Chinese character
1333 (In the following example, `W_' stands for them.)
1334
1335 Multi-column characters can be divided around the right margin,
1336 but wide-column characters cannot.
1337
1338 NOTE:
1339
1340 (*) The cursor is placed on the next character after the point.
1341
1342 ----------
1343 abcdefghi\
1344 j ^---- next after the point
1345 ^--- next char. after the point.
1346 ----------
1347 In case of sigle-column character
1348
1349 ----------
1350 abcdefgh\\
1351 033 ^---- next after the point, next char. after the point.
1352 ----------
1353 In case of multi-column character
1354
1355 ----------
1356 abcdefgh\\
1357 W_ ^---- next after the point
1358 ^---- next char. after the point.
1359 ----------
1360 In case of wide-column character
1361
1362 The problem here is continuation at a wide-column character.
1363 In this case, the line may shorter less than WIDTH.
1364 And we find the continuation AFTER it occurs.
1365
1366 */
1367
1368 if (hpos > width)
2ab90d49
KH
1369 {
1370 if (hscroll
1371 || (truncate_partial_width_windows
1372 && width + 1 < FRAME_WIDTH (XFRAME (WINDOW_FRAME (win))))
1373 || !NILP (current_buffer->truncate_lines))
1374 {
529724fe
AS
1375 /* Truncating: skip to newline, unless we are already past
1376 TO (we need to go back below). */
1377 if (pos <= to)
fe0066f5
RS
1378 {
1379 pos = find_before_next_newline (pos, to, 1);
1380 pos_byte = CHAR_TO_BYTE (pos);
529724fe
AS
1381 hpos = width;
1382 /* If we just skipped next_boundary,
1383 loop around in the main while
1384 and handle it. */
1385 if (pos >= next_boundary)
1386 next_boundary = pos + 1;
1387 prev_hpos = width;
1388 prev_tab_offset = tab_offset;
fe0066f5 1389 }
2ab90d49
KH
1390 }
1391 else
1392 {
1393 /* Continuing. */
a997a7ca
KH
1394 /* Remember the previous value. */
1395 prev_tab_offset = tab_offset;
1396
c9c0f7cf 1397 if (wide_column_end_hpos > width)
a997a7ca
KH
1398 {
1399 hpos -= prev_hpos;
1400 tab_offset += prev_hpos;
1401 }
1402 else
1403 {
1404 tab_offset += width;
1405 hpos -= width;
1406 }
1407 vpos++;
1408 contin_hpos = prev_hpos;
1409 prev_hpos = 0;
2ab90d49
KH
1410 }
1411 }
1412
1413 /* Stop if past the target buffer position or screen position. */
33fe7d20 1414 if (pos > to)
a997a7ca
KH
1415 {
1416 /* Go back to the previous position. */
1417 pos = prev_pos;
fe0066f5 1418 pos_byte = prev_pos_byte;
a997a7ca
KH
1419 hpos = prev_hpos;
1420 tab_offset = prev_tab_offset;
1421
1422 /* NOTE on contin_hpos, hpos, and prev_hpos.
1423
1424 ----------
1425 abcdefgh\\
1426 W_ ^---- contin_hpos
1427 | ^----- hpos
1428 \---- prev_hpos
1429 ----------
1430 */
1431
1432 if (contin_hpos && prev_hpos == 0
c9c0f7cf 1433 && contin_hpos < width && !wide_column_end_hpos)
a997a7ca
KH
1434 {
1435 /* Line breaking occurs in the middle of multi-column
1436 character. Go back to previous line. */
1437 hpos = contin_hpos;
1438 vpos = vpos - 1;
1439 }
1440 else if (c == '\n')
1441 /* If previous character is NEWLINE,
1442 set VPOS back to previous line */
1443 vpos = vpos - 1;
1444 break;
1445 }
1446
33fe7d20
RS
1447 if (vpos > tovpos || vpos == tovpos && hpos >= tohpos)
1448 {
1449 if (contin_hpos && prev_hpos == 0
9129bcc3
KH
1450 && hpos > tohpos
1451 && (contin_hpos == width || wide_column_end_hpos > width))
33fe7d20
RS
1452 { /* Line breaks because we can't put the character at the
1453 previous line any more. It is not the multi-column
1454 character continued in middle. Go back to previous
1455 buffer position, screen position, and set tab offset
1456 to previous value. It's the beginning of the
1457 line. */
1458 pos = prev_pos;
1459 pos_byte = prev_pos_byte;
1460 hpos = prev_hpos;
1461 tab_offset = prev_tab_offset;
1462 }
1463 break;
1464 }
a997a7ca 1465 if (pos == ZV) /* We cannot go beyond ZV. Stop here. */
2ab90d49
KH
1466 break;
1467
2ab90d49 1468 prev_hpos = hpos;
a997a7ca 1469 prev_pos = pos;
fe0066f5 1470 prev_pos_byte = pos_byte;
c9c0f7cf 1471 wide_column_end_hpos = 0;
0aa01123
JB
1472
1473 /* Consult the width run cache to see if we can avoid inspecting
1474 the text character-by-character. */
1475 if (current_buffer->width_run_cache && pos >= next_width_run)
1476 {
1477 int run_end;
1478 int common_width
1479 = region_cache_forward (current_buffer,
1480 current_buffer->width_run_cache,
1481 pos, &run_end);
1482
1483 /* A width of zero means the character's width varies (like
1484 a tab), is meaningless (like a newline), or we just don't
1485 want to skip over it for some other reason. */
1486 if (common_width != 0)
1487 {
1488 int run_end_hpos;
1489
1490 /* Don't go past the final buffer posn the user
1491 requested. */
1492 if (run_end > to)
1493 run_end = to;
1494
1495 run_end_hpos = hpos + (run_end - pos) * common_width;
1496
1497 /* Don't go past the final horizontal position the user
1498 requested. */
1499 if (vpos == tovpos && run_end_hpos > tohpos)
1500 {
1501 run_end = pos + (tohpos - hpos) / common_width;
1502 run_end_hpos = hpos + (run_end - pos) * common_width;
1503 }
2ff4775b 1504
0aa01123
JB
1505 /* Don't go past the margin. */
1506 if (run_end_hpos >= width)
1507 {
1508 run_end = pos + (width - hpos) / common_width;
1509 run_end_hpos = hpos + (run_end - pos) * common_width;
1510 }
1511
1512 hpos = run_end_hpos;
1513 if (run_end > pos)
1514 prev_hpos = hpos - common_width;
fe0066f5
RS
1515 if (pos != run_end)
1516 {
1517 pos = run_end;
1518 pos_byte = CHAR_TO_BYTE (pos);
1519 }
0aa01123
JB
1520 }
1521
1522 next_width_run = run_end + 1;
1523 }
1524
1525 /* We have to scan the text character-by-character. */
993b6404 1526 else
2ab90d49 1527 {
88c6e37e
GM
1528 EMACS_INT i, n;
1529 Lisp_Object charvec;
1530
fe0066f5 1531 c = FETCH_BYTE (pos_byte);
012fd715
KH
1532
1533 /* Check composition sequence. */
1534 {
1535 int len, len_byte, width;
1536
1537 if (check_composition (pos, pos_byte, to, &len, &len_byte, &width))
1538 {
1539 pos += len;
1540 pos_byte += len_byte;
1541 hpos += width;
1542 continue;
1543 }
1544 }
1545
fe0066f5 1546 pos++, pos_byte++;
0aa01123 1547
2ab90d49
KH
1548 /* Perhaps add some info to the width_run_cache. */
1549 if (current_buffer->width_run_cache)
1550 {
1551 /* Is this character part of the current run? If so, extend
1552 the run. */
1553 if (pos - 1 == width_run_end
5db0afb7 1554 && XFASTINT (width_table[c]) == width_run_width)
2ab90d49
KH
1555 width_run_end = pos;
1556
1557 /* The previous run is over, since this is a character at a
1558 different position, or a different width. */
1559 else
1560 {
1561 /* Have we accumulated a run to put in the cache?
1562 (Currently, we only cache runs of width == 1). */
1563 if (width_run_start < width_run_end
1564 && width_run_width == 1)
1565 know_region_cache (current_buffer,
1566 current_buffer->width_run_cache,
1567 width_run_start, width_run_end);
1568
1569 /* Start recording a new width run. */
5db0afb7 1570 width_run_width = XFASTINT (width_table[c]);
2ab90d49
KH
1571 width_run_start = pos - 1;
1572 width_run_end = pos;
1573 }
1574 }
993b6404 1575
c9c0f7cf
KH
1576 if (dp != 0
1577 && ! (multibyte && BASE_LEADING_CODE_P (c))
1578 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
993b6404 1579 {
88c6e37e
GM
1580 charvec = DISP_CHAR_VECTOR (dp, c);
1581 n = ASIZE (charvec);
993b6404 1582 }
88c6e37e 1583 else
993b6404 1584 {
88c6e37e
GM
1585 charvec = Qnil;
1586 n = 1;
1587 }
1588
1589 for (i = n - 1; i >= 0; --i)
1590 {
1591 if (VECTORP (charvec))
2ab90d49 1592 {
88c6e37e
GM
1593 /* This should be handled the same as
1594 next_element_from_display_vector does it. */
1595 Lisp_Object entry = AREF (charvec, i);
1596
1597 if (INTEGERP (entry)
1598 && GLYPH_CHAR_VALID_P (XFASTINT (entry)))
1599 c = FAST_GLYPH_CHAR (XFASTINT (entry));
1600 else
1601 c = ' ';
1602 }
1603
1604 if (c >= 040 && c < 0177)
1605 hpos++;
1606 else if (c == '\t')
1607 {
1608 int tem = ((hpos + tab_offset + hscroll - (hscroll > 0))
1609 % tab_width);
1610 if (tem < 0)
1611 tem += tab_width;
1612 hpos += tab_width - tem;
1613 }
1614 else if (c == '\n')
1615 {
1616 if (selective > 0
1617 && indented_beyond_p (pos, pos_byte, selective))
2ab90d49 1618 {
88c6e37e
GM
1619 /* If (pos == to), we don't have to take care of
1620 selective display. */
1621 if (pos < to)
fe0066f5 1622 {
88c6e37e
GM
1623 /* Skip any number of invisible lines all at once */
1624 do
1625 {
1626 pos = find_before_next_newline (pos, to, 1);
1627 if (pos < to)
1628 pos++;
1629 pos_byte = CHAR_TO_BYTE (pos);
1630 }
1631 while (pos < to
1632 && indented_beyond_p (pos, pos_byte, selective));
1633 /* Allow for the " ..." that is displayed for them. */
1634 if (selective_rlen)
1635 {
1636 hpos += selective_rlen;
1637 if (hpos >= width)
1638 hpos = width;
1639 }
1640 DEC_BOTH (pos, pos_byte);
1641 /* We have skipped the invis text, but not the
1642 newline after. */
fe0066f5 1643 }
2ab90d49 1644 }
88c6e37e
GM
1645 else
1646 {
1647 /* A visible line. */
1648 vpos++;
1649 hpos = 0;
1650 hpos -= hscroll;
1651 /* Count the truncation glyph on column 0 */
1652 if (hscroll > 0)
1653 hpos++;
1654 tab_offset = 0;
1655 }
1656 contin_hpos = 0;
2ab90d49 1657 }
88c6e37e 1658 else if (c == CR && selective < 0)
fe0066f5 1659 {
88c6e37e
GM
1660 /* In selective display mode,
1661 everything from a ^M to the end of the line is invisible.
1662 Stop *before* the real newline. */
1663 if (pos < to)
1664 {
1665 pos = find_before_next_newline (pos, to, 1);
1666 pos_byte = CHAR_TO_BYTE (pos);
1667 }
1668 /* If we just skipped next_boundary,
1669 loop around in the main while
1670 and handle it. */
1671 if (pos > next_boundary)
1672 next_boundary = pos;
1673 /* Allow for the " ..." that is displayed for them. */
1674 if (selective_rlen)
1675 {
1676 hpos += selective_rlen;
1677 if (hpos >= width)
1678 hpos = width;
1679 }
fe0066f5 1680 }
88c6e37e 1681 else if (multibyte && BASE_LEADING_CODE_P (c))
2ab90d49 1682 {
88c6e37e
GM
1683 /* Start of multi-byte form. */
1684 unsigned char *ptr;
1685 int bytes, width, wide_column;
1686
1687 pos_byte--; /* rewind POS_BYTE */
1688 ptr = BYTE_POS_ADDR (pos_byte);
1689 MULTIBYTE_BYTES_WIDTH (ptr, dp);
1690 pos_byte += bytes;
1691 if (wide_column)
1692 wide_column_end_hpos = hpos + wide_column;
1693 hpos += width;
2ab90d49 1694 }
f1004faf
GM
1695 else if (VECTORP (charvec))
1696 ++hpos;
88c6e37e
GM
1697 else
1698 hpos += (ctl_arrow && c < 0200) ? 2 : 4;
2ab90d49 1699 }
993b6404
JB
1700 }
1701 }
1702
98136db3
RS
1703 after_loop:
1704
0aa01123
JB
1705 /* Remember any final width run in the cache. */
1706 if (current_buffer->width_run_cache
1707 && width_run_width == 1
1708 && width_run_start < width_run_end)
1709 know_region_cache (current_buffer, current_buffer->width_run_cache,
1710 width_run_start, width_run_end);
1711
993b6404 1712 val_compute_motion.bufpos = pos;
fe0066f5 1713 val_compute_motion.bytepos = pos_byte;
cde9337b
JB
1714 val_compute_motion.hpos = hpos;
1715 val_compute_motion.vpos = vpos;
ef3af330
AS
1716 if (contin_hpos && prev_hpos == 0)
1717 val_compute_motion.prevhpos = contin_hpos;
1718 else
1719 val_compute_motion.prevhpos = prev_hpos;
927b5a55
RS
1720 /* We alalways handle all of them here; none of them remain to do. */
1721 val_compute_motion.ovstring_chars_done = 0;
993b6404
JB
1722
1723 /* Nonzero if have just continued a line */
a997a7ca 1724 val_compute_motion.contin = (contin_hpos && prev_hpos == 0);
993b6404 1725
e4500116 1726 immediate_quit = 0;
993b6404
JB
1727 return &val_compute_motion;
1728}
993b6404 1729
8720a429 1730
88af3af4 1731DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0,
8c1a1077
PJ
1732 doc: /* Scan through the current buffer, calculating screen position.
1733Scan the current buffer forward from offset FROM,
1734assuming it is at position FROMPOS--a cons of the form (HPOS . VPOS)--
1735to position TO or position TOPOS--another cons of the form (HPOS . VPOS)--
1736and return the ending buffer position and screen location.
1737
1738There are three additional arguments:
1739
1740WIDTH is the number of columns available to display text;
1741this affects handling of continuation lines.
1742This is usually the value returned by `window-width', less one (to allow
1743for the continuation glyph).
1744
1745OFFSETS is either nil or a cons cell (HSCROLL . TAB-OFFSET).
1746HSCROLL is the number of columns not being displayed at the left
1747margin; this is usually taken from a window's hscroll member.
1748TAB-OFFSET is the number of columns of the first tab that aren't
1749being displayed, perhaps because the line was continued within it.
1750If OFFSETS is nil, HSCROLL and TAB-OFFSET are assumed to be zero.
1751
1752WINDOW is the window to operate on. It is used to choose the display table;
1753if it is showing the current buffer, it is used also for
1754deciding which overlay properties apply.
1755Note that `compute-motion' always operates on the current buffer.
1756
1757The value is a list of five elements:
1758 (POS HPOS VPOS PREVHPOS CONTIN)
1759POS is the buffer position where the scan stopped.
1760VPOS is the vertical position where the scan stopped.
1761HPOS is the horizontal position where the scan stopped.
1762
1763PREVHPOS is the horizontal position one character back from POS.
1764CONTIN is t if a line was continued after (or within) the previous character.
1765
1766For example, to find the buffer position of column COL of line LINE
1767of a certain window, pass the window's starting location as FROM
1768and the window's upper-left coordinates as FROMPOS.
1769Pass the buffer's (point-max) as TO, to limit the scan to the end of the
1770visible section of the buffer, and pass LINE and COL as TOPOS. */)
1771 (from, frompos, to, topos, width, offsets, window)
42918ba5 1772 Lisp_Object from, frompos, to, topos;
88af3af4 1773 Lisp_Object width, offsets, window;
42918ba5 1774{
8798a92b 1775 Lisp_Object bufpos, hpos, vpos, prevhpos;
42918ba5
RS
1776 struct position *pos;
1777 int hscroll, tab_offset;
1778
b7826503
PJ
1779 CHECK_NUMBER_COERCE_MARKER (from);
1780 CHECK_CONS (frompos);
1781 CHECK_NUMBER_CAR (frompos);
1782 CHECK_NUMBER_CDR (frompos);
1783 CHECK_NUMBER_COERCE_MARKER (to);
1784 CHECK_CONS (topos);
1785 CHECK_NUMBER_CAR (topos);
1786 CHECK_NUMBER_CDR (topos);
1787 CHECK_NUMBER (width);
42918ba5
RS
1788 if (!NILP (offsets))
1789 {
b7826503
PJ
1790 CHECK_CONS (offsets);
1791 CHECK_NUMBER_CAR (offsets);
1792 CHECK_NUMBER_CDR (offsets);
70949dac
KR
1793 hscroll = XINT (XCAR (offsets));
1794 tab_offset = XINT (XCDR (offsets));
42918ba5
RS
1795 }
1796 else
1797 hscroll = tab_offset = 0;
1798
88af3af4
KH
1799 if (NILP (window))
1800 window = Fselected_window ();
1801 else
b7826503 1802 CHECK_LIVE_WINDOW (window);
88af3af4 1803
9fdae274
KH
1804 if (XINT (from) < BEGV || XINT (from) > ZV)
1805 args_out_of_range_3 (from, make_number (BEGV), make_number (ZV));
1806 if (XINT (to) < BEGV || XINT (to) > ZV)
1807 args_out_of_range_3 (to, make_number (BEGV), make_number (ZV));
1808
70949dac
KR
1809 pos = compute_motion (XINT (from), XINT (XCDR (frompos)),
1810 XINT (XCAR (frompos)), 0,
1811 XINT (to), XINT (XCDR (topos)),
1812 XINT (XCAR (topos)),
88af3af4
KH
1813 XINT (width), hscroll, tab_offset,
1814 XWINDOW (window));
42918ba5 1815
94d92e9c 1816 XSETFASTINT (bufpos, pos->bufpos);
f8f645a1
KH
1817 XSETINT (hpos, pos->hpos);
1818 XSETINT (vpos, pos->vpos);
1819 XSETINT (prevhpos, pos->prevhpos);
42918ba5
RS
1820
1821 return Fcons (bufpos,
1822 Fcons (hpos,
1823 Fcons (vpos,
1824 Fcons (prevhpos,
1825 Fcons (pos->contin ? Qt : Qnil, Qnil)))));
1826
1827}
993b6404 1828\f
0aa01123 1829/* Fvertical_motion and vmotion */
88c6e37e 1830
993b6404
JB
1831struct position val_vmotion;
1832
1833struct position *
99ce22d5
KH
1834vmotion (from, vtarget, w)
1835 register int from, vtarget;
1836 struct window *w;
993b6404 1837{
99ce22d5
KH
1838 int width = window_internal_width (w) - 1;
1839 int hscroll = XINT (w->hscroll);
993b6404
JB
1840 struct position pos;
1841 /* vpos is cumulative vertical position, changed as from is changed */
1842 register int vpos = 0;
92992c7e 1843 Lisp_Object prevline;
993b6404 1844 register int first;
fe0066f5 1845 int from_byte;
993b6404
JB
1846 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
1847 int selective
eeaafd4f
KH
1848 = (INTEGERP (current_buffer->selective_display)
1849 ? XINT (current_buffer->selective_display)
1850 : !NILP (current_buffer->selective_display) ? -1 : 0);
99ce22d5
KH
1851 Lisp_Object window;
1852 int start_hpos = 0;
2ab90d49 1853 int did_motion;
7ac57cb3
RS
1854 /* This is the object we use for fetching character properties. */
1855 Lisp_Object text_prop_object;
99ce22d5
KH
1856
1857 XSETWINDOW (window, w);
1858
7ac57cb3
RS
1859 /* If the window contains this buffer, use it for getting text properties.
1860 Otherwise use the current buffer as arg for doing that. */
1861 if (EQ (w->buffer, Fcurrent_buffer ()))
1862 text_prop_object = window;
1863 else
1864 text_prop_object = Fcurrent_buffer ();
1865
99ce22d5 1866 if (vpos >= vtarget)
993b6404 1867 {
99ce22d5 1868 /* To move upward, go a line at a time until
fe0066f5 1869 we have gone at least far enough. */
99ce22d5
KH
1870
1871 first = 1;
1872
1873 while ((vpos > vtarget || first) && from > BEGV)
993b6404 1874 {
66c75ca5
RS
1875 Lisp_Object propval;
1876
99ce22d5 1877 XSETFASTINT (prevline, find_next_newline_no_quit (from - 1, -1));
92992c7e 1878 while (XFASTINT (prevline) > BEGV
5a05d3d2 1879 && ((selective > 0
fe0066f5
RS
1880 && indented_beyond_p (XFASTINT (prevline),
1881 CHAR_TO_BYTE (XFASTINT (prevline)),
1882 selective))
5a05d3d2 1883 /* watch out for newlines with `invisible' property */
66c75ca5
RS
1884 || (propval = Fget_char_property (prevline,
1885 Qinvisible,
7ac57cb3 1886 text_prop_object),
339ee979 1887 TEXT_PROP_MEANS_INVISIBLE (propval))))
94d92e9c
KH
1888 XSETFASTINT (prevline,
1889 find_next_newline_no_quit (XFASTINT (prevline) - 1,
1890 -1));
92992c7e 1891 pos = *compute_motion (XFASTINT (prevline), 0,
99ce22d5 1892 lmargin + (XFASTINT (prevline) == BEG
92992c7e 1893 ? start_hpos : 0),
2ab90d49 1894 0,
a997a7ca
KH
1895 from,
1896 /* Don't care for VPOS... */
1897 1 << (BITS_PER_SHORT - 1),
1898 /* ... nor HPOS. */
1899 1 << (BITS_PER_SHORT - 1),
2dd4e608
RS
1900 width, hscroll,
1901 /* This compensates for start_hpos
1902 so that a tab as first character
1903 still occupies 8 columns. */
1904 (XFASTINT (prevline) == BEG
1905 ? -start_hpos : 0),
1906 w);
99ce22d5
KH
1907 vpos -= pos.vpos;
1908 first = 0;
1909 from = XFASTINT (prevline);
993b6404 1910 }
99ce22d5
KH
1911
1912 /* If we made exactly the desired vertical distance,
1913 or if we hit beginning of buffer,
1914 return point found */
1915 if (vpos >= vtarget)
993b6404 1916 {
99ce22d5 1917 val_vmotion.bufpos = from;
fe0066f5 1918 val_vmotion.bytepos = CHAR_TO_BYTE (from);
99ce22d5
KH
1919 val_vmotion.vpos = vpos;
1920 val_vmotion.hpos = lmargin;
1921 val_vmotion.contin = 0;
1922 val_vmotion.prevhpos = 0;
927b5a55 1923 val_vmotion.ovstring_chars_done = 0;
a997a7ca 1924 val_vmotion.tab_offset = 0; /* For accumulating tab offset. */
99ce22d5 1925 return &val_vmotion;
993b6404 1926 }
993b6404 1927
99ce22d5
KH
1928 /* Otherwise find the correct spot by moving down */
1929 }
1930 /* Moving downward is simple, but must calculate from beg of line
1931 to determine hpos of starting point */
fe0066f5
RS
1932 from_byte = CHAR_TO_BYTE (from);
1933 if (from > BEGV && FETCH_BYTE (from_byte - 1) != '\n')
993b6404 1934 {
2ab90d49 1935 Lisp_Object propval;
66c75ca5 1936
99ce22d5
KH
1937 XSETFASTINT (prevline, find_next_newline_no_quit (from, -1));
1938 while (XFASTINT (prevline) > BEGV
1939 && ((selective > 0
fe0066f5
RS
1940 && indented_beyond_p (XFASTINT (prevline),
1941 CHAR_TO_BYTE (XFASTINT (prevline)),
1942 selective))
99ce22d5
KH
1943 /* watch out for newlines with `invisible' property */
1944 || (propval = Fget_char_property (prevline, Qinvisible,
7ac57cb3 1945 text_prop_object),
339ee979 1946 TEXT_PROP_MEANS_INVISIBLE (propval))))
99ce22d5
KH
1947 XSETFASTINT (prevline,
1948 find_next_newline_no_quit (XFASTINT (prevline) - 1,
1949 -1));
92992c7e 1950 pos = *compute_motion (XFASTINT (prevline), 0,
99ce22d5 1951 lmargin + (XFASTINT (prevline) == BEG
92992c7e 1952 ? start_hpos : 0),
2ab90d49 1953 0,
a997a7ca
KH
1954 from,
1955 /* Don't care for VPOS... */
1956 1 << (BITS_PER_SHORT - 1),
1957 /* ... nor HPOS. */
1958 1 << (BITS_PER_SHORT - 1),
2dd4e608
RS
1959 width, hscroll,
1960 (XFASTINT (prevline) == BEG ? -start_hpos : 0),
1961 w);
2ab90d49 1962 did_motion = 1;
993b6404 1963 }
99ce22d5 1964 else
993b6404 1965 {
99ce22d5
KH
1966 pos.hpos = lmargin + (from == BEG ? start_hpos : 0);
1967 pos.vpos = 0;
a997a7ca 1968 pos.tab_offset = 0;
2ab90d49 1969 did_motion = 0;
993b6404 1970 }
2ab90d49 1971 return compute_motion (from, vpos, pos.hpos, did_motion,
a997a7ca 1972 ZV, vtarget, - (1 << (BITS_PER_SHORT - 1)),
2dd4e608 1973 width, hscroll,
a997a7ca 1974 pos.tab_offset - (from == BEG ? start_hpos : 0),
2dd4e608 1975 w);
993b6404
JB
1976}
1977
f1ecfe9b 1978DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 2, 0,
8c1a1077
PJ
1979 doc: /* Move point to start of the screen line LINES lines down.
1980If LINES is negative, this means moving up.
1981
1982This function is an ordinary cursor motion function
1983which calculates the new position based on how text would be displayed.
1984The new position may be the start of a line,
1985or just the start of a continuation line.
1986The function returns number of screen lines moved over;
1987that usually equals LINES, but may be closer to zero
1988if beginning or end of buffer was reached.
1989
1990The optional second argument WINDOW specifies the window to use for
1991parameters such as width, horizontal scrolling, and so on.
1992The default is to use the selected window's parameters.
1993
1994`vertical-motion' always uses the current buffer,
1995regardless of which buffer is displayed in WINDOW.
1996This is consistent with other cursor motion functions
1997and makes it possible to use `vertical-motion' in any buffer,
1998whether or not it is currently displayed in some window. */)
1999 (lines, window)
f1ecfe9b 2000 Lisp_Object lines, window;
993b6404 2001{
8720a429
GM
2002 struct it it;
2003 struct text_pos pt;
8720a429 2004 struct window *w;
39210e90
GM
2005 Lisp_Object old_buffer;
2006 struct gcpro gcpro1;
993b6404 2007
b7826503 2008 CHECK_NUMBER (lines);
f1ecfe9b 2009 if (! NILP (window))
b7826503 2010 CHECK_WINDOW (window);
f1ecfe9b 2011 else
92992c7e 2012 window = selected_window;
8720a429 2013 w = XWINDOW (window);
39210e90
GM
2014
2015 old_buffer = Qnil;
2016 GCPRO1 (old_buffer);
2017 if (XBUFFER (w->buffer) != current_buffer)
8720a429 2018 {
39210e90
GM
2019 /* Set the window's buffer temporarily to the current buffer. */
2020 old_buffer = w->buffer;
2021 XSETBUFFER (w->buffer, current_buffer);
8720a429 2022 }
8720a429
GM
2023
2024 SET_TEXT_POS (pt, PT, PT_BYTE);
2025 start_display (&it, w, pt);
2026 move_it_by_lines (&it, XINT (lines), 0);
2027 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
2028
39210e90
GM
2029 if (BUFFERP (old_buffer))
2030 w->buffer = old_buffer;
8720a429 2031
39210e90 2032 RETURN_UNGCPRO (make_number (it.vpos));
993b6404 2033}
8720a429
GM
2034
2035
993b6404 2036\f
88c6e37e 2037/* File's initialization. */
0aa01123 2038
dfcf069d 2039void
993b6404
JB
2040syms_of_indent ()
2041{
2042 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
8c1a1077
PJ
2043 doc: /* *Indentation can insert tabs if this is non-nil.
2044Setting this variable automatically makes it local to the current buffer. */);
993b6404
JB
2045 indent_tabs_mode = 1;
2046
2047 defsubr (&Scurrent_indentation);
2048 defsubr (&Sindent_to);
2049 defsubr (&Scurrent_column);
2050 defsubr (&Smove_to_column);
2051 defsubr (&Svertical_motion);
42918ba5 2052 defsubr (&Scompute_motion);
993b6404 2053}