(Fforward_comment): Always clear immediate_quit for return.
[bpt/emacs.git] / src / indent.c
1 /* Indentation functions.
2 Copyright (C) 1985,86,87,88,93,94,95 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21 #include <config.h>
22 #include "lisp.h"
23 #include "buffer.h"
24 #include "indent.h"
25 #include "frame.h"
26 #include "window.h"
27 #include "termchar.h"
28 #include "termopts.h"
29 #include "disptab.h"
30 #include "intervals.h"
31 #include "region-cache.h"
32
33 /* Indentation can insert tabs if this is non-zero;
34 otherwise always uses spaces */
35 int 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 */
46 int last_known_column;
47 /* Value of point when current_column was called */
48 int last_known_column_point;
49 /* Value of MODIFF when current_column was called */
50 int last_known_column_modified;
51
52 /* Get the display table to use for the current buffer. */
53
54 struct Lisp_Vector *
55 buffer_display_table ()
56 {
57 Lisp_Object thisbuf;
58
59 thisbuf = current_buffer->display_table;
60 if (VECTORP (thisbuf) && XVECTOR (thisbuf)->size == DISP_TABLE_SIZE)
61 return XVECTOR (thisbuf);
62 if (VECTORP (Vstandard_display_table)
63 && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
64 return XVECTOR (Vstandard_display_table);
65 return 0;
66 }
67 \f
68 /* Width run cache considerations. */
69
70 /* Return the width of character C under display table DP. */
71 static int
72 character_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. */
108 int
109 disptab_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. */
127 void
128 recompute_width_table (buf, disptab)
129 struct buffer *buf;
130 struct Lisp_Vector *disptab;
131 {
132 int i;
133 struct Lisp_Vector *widthtab;
134
135 if (!VECTORP (buf->width_table))
136 buf->width_table = Fmake_vector (make_number (256), make_number (0));
137 widthtab = XVECTOR (buf->width_table);
138 if (widthtab->size != 256)
139 abort ();
140
141 for (i = 0; i < 256; i++)
142 XSETFASTINT (widthtab->contents[i], character_width (i, disptab));
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. */
147 static void
148 width_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 ();
166 recompute_width_table (current_buffer, buffer_display_table ());
167 }
168 }
169 }
170
171 \f
172 DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
173 "Return the horizontal position of point. Beginning of line is column 0.\n\
174 This is calculated by adding together the widths of all the displayed\n\
175 representations of the character between the start of the previous line\n\
176 and point. (eg control characters will have a width of 2 or 4, tabs\n\
177 will have a variable width)\n\
178 Ignores finite width of frame, which means that this function may return\n\
179 values greater than (frame-width).\n\
180 Whether the line is visible (if `selective-display' is t) has no effect;\n\
181 however, ^M is treated as end of line when `selective-display' is t.")
182 ()
183 {
184 Lisp_Object temp;
185 XSETFASTINT (temp, current_column ());
186 return temp;
187 }
188
189 /* Cancel any recorded value of the horizontal position. */
190
191 invalidate_current_column ()
192 {
193 last_known_column_point = 0;
194 }
195
196 int
197 current_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);
205 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
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
224 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
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
245 && (dp == 0 || !VECTORP (DISP_CHAR_VECTOR (dp, c))))
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 }
262 else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
263 col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
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
281 DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
282 "Indent from point with tabs and spaces until COLUMN is reached.\n\
283 Optional second argument MIN says always do at least MIN spaces\n\
284 even 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);
293 if (NILP (minimum))
294 XSETFASTINT (minimum, 0);
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
304 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
305
306 if (indent_tabs_mode)
307 {
308 Lisp_Object n;
309 XSETFASTINT (n, mincol / tab_width - fromcol / tab_width);
310 if (XFASTINT (n) != 0)
311 {
312 Finsert_char (make_number ('\t'), n, Qt);
313
314 fromcol = (mincol / tab_width) * tab_width;
315 }
316 }
317
318 XSETFASTINT (col, mincol - fromcol);
319 Finsert_char (make_number (' '), col, Qt);
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 }
328
329 \f
330 DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
331 0, 0, 0,
332 "Return the indentation of the current line.\n\
333 This is the horizontal position of the character\n\
334 following any initial whitespace.")
335 ()
336 {
337 Lisp_Object val;
338
339 XSETFASTINT (val, position_indentation (find_next_newline (point, -1)));
340 return val;
341 }
342
343 position_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
351 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
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 }
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. */
382 int
383 indented_beyond_p (pos, column)
384 int pos, column;
385 {
386 while (pos > BEGV && FETCH_CHAR (pos) == '\n')
387 pos = find_next_newline_no_quit (pos - 1, -1);
388 return (position_indentation (pos) >= column);
389 }
390
391 \f
392 DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, 0,
393 "Move point to column COLUMN in the current line.\n\
394 The column of a character is calculated by adding together the widths\n\
395 as displayed of the previous characters in the line.\n\
396 This function ignores line-continuation;\n\
397 there is no upper limit on the column number a character can have\n\
398 and horizontal scrolling has no effect.\n\
399 \n\
400 If specified column is within a character, point goes after that character.\n\
401 If it's past end of line, point goes to end of line.\n\n\
402 A non-nil second (optional) argument FORCE means, if the line\n\
403 is too short to reach column COLUMN then add spaces/tabs to get there,\n\
404 and 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);
413 register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
414 register struct Lisp_Vector *dp = buffer_display_table ();
415
416 Lisp_Object val;
417 int prev_col;
418 int c;
419
420 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
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 }
450 else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
451 col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
452 else if (ctl_arrow && (c < 040 || c == 0177))
453 col += 2;
454 else if (c < 040 || c >= 0177)
455 col += 4;
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. */
464 if (!NILP (force) && col > goal && c == '\t' && prev_col < goal)
465 {
466 int old_point;
467
468 del_range (point - 1, point);
469 Findent_to (make_number (goal), Qnil);
470 old_point = point;
471 Findent_to (make_number (col), Qnil);
472 SET_PT (old_point);
473 /* Set the last_known... vars consistently. */
474 col = goal;
475 }
476
477 /* If line ends prematurely, add space to the end. */
478 if (col < goal && !NILP (force))
479 Findent_to (make_number (col = goal), Qnil);
480
481 last_known_column = col;
482 last_known_column_point = point;
483 last_known_column_modified = MODIFF;
484
485 XSETFASTINT (val, col);
486 return val;
487 }
488
489 \f
490 /* compute_motion: compute buffer posn given screen posn and vice versa */
491
492 struct 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),
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.
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.
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.
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
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).
519
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
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
535 - (has_vertical_scroll_bars
536 ? FRAME_SCROLL_BAR_COLS (XFRAME (window->frame))
537 : (window_width + window_left != frame_width))
538
539 where
540 window_width is XFASTINT (w->width),
541 window_left is XFASTINT (w->left),
542 has_vertical_scroll_bars is
543 FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (WINDOW_FRAME (window)))
544 and frame_width = FRAME_WIDTH (XFRAME (window->frame))
545
546 Or you can let window_internal_width do this all for you, and write:
547 window_internal_width (w) - 1
548
549 The `-1' accounts for the continuation-line backslashes; the rest
550 accounts for window borders if the window is split horizontally, and
551 the scroll bars if they are turned on. */
552
553 struct position *
554 compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, tab_offset, win)
555 int from, fromvpos, fromhpos, to, tovpos, tohpos;
556 register int width;
557 int hscroll, tab_offset;
558 struct window *win;
559 {
560 register int hpos = fromhpos;
561 register int vpos = fromvpos;
562
563 register int pos;
564 register int c;
565 register int tab_width = XFASTINT (current_buffer->tab_width);
566 register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
567 register struct Lisp_Vector *dp = window_display_table (win);
568 int selective
569 = (INTEGERP (current_buffer->selective_display)
570 ? XINT (current_buffer->selective_display)
571 : !NILP (current_buffer->selective_display) ? -1 : 0);
572 int prev_vpos = vpos, prev_hpos = 0;
573 int selective_rlen
574 = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
575 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0);
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
581
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
604 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
605 for (pos = from; pos < to; )
606 {
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
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)
619 {
620 XSETFASTINT (position, pos);
621 prop = Fget_char_property (position,
622 Qinvisible,
623 Fcurrent_buffer ());
624 {
625 Lisp_Object end, limit;
626
627 recenter_overlay_lists (current_buffer, pos);
628 /* This is just an estimate to give reasonable
629 performance; nothing should go wrong if it is too small. */
630 limit = Fnext_overlay_change (position);
631 if (XFASTINT (limit) > pos + 100)
632 XSETFASTINT (limit, pos + 100);
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 }
643 if (pos >= to)
644 break;
645 #endif
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. */
696 else
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) + 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 --pos;
759 /* We have skipped the invis text, but not the
760 newline after. */
761 }
762 else
763 {
764 /* A visible line. */
765 vpos++;
766 hpos = 0;
767 hpos -= hscroll;
768 /* Count the truncation glyph on column 0 */
769 if (hscroll > 0)
770 hpos++;
771 tab_offset = 0;
772 }
773 }
774 else if (c == CR && selective < 0)
775 {
776 /* In selective display mode,
777 everything from a ^M to the end of the line is invisible.
778 Stop *before* the real newline. */
779 pos = find_before_next_newline (pos, to, 1);
780 /* Allow for the " ..." that is displayed for them. */
781 if (selective_rlen)
782 {
783 hpos += selective_rlen;
784 if (hpos >= width)
785 hpos = width;
786 }
787 }
788 else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
789 hpos += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
790 else
791 hpos += (ctl_arrow && c < 0200) ? 2 : 4;
792 }
793
794 /* Handle right margin. */
795 if (hpos >= width
796 && (hpos > width
797 || (pos < ZV
798 && FETCH_CHAR (pos) != '\n')))
799 {
800 if (vpos > tovpos
801 || (vpos == tovpos && hpos >= tohpos))
802 break;
803 if (hscroll
804 || (truncate_partial_width_windows
805 && width + 1 < FRAME_WIDTH (XFRAME (WINDOW_FRAME (win))))
806 || !NILP (current_buffer->truncate_lines))
807 {
808 /* Truncating: skip to newline. */
809 pos = find_before_next_newline (pos, to, 1);
810 hpos = width;
811 }
812 else
813 {
814 /* Continuing. */
815 vpos++;
816 hpos -= width;
817 tab_offset += width;
818 }
819
820 }
821 }
822
823 /* Remember any final width run in the cache. */
824 if (current_buffer->width_run_cache
825 && width_run_width == 1
826 && width_run_start < width_run_end)
827 know_region_cache (current_buffer, current_buffer->width_run_cache,
828 width_run_start, width_run_end);
829
830 val_compute_motion.bufpos = pos;
831 val_compute_motion.hpos = hpos;
832 val_compute_motion.vpos = vpos;
833 val_compute_motion.prevhpos = prev_hpos;
834
835 /* Nonzero if have just continued a line */
836 val_compute_motion.contin
837 = (pos != from
838 && (val_compute_motion.vpos != prev_vpos)
839 && c != '\n');
840
841 return &val_compute_motion;
842 }
843
844 #if 0 /* The doc string is too long for some compilers,
845 but make-docfile can find it in this comment. */
846 DEFUN ("compute-motion", Ffoo, Sfoo, 7, 7, 0,
847 "Scan through the current buffer, calculating screen position.\n\
848 Scan the current buffer forward from offset FROM,\n\
849 assuming it is at position FROMPOS--a cons of the form (HPOS . VPOS)--\n\
850 to position TO or position TOPOS--another cons of the form (HPOS . VPOS)--\n\
851 and return the ending buffer position and screen location.\n\
852 \n\
853 There are three additional arguments:\n\
854 \n\
855 WIDTH is the number of columns available to display text;\n\
856 this affects handling of continuation lines.\n\
857 This is usually the value returned by `window-width', less one (to allow\n\
858 for the continuation glyph).\n\
859 \n\
860 OFFSETS is either nil or a cons cell (HSCROLL . TAB-OFFSET).\n\
861 HSCROLL is the number of columns not being displayed at the left\n\
862 margin; this is usually taken from a window's hscroll member.\n\
863 TAB-OFFSET is the number of columns of the first tab that aren't\n\
864 being displayed, perhaps because the line was continued within it.\n\
865 If OFFSETS is nil, HSCROLL and TAB-OFFSET are assumed to be zero.\n\
866 \n\
867 WINDOW is the window to operate on. Currently this is used only to\n\
868 find the display table. It does not matter what buffer WINDOW displays;\n\
869 `compute-motion' always operates on the current buffer.\n\
870 \n\
871 The value is a list of five elements:\n\
872 (POS HPOS VPOS PREVHPOS CONTIN)\n\
873 POS is the buffer position where the scan stopped.\n\
874 VPOS is the vertical position where the scan stopped.\n\
875 HPOS is the horizontal position where the scan stopped.\n\
876 \n\
877 PREVHPOS is the horizontal position one character back from POS.\n\
878 CONTIN is t if a line was continued after (or within) the previous character.\n\
879 \n\
880 For example, to find the buffer position of column COL of line LINE\n\
881 of a certain window, pass the window's starting location as FROM\n\
882 and the window's upper-left coordinates as FROMPOS.\n\
883 Pass the buffer's (point-max) as TO, to limit the scan to the end of the\n\
884 visible section of the buffer, and pass LINE and COL as TOPOS.")
885 (from, frompos, to, topos, width, offsets, window)
886 #endif
887
888 DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0,
889 0)
890 (from, frompos, to, topos, width, offsets, window)
891 Lisp_Object from, frompos, to, topos;
892 Lisp_Object width, offsets, window;
893 {
894 Lisp_Object bufpos, hpos, vpos, prevhpos, contin;
895 struct position *pos;
896 int hscroll, tab_offset;
897
898 CHECK_NUMBER_COERCE_MARKER (from, 0);
899 CHECK_CONS (frompos, 0);
900 CHECK_NUMBER (XCONS (frompos)->car, 0);
901 CHECK_NUMBER (XCONS (frompos)->cdr, 0);
902 CHECK_NUMBER_COERCE_MARKER (to, 0);
903 CHECK_CONS (topos, 0);
904 CHECK_NUMBER (XCONS (topos)->car, 0);
905 CHECK_NUMBER (XCONS (topos)->cdr, 0);
906 CHECK_NUMBER (width, 0);
907 if (!NILP (offsets))
908 {
909 CHECK_CONS (offsets, 0);
910 CHECK_NUMBER (XCONS (offsets)->car, 0);
911 CHECK_NUMBER (XCONS (offsets)->cdr, 0);
912 hscroll = XINT (XCONS (offsets)->car);
913 tab_offset = XINT (XCONS (offsets)->cdr);
914 }
915 else
916 hscroll = tab_offset = 0;
917
918 if (NILP (window))
919 window = Fselected_window ();
920 else
921 CHECK_LIVE_WINDOW (window, 0);
922
923 pos = compute_motion (XINT (from), XINT (XCONS (frompos)->cdr),
924 XINT (XCONS (frompos)->car),
925 XINT (to), XINT (XCONS (topos)->cdr),
926 XINT (XCONS (topos)->car),
927 XINT (width), hscroll, tab_offset,
928 XWINDOW (window));
929
930 XSETFASTINT (bufpos, pos->bufpos);
931 XSETINT (hpos, pos->hpos);
932 XSETINT (vpos, pos->vpos);
933 XSETINT (prevhpos, pos->prevhpos);
934
935 return Fcons (bufpos,
936 Fcons (hpos,
937 Fcons (vpos,
938 Fcons (prevhpos,
939 Fcons (pos->contin ? Qt : Qnil, Qnil)))));
940
941 }
942 \f
943 /* Return the column of position POS in window W's buffer.
944 The result is rounded down to a multiple of the internal width of W.
945 This is the amount of indentation of position POS
946 that is not visible in its horizontal position in the window. */
947
948 int
949 pos_tab_offset (w, pos)
950 struct window *w;
951 register int pos;
952 {
953 int opoint = PT;
954 int col;
955 int width = window_internal_width (w) - 1;
956
957 if (pos == BEGV || FETCH_CHAR (pos - 1) == '\n')
958 return 0;
959 TEMP_SET_PT (pos);
960 col = current_column ();
961 TEMP_SET_PT (opoint);
962 return col - (col % width);
963 }
964
965 \f
966 /* Fvertical_motion and vmotion */
967 struct position val_vmotion;
968
969 struct position *
970 vmotion (from, vtarget, width, hscroll, window)
971 register int from, vtarget, width;
972 int hscroll;
973 Lisp_Object window;
974 {
975 struct position pos;
976 /* vpos is cumulative vertical position, changed as from is changed */
977 register int vpos = 0;
978 Lisp_Object prevline;
979 register int first;
980 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
981 int selective
982 = (INTEGERP (current_buffer->selective_display)
983 ? XINT (current_buffer->selective_display)
984 : !NILP (current_buffer->selective_display) ? -1 : 0);
985 /* The omission of the clause
986 && marker_position (XWINDOW (window)->start) == BEG
987 here is deliberate; I think we want to measure from the prompt
988 position even if the minibuffer window has scrolled. */
989 int start_hpos = (EQ (window, minibuf_window) ? minibuf_prompt_width : 0);
990
991 retry:
992 if (vtarget > vpos)
993 {
994 /* Moving downward is simple, but must calculate from beg of line
995 to determine hpos of starting point */
996 if (from > BEGV && FETCH_CHAR (from - 1) != '\n')
997 {
998 XSETFASTINT (prevline, find_next_newline_no_quit (from, -1));
999 while (XFASTINT (prevline) > BEGV
1000 && ((selective > 0
1001 && indented_beyond_p (XFASTINT (prevline), selective))
1002 #ifdef USE_TEXT_PROPERTIES
1003 /* watch out for newlines with `invisible' property */
1004 || ! NILP (Fget_char_property (prevline,
1005 Qinvisible,
1006 window))
1007 #endif
1008 ))
1009 XSETFASTINT (prevline,
1010 find_next_newline_no_quit (XFASTINT (prevline) - 1,
1011 -1));
1012 pos = *compute_motion (XFASTINT (prevline), 0,
1013 lmargin + (XFASTINT (prevline) == 1
1014 ? start_hpos : 0),
1015 from, 1 << (INTBITS - 2), 0,
1016 width, hscroll, 0, XWINDOW (window));
1017 }
1018 else
1019 {
1020 pos.hpos = lmargin + (from == 1 ? start_hpos : 0);
1021 pos.vpos = 0;
1022 }
1023 return compute_motion (from, vpos, pos.hpos,
1024 ZV, vtarget, - (1 << (INTBITS - 2)),
1025 width, hscroll, pos.vpos * width,
1026 XWINDOW (window));
1027 }
1028
1029 /* To move upward, go a line at a time until
1030 we have gone at least far enough */
1031
1032 first = 1;
1033
1034 while ((vpos > vtarget || first) && from > BEGV)
1035 {
1036 XSETFASTINT (prevline, from);
1037 while (1)
1038 {
1039 XSETFASTINT (prevline,
1040 find_next_newline_no_quit (XFASTINT (prevline) - 1,
1041 -1));
1042 if (XFASTINT (prevline) == BEGV
1043 || ((selective <= 0
1044 || ! indented_beyond_p (XFASTINT (prevline), selective))
1045 #ifdef USE_TEXT_PROPERTIES
1046 /* watch out for newlines with `invisible' property */
1047 && NILP (Fget_char_property (prevline, Qinvisible, window))
1048 #endif
1049 ))
1050 break;
1051 }
1052 pos = *compute_motion (XFASTINT (prevline), 0,
1053 lmargin + (XFASTINT (prevline) == 1
1054 ? start_hpos : 0),
1055 from, 1 << (INTBITS - 2), 0,
1056 width, hscroll, 0, XWINDOW (window));
1057 vpos -= pos.vpos;
1058 first = 0;
1059 from = XFASTINT (prevline);
1060 }
1061
1062 /* If we made exactly the desired vertical distance,
1063 or if we hit beginning of buffer,
1064 return point found */
1065 if (vpos >= vtarget)
1066 {
1067 val_vmotion.bufpos = from;
1068 val_vmotion.vpos = vpos;
1069 val_vmotion.hpos = lmargin;
1070 val_vmotion.contin = 0;
1071 val_vmotion.prevhpos = 0;
1072 return &val_vmotion;
1073 }
1074
1075 /* Otherwise find the correct spot by moving down */
1076 goto retry;
1077 }
1078
1079 DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 2, 0,
1080 "Move to start of screen line LINES lines down.\n\
1081 If LINES is negative, this is moving up.\n\
1082 \n\
1083 The optional second argument WINDOW specifies the window to use for\n\
1084 parameters such as width, horizontal scrolling, and so on.\n\
1085 the default is the selected window.\n\
1086 It does not matter what buffer is displayed in WINDOW.\n\
1087 `vertical-motion' always uses the current buffer.\n\
1088 \n\
1089 Sets point to position found; this may be start of line\n\
1090 or just the start of a continuation line.\n\
1091 Returns number of lines moved; may be closer to zero than LINES\n\
1092 if beginning or end of buffer was reached.")
1093 (lines, window)
1094 Lisp_Object lines, window;
1095 {
1096 struct position pos;
1097 register struct window *w;
1098
1099 CHECK_NUMBER (lines, 0);
1100 if (! NILP (window))
1101 CHECK_WINDOW (window, 0);
1102 else
1103 window = selected_window;
1104
1105 w = XWINDOW (window);
1106
1107 pos = *vmotion (point, XINT (lines), window_internal_width (w) - 1,
1108 /* Not XFASTINT since perhaps could be negative */
1109 XINT (w->hscroll), window);
1110
1111 SET_PT (pos.bufpos);
1112 return make_number (pos.vpos);
1113 }
1114 \f
1115 /* file's initialization. */
1116
1117 syms_of_indent ()
1118 {
1119 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
1120 "*Indentation can insert tabs if this is non-nil.\n\
1121 Setting this variable automatically makes it local to the current buffer.");
1122 indent_tabs_mode = 1;
1123
1124 defsubr (&Scurrent_indentation);
1125 defsubr (&Sindent_to);
1126 defsubr (&Scurrent_column);
1127 defsubr (&Smove_to_column);
1128 defsubr (&Svertical_motion);
1129 defsubr (&Scompute_motion);
1130 }