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