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