(search_regs_saved): Delete initializer.
[bpt/emacs.git] / src / indent.c
CommitLineData
993b6404 1/* Indentation functions.
3a22ee35 2 Copyright (C) 1985,86,87,88,93,94 Free Software Foundation, Inc.
993b6404
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
18160b98 21#include <config.h>
993b6404
JB
22#include "lisp.h"
23#include "buffer.h"
24#include "indent.h"
502b9b64 25#include "frame.h"
993b6404
JB
26#include "window.h"
27#include "termchar.h"
28#include "termopts.h"
29#include "disptab.h"
5a05d3d2 30#include "intervals.h"
0aa01123 31#include "region-cache.h"
993b6404
JB
32
33/* Indentation can insert tabs if this is non-zero;
34 otherwise always uses spaces */
35int indent_tabs_mode;
36
37#define min(a, b) ((a) < (b) ? (a) : (b))
38#define max(a, b) ((a) > (b) ? (a) : (b))
39
40#define CR 015
41
42/* These three values memoize the current column to avoid recalculation */
43/* Some things in set last_known_column_point to -1
44 to mark the memoized value as invalid */
45/* Last value returned by current_column */
46int last_known_column;
47/* Value of point when current_column was called */
48int last_known_column_point;
49/* Value of MODIFF when current_column was called */
50int last_known_column_modified;
51
993b6404
JB
52/* Get the display table to use for the current buffer. */
53
54struct Lisp_Vector *
55buffer_display_table ()
56{
57 Lisp_Object thisbuf;
58
59 thisbuf = current_buffer->display_table;
eeaafd4f 60 if (VECTORP (thisbuf) && XVECTOR (thisbuf)->size == DISP_TABLE_SIZE)
993b6404 61 return XVECTOR (thisbuf);
eeaafd4f 62 if (VECTORP (Vstandard_display_table)
993b6404
JB
63 && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
64 return XVECTOR (Vstandard_display_table);
65 return 0;
66}
67\f
0aa01123
JB
68/* Width run cache considerations. */
69
70/* Return the width of character C under display table DP. */
71static int
72character_width (c, dp)
73 int c;
74 struct Lisp_Vector *dp;
75{
76 Lisp_Object elt;
77
78 /* These width computations were determined by examining the cases
79 in display_text_line. */
80
81 /* Some characters are never handled by the display table. */
82 if (c == '\n' || c == '\t' || c == '\015')
83 return 0;
84
85 /* Everything else might be handled by the display table, if it's
86 present and the element is right. */
87 else if (dp && (elt = DISP_CHAR_VECTOR (dp, c),
88 VECTORP (elt)))
89 return XVECTOR (elt)->size;
90
91 /* In the absence of display table perversities, printing characters
92 have width 1. */
93 else if (c >= 040 && c < 0177)
94 return 1;
95
96 /* Everybody else (control characters, metacharacters) has other
97 widths. We could return their actual widths here, but they
98 depend on things like ctl_arrow and crud like that, and they're
99 not very common at all. So we'll just claim we don't know their
100 widths. */
101 else
102 return 0;
103}
104
105/* Return true iff the display table DISPTAB specifies the same widths
106 for characters as WIDTHTAB. We use this to decide when to
107 invalidate the buffer's width_run_cache. */
108int
109disptab_matches_widthtab (disptab, widthtab)
110 struct Lisp_Vector *disptab;
111 struct Lisp_Vector *widthtab;
112{
113 int i;
114
115 if (widthtab->size != 256)
116 abort ();
117
118 for (i = 0; i < 256; i++)
119 if (character_width (i, disptab)
120 != XFASTINT (widthtab->contents[i]))
121 return 0;
122
123 return 1;
124}
125
126/* Recompute BUF's width table, using the display table DISPTAB. */
127void
128recompute_width_table (buf, disptab)
129 struct buffer *buf;
130 struct Lisp_Vector *disptab;
131{
132 int i;
228a2e1a 133 struct Lisp_Vector *widthtab;
0aa01123 134
228a2e1a
KH
135 if (!VECTORP (buf->width_table))
136 buf->width_table = Fmake_vector (make_number (256), make_number (0));
137 widthtab = XVECTOR (buf->width_table);
0aa01123
JB
138 if (widthtab->size != 256)
139 abort ();
140
141 for (i = 0; i < 256; i++)
228a2e1a 142 XSETFASTINT (widthtab->contents[i], character_width (i, disptab));
0aa01123
JB
143}
144
145/* Allocate or free the width run cache, as requested by the current
146 state of current_buffer's cache_long_line_scans variable. */
147static void
148width_run_cache_on_off ()
149{
150 if (NILP (current_buffer->cache_long_line_scans))
151 {
152 /* It should be off. */
153 if (current_buffer->width_run_cache)
154 {
155 free_region_cache (current_buffer->width_run_cache);
156 current_buffer->width_run_cache = 0;
157 current_buffer->width_table = Qnil;
158 }
159 }
160 else
161 {
162 /* It should be on. */
163 if (current_buffer->width_run_cache == 0)
164 {
165 current_buffer->width_run_cache = new_region_cache ();
0aa01123
JB
166 recompute_width_table (current_buffer, buffer_display_table ());
167 }
168 }
169}
170
171\f
993b6404
JB
172DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
173 "Return the horizontal position of point. Beginning of line is column 0.\n\
174This is calculated by adding together the widths of all the displayed\n\
175representations of the character between the start of the previous line\n\
176and point. (eg control characters will have a width of 2 or 4, tabs\n\
177will have a variable width)\n\
502b9b64
JB
178Ignores finite width of frame, which means that this function may return\n\
179values greater than (frame-width).\n\
993b6404
JB
180Whether the line is visible (if `selective-display' is t) has no effect;\n\
181however, ^M is treated as end of line when `selective-display' is t.")
182 ()
183{
184 Lisp_Object temp;
94d92e9c 185 XSETFASTINT (temp, current_column ());
993b6404
JB
186 return temp;
187}
188
e74928fc
JB
189/* Cancel any recorded value of the horizontal position. */
190
191invalidate_current_column ()
192{
193 last_known_column_point = 0;
194}
195
993b6404
JB
196int
197current_column ()
198{
199 register int col;
200 register unsigned char *ptr, *stop;
201 register int tab_seen;
202 int post_tab;
203 register int c;
204 register int tab_width = XINT (current_buffer->tab_width);
56a98455 205 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
993b6404
JB
206 register struct Lisp_Vector *dp = buffer_display_table ();
207 int stopchar;
208
209 if (point == last_known_column_point
210 && MODIFF == last_known_column_modified)
211 return last_known_column;
212
213 /* Make a pointer for decrementing through the chars before point. */
214 ptr = &FETCH_CHAR (point - 1) + 1;
215 /* Make a pointer to where consecutive chars leave off,
216 going backwards from point. */
217 if (point == BEGV)
218 stop = ptr;
219 else if (point <= GPT || BEGV > GPT)
220 stop = BEGV_ADDR;
221 else
222 stop = GAP_END_ADDR;
223
ccdcf1f5 224 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
993b6404
JB
225
226 col = 0, tab_seen = 0, post_tab = 0;
227
228 while (1)
229 {
230 if (ptr == stop)
231 {
232 /* We stopped either for the beginning of the buffer
233 or for the gap. */
234 if (ptr == BEGV_ADDR)
235 break;
236 /* It was the gap. Jump back over it. */
237 stop = BEGV_ADDR;
238 ptr = GPT_ADDR;
239 /* Check whether that brings us to beginning of buffer. */
240 if (BEGV >= GPT) break;
241 }
242
243 c = *--ptr;
244 if (c >= 040 && c < 0177
eeaafd4f 245 && (dp == 0 || !VECTORP (DISP_CHAR_VECTOR (dp, c))))
993b6404
JB
246 {
247 col++;
248 }
249 else if (c == '\n')
250 break;
251 else if (c == '\r' && EQ (current_buffer->selective_display, Qt))
252 break;
253 else if (c == '\t')
254 {
255 if (tab_seen)
256 col = ((col + tab_width) / tab_width) * tab_width;
257
258 post_tab += col;
259 col = 0;
260 tab_seen = 1;
261 }
eeaafd4f 262 else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
dea4d2e6 263 col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
993b6404
JB
264 else
265 col += (ctl_arrow && c < 0200) ? 2 : 4;
266 }
267
268 if (tab_seen)
269 {
270 col = ((col + tab_width) / tab_width) * tab_width;
271 col += post_tab;
272 }
273
274 last_known_column = col;
275 last_known_column_point = point;
276 last_known_column_modified = MODIFF;
277
278 return col;
279}
280\f
993b6404
JB
281DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
282 "Indent from point with tabs and spaces until COLUMN is reached.\n\
283Optional second argument MIN says always do at least MIN spaces\n\
284even if that goes past COLUMN; by default, MIN is zero.")
285 (col, minimum)
286 Lisp_Object col, minimum;
287{
288 int mincol;
289 register int fromcol;
290 register int tab_width = XINT (current_buffer->tab_width);
291
292 CHECK_NUMBER (col, 0);
56a98455 293 if (NILP (minimum))
94d92e9c 294 XSETFASTINT (minimum, 0);
993b6404
JB
295 CHECK_NUMBER (minimum, 1);
296
297 fromcol = current_column ();
298 mincol = fromcol + XINT (minimum);
299 if (mincol < XINT (col)) mincol = XINT (col);
300
301 if (fromcol == mincol)
302 return make_number (mincol);
303
ccdcf1f5 304 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
993b6404
JB
305
306 if (indent_tabs_mode)
307 {
308 Lisp_Object n;
94d92e9c 309 XSETFASTINT (n, mincol / tab_width - fromcol / tab_width);
993b6404
JB
310 if (XFASTINT (n) != 0)
311 {
6d1bd1a5 312 Finsert_char (make_number ('\t'), n, Qt);
993b6404
JB
313
314 fromcol = (mincol / tab_width) * tab_width;
315 }
316 }
317
94d92e9c 318 XSETFASTINT (col, mincol - fromcol);
6d1bd1a5 319 Finsert_char (make_number (' '), col, Qt);
993b6404
JB
320
321 last_known_column = mincol;
322 last_known_column_point = point;
323 last_known_column_modified = MODIFF;
324
325 XSETINT (col, mincol);
326 return col;
327}
0aa01123 328
993b6404
JB
329\f
330DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
331 0, 0, 0,
332 "Return the indentation of the current line.\n\
333This is the horizontal position of the character\n\
334following any initial whitespace.")
335 ()
336{
337 Lisp_Object val;
338
94d92e9c 339 XSETFASTINT (val, position_indentation (find_next_newline (point, -1)));
993b6404
JB
340 return val;
341}
342
343position_indentation (pos)
344 register int pos;
345{
346 register int column = 0;
347 register int tab_width = XINT (current_buffer->tab_width);
348 register unsigned char *p;
349 register unsigned char *stop;
350
ccdcf1f5 351 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
993b6404
JB
352
353 stop = &FETCH_CHAR (BUFFER_CEILING_OF (pos)) + 1;
354 p = &FETCH_CHAR (pos);
355 while (1)
356 {
357 while (p == stop)
358 {
359 if (pos == ZV)
360 return column;
361 pos += p - &FETCH_CHAR (pos);
362 p = &FETCH_CHAR (pos);
363 stop = &FETCH_CHAR (BUFFER_CEILING_OF (pos)) + 1;
364 }
365 switch (*p++)
366 {
367 case ' ':
368 column++;
369 break;
370 case '\t':
371 column += tab_width - column % tab_width;
372 break;
373 default:
374 return column;
375 }
376 }
377}
1b15e576
KH
378
379/* Test whether the line beginning at POS is indented beyond COLUMN.
380 Blank lines are treated as if they had the same indentation as the
381 preceding line. */
382int
383indented_beyond_p (pos, column)
384 int pos, column;
385{
386 while (pos > BEGV && FETCH_CHAR (pos) == '\n')
04d25c3d 387 pos = find_next_newline_no_quit (pos - 1, -1);
1b15e576
KH
388 return (position_indentation (pos) >= column);
389}
0aa01123 390
993b6404
JB
391\f
392DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, 0,
393 "Move point to column COLUMN in the current line.\n\
394The column of a character is calculated by adding together the widths\n\
395as displayed of the previous characters in the line.\n\
396This function ignores line-continuation;\n\
397there is no upper limit on the column number a character can have\n\
230a4cbd
JB
398and horizontal scrolling has no effect.\n\
399\n\
993b6404
JB
400If specified column is within a character, point goes after that character.\n\
401If it's past end of line, point goes to end of line.\n\n\
402A non-nil second (optional) argument FORCE means, if the line\n\
403is too short to reach column COLUMN then add spaces/tabs to get there,\n\
404and if COLUMN is in the middle of a tab character, change it to spaces.")
405 (column, force)
406 Lisp_Object column, force;
407{
408 register int pos;
409 register int col = current_column ();
410 register int goal;
411 register int end;
412 register int tab_width = XINT (current_buffer->tab_width);
56a98455 413 register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
993b6404
JB
414 register struct Lisp_Vector *dp = buffer_display_table ();
415
416 Lisp_Object val;
417 int prev_col;
418 int c;
419
ccdcf1f5 420 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
993b6404
JB
421 CHECK_NATNUM (column, 0);
422 goal = XINT (column);
423
424 retry:
425 pos = point;
426 end = ZV;
427
428 /* If we're starting past the desired column,
429 back up to beginning of line and scan from there. */
430 if (col > goal)
431 {
432 pos = find_next_newline (pos, -1);
433 col = 0;
434 }
435
436 while (col < goal && pos < end)
437 {
438 c = FETCH_CHAR (pos);
439 if (c == '\n')
440 break;
441 if (c == '\r' && EQ (current_buffer->selective_display, Qt))
442 break;
443 pos++;
444 if (c == '\t')
445 {
446 prev_col = col;
447 col += tab_width;
448 col = col / tab_width * tab_width;
449 }
eeaafd4f 450 else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
dea4d2e6 451 col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
993b6404 452 else if (ctl_arrow && (c < 040 || c == 0177))
bbc2998f 453 col += 2;
993b6404 454 else if (c < 040 || c >= 0177)
bbc2998f 455 col += 4;
993b6404
JB
456 else
457 col++;
458 }
459
460 SET_PT (pos);
461
462 /* If a tab char made us overshoot, change it to spaces
463 and scan through it again. */
56a98455 464 if (!NILP (force) && col > goal && c == '\t' && prev_col < goal)
993b6404 465 {
70ee42f7
JB
466 int old_point;
467
993b6404 468 del_range (point - 1, point);
70ee42f7
JB
469 Findent_to (make_number (goal), Qnil);
470 old_point = point;
471 Findent_to (make_number (col), Qnil);
472 SET_PT (old_point);
5a05d3d2
RS
473 /* Set the last_known... vars consistently. */
474 col = goal;
993b6404
JB
475 }
476
477 /* If line ends prematurely, add space to the end. */
56a98455 478 if (col < goal && !NILP (force))
230a4cbd 479 Findent_to (make_number (col = goal), Qnil);
993b6404
JB
480
481 last_known_column = col;
482 last_known_column_point = point;
483 last_known_column_modified = MODIFF;
484
94d92e9c 485 XSETFASTINT (val, col);
993b6404
JB
486 return val;
487}
0aa01123 488
993b6404 489\f
0aa01123
JB
490/* compute_motion: compute buffer posn given screen posn and vice versa */
491
993b6404
JB
492struct position val_compute_motion;
493
494/* Scan the current buffer forward from offset FROM, pretending that
495 this is at line FROMVPOS, column FROMHPOS, until reaching buffer
496 offset TO or line TOVPOS, column TOHPOS (whichever comes first),
0aa01123
JB
497 and return the ending buffer position and screen location. If we
498 can't hit the requested column exactly (because of a tab or other
499 multi-column character), overshoot.
993b6404
JB
500
501 WIDTH is the number of columns available to display text;
502 compute_motion uses this to handle continuation lines and such.
503 HSCROLL is the number of columns not being displayed at the left
504 margin; this is usually taken from a window's hscroll member.
a9764248
JB
505 TAB_OFFSET is the number of columns of the first tab that aren't
506 being displayed, perhaps because of a continuation line or
507 something.
993b6404
JB
508
509 compute_motion returns a pointer to a struct position. The bufpos
510 member gives the buffer position at the end of the scan, and hpos
0aa01123
JB
511 and vpos give its cartesian location. prevhpos is the column at
512 which the character before bufpos started, and contin is non-zero
513 if we reached the current line by continuing the previous.
514
515 Note that FROMHPOS and TOHPOS should be expressed in real screen
516 columns, taking HSCROLL and the truncation glyph at the left margin
517 into account. That is, beginning-of-line moves you to the hpos
518 -HSCROLL + (HSCROLL > 0).
993b6404 519
1827d036
KH
520 Note that FROMHPOS and TOHPOS should be expressed in real screen
521 columns, taking HSCROLL and the truncation glyph at the left margin
522 into account. That is, beginning-of-line moves you to the hpos
523 -HSCROLL + (HSCROLL > 0).
524
993b6404
JB
525 For example, to find the buffer position of column COL of line LINE
526 of a certain window, pass the window's starting location as FROM
527 and the window's upper-left coordinates as FROMVPOS and FROMHPOS.
528 Pass the buffer's ZV as TO, to limit the scan to the end of the
529 visible section of the buffer, and pass LINE and COL as TOVPOS and
530 TOHPOS.
531
532 When displaying in window w, a typical formula for WIDTH is:
533
534 window_width - 1
a3c87d4e 535 - (has_vertical_scroll_bars
40284d6b 536 ? FRAME_SCROLL_BAR_COLS (XFRAME (window->frame))
fa61c701 537 : (window_width + window_left != frame_width))
993b6404
JB
538
539 where
540 window_width is XFASTINT (w->width),
541 window_left is XFASTINT (w->left),
a3c87d4e
JB
542 has_vertical_scroll_bars is
543 FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (WINDOW_FRAME (window)))
fa61c701 544 and frame_width = FRAME_WIDTH (XFRAME (window->frame))
993b6404 545
1827d036
KH
546 Or you can let window_internal_width do this all for you, and write:
547 window_internal_width (w) - 1
fa61c701
JB
548
549 The `-1' accounts for the continuation-line backslashes; the rest
7e7a76b5 550 accounts for window borders if the window is split horizontally, and
1827d036 551 the scroll bars if they are turned on. */
993b6404
JB
552
553struct position *
88af3af4 554compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, tab_offset, win)
993b6404
JB
555 int from, fromvpos, fromhpos, to, tovpos, tohpos;
556 register int width;
557 int hscroll, tab_offset;
88af3af4 558 struct window *win;
993b6404 559{
cde9337b
JB
560 register int hpos = fromhpos;
561 register int vpos = fromvpos;
562
993b6404
JB
563 register int pos;
564 register int c;
565 register int tab_width = XFASTINT (current_buffer->tab_width);
56a98455 566 register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
88af3af4 567 register struct Lisp_Vector *dp = window_display_table (win);
993b6404 568 int selective
eeaafd4f 569 = (INTEGERP (current_buffer->selective_display)
69eaf10d
RS
570 ? XINT (current_buffer->selective_display)
571 : !NILP (current_buffer->selective_display) ? -1 : 0);
0aa01123 572 int prev_vpos = vpos, prev_hpos = 0;
993b6404 573 int selective_rlen
eeaafd4f 574 = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
dea4d2e6 575 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0);
5a05d3d2
RS
576#ifdef USE_TEXT_PROPERTIES
577 /* The next location where the `invisible' property changes */
578 int next_invisible = from;
579 Lisp_Object prop, position;
580#endif
993b6404 581
0aa01123
JB
582 /* For computing runs of characters with similar widths.
583 Invariant: width_run_width is zero, or all the characters
584 from width_run_start to width_run_end have a fixed width of
585 width_run_width. */
586 int width_run_start = from;
587 int width_run_end = from;
588 int width_run_width = 0;
589 Lisp_Object *width_table;
590
591 /* The next buffer pos where we should consult the width run cache. */
592 int next_width_run = from;
593
594 width_run_cache_on_off ();
595 if (dp == buffer_display_table ())
596 width_table = (VECTORP (current_buffer->width_table)
597 ? XVECTOR (current_buffer->width_table)->contents
598 : 0);
599 else
600 /* If the window has its own display table, we can't use the width
601 run cache, because that's based on the buffer's display table. */
602 width_table = 0;
603
ccdcf1f5 604 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
0aa01123 605 for (pos = from; pos < to; )
993b6404 606 {
cde9337b
JB
607 /* Stop if past the target screen position. */
608 if (vpos > tovpos
609 || (vpos == tovpos && hpos >= tohpos))
610 break;
611
612 prev_vpos = vpos;
613 prev_hpos = hpos;
614
5a05d3d2
RS
615#ifdef USE_TEXT_PROPERTIES
616 /* if the `invisible' property is set, we can skip to
617 the next property change */
618 while (pos == next_invisible && pos < to)
f75c0f8a 619 {
94d92e9c 620 XSETFASTINT (position, pos);
67406ef4 621 prop = Fget_char_property (position,
f75c0f8a
RS
622 Qinvisible,
623 Fcurrent_buffer ());
624 {
625 Lisp_Object end, limit;
626
90ed3777 627 recenter_overlay_lists (current_buffer, pos);
f75c0f8a
RS
628 /* This is just an estimate to give reasonable
629 performance; nothing should go wrong if it is too small. */
7ea9c020
KH
630 limit = Fnext_overlay_change (position);
631 if (XFASTINT (limit) > pos + 100)
94d92e9c 632 XSETFASTINT (limit, pos + 100);
f75c0f8a
RS
633 end = Fnext_single_property_change (position, Qinvisible,
634 Fcurrent_buffer (), limit);
635 if (INTEGERP (end))
636 next_invisible = XINT (end);
637 else
638 next_invisible = to;
639 if (! NILP (prop))
640 pos = next_invisible;
641 }
642 }
5a05d3d2
RS
643 if (pos >= to)
644 break;
645#endif
0aa01123
JB
646
647 /* Consult the width run cache to see if we can avoid inspecting
648 the text character-by-character. */
649 if (current_buffer->width_run_cache && pos >= next_width_run)
650 {
651 int run_end;
652 int common_width
653 = region_cache_forward (current_buffer,
654 current_buffer->width_run_cache,
655 pos, &run_end);
656
657 /* A width of zero means the character's width varies (like
658 a tab), is meaningless (like a newline), or we just don't
659 want to skip over it for some other reason. */
660 if (common_width != 0)
661 {
662 int run_end_hpos;
663
664 /* Don't go past the final buffer posn the user
665 requested. */
666 if (run_end > to)
667 run_end = to;
668
669 run_end_hpos = hpos + (run_end - pos) * common_width;
670
671 /* Don't go past the final horizontal position the user
672 requested. */
673 if (vpos == tovpos && run_end_hpos > tohpos)
674 {
675 run_end = pos + (tohpos - hpos) / common_width;
676 run_end_hpos = hpos + (run_end - pos) * common_width;
677 }
678
679 /* Don't go past the margin. */
680 if (run_end_hpos >= width)
681 {
682 run_end = pos + (width - hpos) / common_width;
683 run_end_hpos = hpos + (run_end - pos) * common_width;
684 }
685
686 hpos = run_end_hpos;
687 if (run_end > pos)
688 prev_hpos = hpos - common_width;
689 pos = run_end;
690 }
691
692 next_width_run = run_end + 1;
693 }
694
695 /* We have to scan the text character-by-character. */
993b6404 696 else
0aa01123
JB
697 {
698 c = FETCH_CHAR (pos);
699 pos++;
700
701 /* Perhaps add some info to the width_run_cache. */
702 if (current_buffer->width_run_cache)
703 {
704 /* Is this character part of the current run? If so, extend
705 the run. */
706 if (pos - 1 == width_run_end
707 && width_table[c] == width_run_width)
708 width_run_end = pos;
709
710 /* The previous run is over, since this is a character at a
711 different position, or a different width. */
712 else
713 {
714 /* Have we accumulated a run to put in the cache?
715 (Currently, we only cache runs of width == 1. */
716 if (width_run_start < width_run_end
717 && width_run_width == 1)
718 know_region_cache (current_buffer,
719 current_buffer->width_run_cache,
720 width_run_start, width_run_end);
721
722 /* Start recording a new width run. */
723 width_run_width = width_table[c];
724 width_run_start = pos - 1;
725 width_run_end = pos;
726 }
727 }
728
729 if (c >= 040 && c < 0177
730 && (dp == 0 || ! VECTORP (DISP_CHAR_VECTOR (dp, c))))
731 hpos++;
732 else if (c == '\t')
733 {
734 hpos += tab_width - ((hpos + tab_offset + hscroll - (hscroll > 0)
735 /* Add tab_width here to make sure
736 positive. hpos can be negative
737 after continuation but can't be
738 less than -tab_width. */
739 + tab_width)
740 % tab_width);
741 }
742 else if (c == '\n')
743 {
744 if (selective > 0 && indented_beyond_p (pos, selective))
745 {
746 /* Skip any number of invisible lines all at once */
747 do
748 pos = find_before_next_newline (pos, to, 1);
749 while (pos < to
750 && indented_beyond_p (pos, selective));
751 /* Allow for the " ..." that is displayed for them. */
752 if (selective_rlen)
753 {
754 hpos += selective_rlen;
755 if (hpos >= width)
756 hpos = width;
757 }
758 /* We have skipped the invis text, but not the
759 newline after. */
760 }
761 else
762 {
763 /* A visible line. */
764 vpos++;
765 hpos = 0;
766 hpos -= hscroll;
767 /* Count the truncation glyph on column 0 */
768 if (hscroll > 0)
769 hpos++;
770 tab_offset = 0;
771 }
772 }
773 else if (c == CR && selective < 0)
774 {
775 /* In selective display mode,
776 everything from a ^M to the end of the line is invisible.
777 Stop *before* the real newline. */
778 pos = find_before_next_newline (pos, to, 1);
779 /* Allow for the " ..." that is displayed for them. */
780 if (selective_rlen)
781 {
782 hpos += selective_rlen;
783 if (hpos >= width)
784 hpos = width;
785 }
786 }
787 else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
788 hpos += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
789 else
790 hpos += (ctl_arrow && c < 0200) ? 2 : 4;
791 }
993b6404 792
cde9337b
JB
793 /* Handle right margin. */
794 if (hpos >= width
795 && (hpos > width
0aa01123
JB
796 || (pos < ZV
797 && FETCH_CHAR (pos) != '\n')))
993b6404 798 {
cde9337b
JB
799 if (vpos > tovpos
800 || (vpos == tovpos && hpos >= tohpos))
993b6404
JB
801 break;
802 if (hscroll
803 || (truncate_partial_width_windows
5d83b593 804 && width + 1 < FRAME_WIDTH (XFRAME (WINDOW_FRAME (win))))
56a98455 805 || !NILP (current_buffer->truncate_lines))
993b6404 806 {
cde9337b 807 /* Truncating: skip to newline. */
0aa01123 808 pos = find_before_next_newline (pos, to, 1);
e51eab7c 809 hpos = width;
993b6404
JB
810 }
811 else
812 {
cde9337b
JB
813 /* Continuing. */
814 vpos++;
815 hpos -= width;
993b6404
JB
816 tab_offset += width;
817 }
818
819 }
820 }
821
0aa01123
JB
822 /* Remember any final width run in the cache. */
823 if (current_buffer->width_run_cache
824 && width_run_width == 1
825 && width_run_start < width_run_end)
826 know_region_cache (current_buffer, current_buffer->width_run_cache,
827 width_run_start, width_run_end);
828
993b6404 829 val_compute_motion.bufpos = pos;
cde9337b
JB
830 val_compute_motion.hpos = hpos;
831 val_compute_motion.vpos = vpos;
832 val_compute_motion.prevhpos = prev_hpos;
993b6404
JB
833
834 /* Nonzero if have just continued a line */
835 val_compute_motion.contin
cde9337b
JB
836 = (pos != from
837 && (val_compute_motion.vpos != prev_vpos)
838 && c != '\n');
993b6404
JB
839
840 return &val_compute_motion;
841}
993b6404 842
992371ca
KH
843#if 0 /* The doc string is too long for some compilers,
844 but make-docfile can find it in this comment. */
88af3af4 845DEFUN ("compute-motion", Ffoo, Sfoo, 7, 7, 0,
42918ba5
RS
846 "Scan through the current buffer, calculating screen position.\n\
847Scan the current buffer forward from offset FROM,\n\
848assuming it is at position FROMPOS--a cons of the form (HPOS . VPOS)--\n\
849to position TO or position TOPOS--another cons of the form (HPOS . VPOS)--\n\
850and return the ending buffer position and screen location.\n\
851\n\
88af3af4 852There are three additional arguments:\n\
42918ba5
RS
853\n\
854WIDTH is the number of columns available to display text;\n\
855this affects handling of continuation lines.\n\
992371ca
KH
856This is usually the value returned by `window-width', less one (to allow\n\
857for the continuation glyph).\n\
42918ba5
RS
858\n\
859OFFSETS is either nil or a cons cell (HSCROLL . TAB-OFFSET).\n\
860HSCROLL is the number of columns not being displayed at the left\n\
861margin; this is usually taken from a window's hscroll member.\n\
862TAB-OFFSET is the number of columns of the first tab that aren't\n\
863being displayed, perhaps because the line was continued within it.\n\
4fb76787 864If OFFSETS is nil, HSCROLL and TAB-OFFSET are assumed to be zero.\n\
69eaf10d 865\n\
88af3af4 866WINDOW is the window to operate on. Currently this is used only to\n\
69eaf10d
RS
867find the display table. It does not matter what buffer WINDOW displays;\n\
868`compute-motion' always operates on the current buffer.\n\
42918ba5
RS
869\n\
870The value is a list of five elements:\n\
faa5c515 871 (POS HPOS VPOS PREVHPOS CONTIN)\n\
42918ba5
RS
872POS is the buffer position where the scan stopped.\n\
873VPOS is the vertical position where the scan stopped.\n\
874HPOS is the horizontal position where the scan stopped.\n\
875\n\
876PREVHPOS is the horizontal position one character back from POS.\n\
877CONTIN is t if a line was continued after (or within) the previous character.\n\
878\n\
879For example, to find the buffer position of column COL of line LINE\n\
880of a certain window, pass the window's starting location as FROM\n\
881and the window's upper-left coordinates as FROMPOS.\n\
882Pass the buffer's (point-max) as TO, to limit the scan to the end of the\n\
883visible section of the buffer, and pass LINE and COL as TOPOS.")
5844e1c4 884 (from, frompos, to, topos, width, offsets, window)
992371ca
KH
885#endif
886
88af3af4 887DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0,
992371ca 888 0)
88af3af4 889 (from, frompos, to, topos, width, offsets, window)
42918ba5 890 Lisp_Object from, frompos, to, topos;
88af3af4 891 Lisp_Object width, offsets, window;
42918ba5
RS
892{
893 Lisp_Object bufpos, hpos, vpos, prevhpos, contin;
894 struct position *pos;
895 int hscroll, tab_offset;
896
26a8d14b 897 CHECK_NUMBER_COERCE_MARKER (from, 0);
42918ba5 898 CHECK_CONS (frompos, 0);
26a8d14b
KH
899 CHECK_NUMBER (XCONS (frompos)->car, 0);
900 CHECK_NUMBER (XCONS (frompos)->cdr, 0);
901 CHECK_NUMBER_COERCE_MARKER (to, 0);
42918ba5 902 CHECK_CONS (topos, 0);
26a8d14b
KH
903 CHECK_NUMBER (XCONS (topos)->car, 0);
904 CHECK_NUMBER (XCONS (topos)->cdr, 0);
905 CHECK_NUMBER (width, 0);
42918ba5
RS
906 if (!NILP (offsets))
907 {
908 CHECK_CONS (offsets, 0);
26a8d14b
KH
909 CHECK_NUMBER (XCONS (offsets)->car, 0);
910 CHECK_NUMBER (XCONS (offsets)->cdr, 0);
42918ba5
RS
911 hscroll = XINT (XCONS (offsets)->car);
912 tab_offset = XINT (XCONS (offsets)->cdr);
913 }
914 else
915 hscroll = tab_offset = 0;
916
88af3af4
KH
917 if (NILP (window))
918 window = Fselected_window ();
919 else
920 CHECK_LIVE_WINDOW (window, 0);
921
42918ba5
RS
922 pos = compute_motion (XINT (from), XINT (XCONS (frompos)->cdr),
923 XINT (XCONS (frompos)->car),
924 XINT (to), XINT (XCONS (topos)->cdr),
925 XINT (XCONS (topos)->car),
88af3af4
KH
926 XINT (width), hscroll, tab_offset,
927 XWINDOW (window));
42918ba5 928
94d92e9c 929 XSETFASTINT (bufpos, pos->bufpos);
f8f645a1
KH
930 XSETINT (hpos, pos->hpos);
931 XSETINT (vpos, pos->vpos);
932 XSETINT (prevhpos, pos->prevhpos);
42918ba5
RS
933
934 return Fcons (bufpos,
935 Fcons (hpos,
936 Fcons (vpos,
937 Fcons (prevhpos,
938 Fcons (pos->contin ? Qt : Qnil, Qnil)))));
939
940}
993b6404 941\f
0aa01123
JB
942/* Return the column of position POS in window W's buffer.
943 The result is rounded down to a multiple of the internal width of W.
993b6404
JB
944 This is the amount of indentation of position POS
945 that is not visible in its horizontal position in the window. */
946
947int
948pos_tab_offset (w, pos)
949 struct window *w;
950 register int pos;
951{
3d94e943 952 int opoint = PT;
993b6404 953 int col;
fa61c701 954 int width = window_internal_width (w) - 1;
993b6404
JB
955
956 if (pos == BEGV || FETCH_CHAR (pos - 1) == '\n')
957 return 0;
3d94e943 958 TEMP_SET_PT (pos);
993b6404 959 col = current_column ();
3d94e943 960 TEMP_SET_PT (opoint);
993b6404
JB
961 return col - (col % width);
962}
963
0aa01123
JB
964\f
965/* Fvertical_motion and vmotion */
993b6404
JB
966struct position val_vmotion;
967
968struct position *
969vmotion (from, vtarget, width, hscroll, window)
970 register int from, vtarget, width;
971 int hscroll;
972 Lisp_Object window;
973{
974 struct position pos;
975 /* vpos is cumulative vertical position, changed as from is changed */
976 register int vpos = 0;
92992c7e 977 Lisp_Object prevline;
993b6404
JB
978 register int first;
979 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
980 int selective
eeaafd4f
KH
981 = (INTEGERP (current_buffer->selective_display)
982 ? XINT (current_buffer->selective_display)
983 : !NILP (current_buffer->selective_display) ? -1 : 0);
cb1068e5
KH
984 /* The omission of the clause
985 && marker_position (XWINDOW (window)->start) == BEG
986 here is deliberate; I think we want to measure from the prompt
987 position even if the minibuffer window has scrolled. */
988 int start_hpos = (EQ (window, minibuf_window) ? minibuf_prompt_width : 0);
993b6404
JB
989
990 retry:
991 if (vtarget > vpos)
992 {
993 /* Moving downward is simple, but must calculate from beg of line
994 to determine hpos of starting point */
995 if (from > BEGV && FETCH_CHAR (from - 1) != '\n')
996 {
94d92e9c 997 XSETFASTINT (prevline, find_next_newline_no_quit (from, -1));
92992c7e 998 while (XFASTINT (prevline) > BEGV
5a05d3d2 999 && ((selective > 0
92992c7e 1000 && indented_beyond_p (XFASTINT (prevline), selective))
5a05d3d2
RS
1001#ifdef USE_TEXT_PROPERTIES
1002 /* watch out for newlines with `invisible' property */
92992c7e 1003 || ! NILP (Fget_char_property (prevline,
5a05d3d2 1004 Qinvisible,
67406ef4 1005 window))
5a05d3d2
RS
1006#endif
1007 ))
94d92e9c
KH
1008 XSETFASTINT (prevline,
1009 find_next_newline_no_quit (XFASTINT (prevline) - 1,
1010 -1));
92992c7e
KH
1011 pos = *compute_motion (XFASTINT (prevline), 0,
1012 lmargin + (XFASTINT (prevline) == 1
1013 ? start_hpos : 0),
cde9337b 1014 from, 1 << (INTBITS - 2), 0,
88af3af4 1015 width, hscroll, 0, XWINDOW (window));
993b6404
JB
1016 }
1017 else
1018 {
1019 pos.hpos = lmargin + (from == 1 ? start_hpos : 0);
1020 pos.vpos = 0;
1021 }
1022 return compute_motion (from, vpos, pos.hpos,
cde9337b 1023 ZV, vtarget, - (1 << (INTBITS - 2)),
88af3af4
KH
1024 width, hscroll, pos.vpos * width,
1025 XWINDOW (window));
993b6404
JB
1026 }
1027
1028 /* To move upward, go a line at a time until
1029 we have gone at least far enough */
1030
1031 first = 1;
1032
1033 while ((vpos > vtarget || first) && from > BEGV)
1034 {
94d92e9c 1035 XSETFASTINT (prevline, from);
993b6404
JB
1036 while (1)
1037 {
94d92e9c
KH
1038 XSETFASTINT (prevline,
1039 find_next_newline_no_quit (XFASTINT (prevline) - 1,
1040 -1));
92992c7e 1041 if (XFASTINT (prevline) == BEGV
5a05d3d2 1042 || ((selective <= 0
92992c7e 1043 || ! indented_beyond_p (XFASTINT (prevline), selective))
5a05d3d2
RS
1044#ifdef USE_TEXT_PROPERTIES
1045 /* watch out for newlines with `invisible' property */
92992c7e 1046 && NILP (Fget_char_property (prevline, Qinvisible, window))
5a05d3d2
RS
1047#endif
1048 ))
993b6404
JB
1049 break;
1050 }
92992c7e
KH
1051 pos = *compute_motion (XFASTINT (prevline), 0,
1052 lmargin + (XFASTINT (prevline) == 1
1053 ? start_hpos : 0),
cde9337b 1054 from, 1 << (INTBITS - 2), 0,
88af3af4 1055 width, hscroll, 0, XWINDOW (window));
993b6404
JB
1056 vpos -= pos.vpos;
1057 first = 0;
92992c7e 1058 from = XFASTINT (prevline);
993b6404
JB
1059 }
1060
1061 /* If we made exactly the desired vertical distance,
1062 or if we hit beginning of buffer,
1063 return point found */
1064 if (vpos >= vtarget)
1065 {
1066 val_vmotion.bufpos = from;
1067 val_vmotion.vpos = vpos;
1068 val_vmotion.hpos = lmargin;
1069 val_vmotion.contin = 0;
1070 val_vmotion.prevhpos = 0;
1071 return &val_vmotion;
1072 }
1073
1074 /* Otherwise find the correct spot by moving down */
1075 goto retry;
1076}
1077
f1ecfe9b 1078DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 2, 0,
993b6404
JB
1079 "Move to start of screen line LINES lines down.\n\
1080If LINES is negative, this is moving up.\n\
69eaf10d
RS
1081\n\
1082The optional second argument WINDOW specifies the window to use for\n\
1083parameters such as width, horizontal scrolling, and so on.\n\
1084the default is the selected window.\n\
1085It does not matter what buffer is displayed in WINDOW.\n\
1086`vertical-motion' always uses the current buffer.\n\
1087\n\
993b6404 1088Sets point to position found; this may be start of line\n\
69eaf10d 1089or just the start of a continuation line.\n\
993b6404 1090Returns number of lines moved; may be closer to zero than LINES\n\
69eaf10d 1091if beginning or end of buffer was reached.")
f1ecfe9b
RS
1092 (lines, window)
1093 Lisp_Object lines, window;
993b6404
JB
1094{
1095 struct position pos;
230a75fc 1096 register struct window *w;
993b6404
JB
1097
1098 CHECK_NUMBER (lines, 0);
f1ecfe9b
RS
1099 if (! NILP (window))
1100 CHECK_WINDOW (window, 0);
1101 else
92992c7e 1102 window = selected_window;
993b6404 1103
230a75fc 1104 w = XWINDOW (window);
69eaf10d 1105
230a75fc 1106 pos = *vmotion (point, XINT (lines), window_internal_width (w) - 1,
993b6404 1107 /* Not XFASTINT since perhaps could be negative */
f1ecfe9b 1108 XINT (w->hscroll), window);
993b6404
JB
1109
1110 SET_PT (pos.bufpos);
1111 return make_number (pos.vpos);
1112}
1113\f
0aa01123
JB
1114/* file's initialization. */
1115
993b6404
JB
1116syms_of_indent ()
1117{
1118 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
1119 "*Indentation can insert tabs if this is non-nil.\n\
1120Setting this variable automatically makes it local to the current buffer.");
1121 indent_tabs_mode = 1;
1122
1123 defsubr (&Scurrent_indentation);
1124 defsubr (&Sindent_to);
1125 defsubr (&Scurrent_column);
1126 defsubr (&Smove_to_column);
1127 defsubr (&Svertical_motion);
42918ba5 1128 defsubr (&Scompute_motion);
993b6404 1129}