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