1 /* Indentation functions.
2 Copyright (C) 1985,86,87,88,93,94,95 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
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)
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.
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. */
30 #include "intervals.h"
31 #include "region-cache.h"
33 /* Indentation can insert tabs if this is non-zero;
34 otherwise always uses spaces */
37 #define min(a, b) ((a) < (b) ? (a) : (b))
38 #define max(a, b) ((a) > (b) ? (a) : (b))
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
;
52 /* Get the display table to use for the current buffer. */
55 buffer_display_table ()
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
);
68 /* Width run cache considerations. */
70 /* Return the width of character C under display table DP. */
73 character_width (c
, dp
)
75 struct Lisp_Vector
*dp
;
79 /* These width computations were determined by examining the cases
80 in display_text_line. */
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
;
87 /* Some characters are special. */
88 if (c
== '\n' || c
== '\t' || c
== '\015')
91 /* Printing characters have width 1. */
92 else if (c
>= 040 && c
< 0177)
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
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. */
108 disptab_matches_widthtab (disptab
, widthtab
)
109 struct Lisp_Vector
*disptab
;
110 struct Lisp_Vector
*widthtab
;
114 if (widthtab
->size
!= 256)
117 for (i
= 0; i
< 256; i
++)
118 if (character_width (i
, disptab
)
119 != XFASTINT (widthtab
->contents
[i
]))
125 /* Recompute BUF's width table, using the display table DISPTAB. */
127 recompute_width_table (buf
, disptab
)
129 struct Lisp_Vector
*disptab
;
132 struct Lisp_Vector
*widthtab
;
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)
140 for (i
= 0; i
< 256; i
++)
141 XSETFASTINT (widthtab
->contents
[i
], character_width (i
, disptab
));
144 /* Allocate or free the width run cache, as requested by the current
145 state of current_buffer's cache_long_line_scans variable. */
147 width_run_cache_on_off ()
149 if (NILP (current_buffer
->cache_long_line_scans
))
151 /* It should be off. */
152 if (current_buffer
->width_run_cache
)
154 free_region_cache (current_buffer
->width_run_cache
);
155 current_buffer
->width_run_cache
= 0;
156 current_buffer
->width_table
= Qnil
;
161 /* It should be on. */
162 if (current_buffer
->width_run_cache
== 0)
164 current_buffer
->width_run_cache
= new_region_cache ();
165 recompute_width_table (current_buffer
, buffer_display_table ());
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.")
184 XSETFASTINT (temp
, current_column ());
188 /* Cancel any recorded value of the horizontal position. */
190 invalidate_current_column ()
192 last_known_column_point
= 0;
199 register unsigned char *ptr
, *stop
;
200 register int tab_seen
;
203 register int tab_width
= XINT (current_buffer
->tab_width
);
204 int ctl_arrow
= !NILP (current_buffer
->ctl_arrow
);
205 register struct Lisp_Vector
*dp
= buffer_display_table ();
208 if (point
== last_known_column_point
209 && MODIFF
== last_known_column_modified
)
210 return last_known_column
;
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. */
218 else if (point
<= GPT
|| BEGV
> GPT
)
223 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
225 col
= 0, tab_seen
= 0, post_tab
= 0;
231 /* We stopped either for the beginning of the buffer
233 if (ptr
== BEGV_ADDR
)
235 /* It was the gap. Jump back over it. */
238 /* Check whether that brings us to beginning of buffer. */
239 if (BEGV
>= GPT
) break;
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)
249 else if (c
== '\r' && EQ (current_buffer
->selective_display
, Qt
))
254 col
= ((col
+ tab_width
) / tab_width
) * tab_width
;
261 col
+= (ctl_arrow
&& c
< 0200) ? 2 : 4;
266 col
= ((col
+ tab_width
) / tab_width
) * tab_width
;
270 last_known_column
= col
;
271 last_known_column_point
= point
;
272 last_known_column_modified
= MODIFF
;
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. */
282 string_width (string
, beg
, end
)
283 Lisp_Object string
, beg
, end
;
286 register unsigned char *ptr
, *stop
;
287 register int tab_seen
;
290 register int tab_width
= XINT (current_buffer
->tab_width
);
291 int ctl_arrow
= !NILP (current_buffer
->ctl_arrow
);
292 register struct Lisp_Vector
*dp
= buffer_display_table ();
296 e
= XSTRING (string
)->size
;
299 CHECK_NUMBER (end
, 0);
307 CHECK_NUMBER (beg
, 0);
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
;
317 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
319 col
= 0, tab_seen
= 0, post_tab
= 0;
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)
336 col
= ((col
+ tab_width
) / tab_width
) * tab_width
;
343 col
+= (ctl_arrow
&& c
< 0200) ? 2 : 4;
348 col
= ((col
+ tab_width
) / tab_width
) * tab_width
;
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 MIN says always do at least MIN spaces\n\
358 even if that goes past COLUMN; by default, MIN is zero.")
360 Lisp_Object col
, minimum
;
363 register int fromcol
;
364 register int tab_width
= XINT (current_buffer
->tab_width
);
366 CHECK_NUMBER (col
, 0);
368 XSETFASTINT (minimum
, 0);
369 CHECK_NUMBER (minimum
, 1);
371 fromcol
= current_column ();
372 mincol
= fromcol
+ XINT (minimum
);
373 if (mincol
< XINT (col
)) mincol
= XINT (col
);
375 if (fromcol
== mincol
)
376 return make_number (mincol
);
378 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
380 if (indent_tabs_mode
)
383 XSETFASTINT (n
, mincol
/ tab_width
- fromcol
/ tab_width
);
384 if (XFASTINT (n
) != 0)
386 Finsert_char (make_number ('\t'), n
, Qt
);
388 fromcol
= (mincol
/ tab_width
) * tab_width
;
392 XSETFASTINT (col
, mincol
- fromcol
);
393 Finsert_char (make_number (' '), col
, Qt
);
395 last_known_column
= mincol
;
396 last_known_column_point
= point
;
397 last_known_column_modified
= MODIFF
;
399 XSETINT (col
, mincol
);
404 DEFUN ("current-indentation", Fcurrent_indentation
, Scurrent_indentation
,
406 "Return the indentation of the current line.\n\
407 This is the horizontal position of the character\n\
408 following any initial whitespace.")
413 XSETFASTINT (val
, position_indentation (find_next_newline (point
, -1)));
417 position_indentation (pos
)
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
;
425 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
427 stop
= &FETCH_CHAR (BUFFER_CEILING_OF (pos
)) + 1;
428 p
= &FETCH_CHAR (pos
);
435 pos
+= p
- &FETCH_CHAR (pos
);
436 p
= &FETCH_CHAR (pos
);
437 stop
= &FETCH_CHAR (BUFFER_CEILING_OF (pos
)) + 1;
445 column
+= tab_width
- column
% tab_width
;
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
457 indented_beyond_p (pos
, column
)
460 while (pos
> BEGV
&& FETCH_CHAR (pos
) == '\n')
461 pos
= find_next_newline_no_quit (pos
- 1, -1);
462 return (position_indentation (pos
) >= column
);
466 DEFUN ("move-to-column", Fmove_to_column
, Smove_to_column
, 1, 2, 0,
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\
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.")
480 Lisp_Object column
, force
;
483 register int col
= current_column ();
486 register int tab_width
= XINT (current_buffer
->tab_width
);
487 register int ctl_arrow
= !NILP (current_buffer
->ctl_arrow
);
488 register struct Lisp_Vector
*dp
= buffer_display_table ();
494 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
495 CHECK_NATNUM (column
, 0);
496 goal
= XINT (column
);
502 /* If we're starting past the desired column,
503 back up to beginning of line and scan from there. */
506 pos
= find_next_newline (pos
, -1);
510 while (col
< goal
&& pos
< end
)
512 c
= FETCH_CHAR (pos
);
513 if (dp
!= 0 && VECTORP (DISP_CHAR_VECTOR (dp
, c
)))
515 col
+= XVECTOR (DISP_CHAR_VECTOR (dp
, c
))->size
;
521 if (c
== '\r' && EQ (current_buffer
->selective_display
, Qt
))
528 col
= col
/ tab_width
* tab_width
;
530 else if (ctl_arrow
&& (c
< 040 || c
== 0177))
532 else if (c
< 040 || c
>= 0177)
540 /* If a tab char made us overshoot, change it to spaces
541 and scan through it again. */
542 if (!NILP (force
) && col
> goal
&& c
== '\t' && prev_col
< goal
)
546 del_range (point
- 1, point
);
547 Findent_to (make_number (goal
), Qnil
);
549 Findent_to (make_number (col
), Qnil
);
551 /* Set the last_known... vars consistently. */
555 /* If line ends prematurely, add space to the end. */
556 if (col
< goal
&& !NILP (force
))
557 Findent_to (make_number (col
= goal
), Qnil
);
559 last_known_column
= col
;
560 last_known_column_point
= point
;
561 last_known_column_modified
= MODIFF
;
563 XSETFASTINT (val
, col
);
568 /* compute_motion: compute buffer posn given screen posn and vice versa */
570 struct position val_compute_motion
;
572 /* Scan the current buffer forward from offset FROM, pretending that
573 this is at line FROMVPOS, column FROMHPOS, until reaching buffer
574 offset TO or line TOVPOS, column TOHPOS (whichever comes first),
575 and return the ending buffer position and screen location. If we
576 can't hit the requested column exactly (because of a tab or other
577 multi-column character), overshoot.
579 WIDTH is the number of columns available to display text;
580 compute_motion uses this to handle continuation lines and such.
581 HSCROLL is the number of columns not being displayed at the left
582 margin; this is usually taken from a window's hscroll member.
583 TAB_OFFSET is the number of columns of the first tab that aren't
584 being displayed, perhaps because of a continuation line or
587 compute_motion returns a pointer to a struct position. The bufpos
588 member gives the buffer position at the end of the scan, and hpos
589 and vpos give its cartesian location. prevhpos is the column at
590 which the character before bufpos started, and contin is non-zero
591 if we reached the current line by continuing the previous.
593 Note that FROMHPOS and TOHPOS should be expressed in real screen
594 columns, taking HSCROLL and the truncation glyph at the left margin
595 into account. That is, beginning-of-line moves you to the hpos
596 -HSCROLL + (HSCROLL > 0).
598 Note that FROMHPOS and TOHPOS should be expressed in real screen
599 columns, taking HSCROLL and the truncation glyph at the left margin
600 into account. That is, beginning-of-line moves you to the hpos
601 -HSCROLL + (HSCROLL > 0).
603 For example, to find the buffer position of column COL of line LINE
604 of a certain window, pass the window's starting location as FROM
605 and the window's upper-left coordinates as FROMVPOS and FROMHPOS.
606 Pass the buffer's ZV as TO, to limit the scan to the end of the
607 visible section of the buffer, and pass LINE and COL as TOVPOS and
610 When displaying in window w, a typical formula for WIDTH is:
613 - (has_vertical_scroll_bars
614 ? FRAME_SCROLL_BAR_COLS (XFRAME (window->frame))
615 : (window_width + window_left != frame_width))
618 window_width is XFASTINT (w->width),
619 window_left is XFASTINT (w->left),
620 has_vertical_scroll_bars is
621 FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (WINDOW_FRAME (window)))
622 and frame_width = FRAME_WIDTH (XFRAME (window->frame))
624 Or you can let window_internal_width do this all for you, and write:
625 window_internal_width (w) - 1
627 The `-1' accounts for the continuation-line backslashes; the rest
628 accounts for window borders if the window is split horizontally, and
629 the scroll bars if they are turned on. */
632 compute_motion (from
, fromvpos
, fromhpos
, to
, tovpos
, tohpos
, width
, hscroll
, tab_offset
, win
)
633 int from
, fromvpos
, fromhpos
, to
, tovpos
, tohpos
;
635 int hscroll
, tab_offset
;
638 register int hpos
= fromhpos
;
639 register int vpos
= fromvpos
;
643 register int tab_width
= XFASTINT (current_buffer
->tab_width
);
644 register int ctl_arrow
= !NILP (current_buffer
->ctl_arrow
);
645 register struct Lisp_Vector
*dp
= window_display_table (win
);
647 = (INTEGERP (current_buffer
->selective_display
)
648 ? XINT (current_buffer
->selective_display
)
649 : !NILP (current_buffer
->selective_display
) ? -1 : 0);
650 int prev_vpos
= vpos
, prev_hpos
= 0;
652 = (selective
&& dp
&& VECTORP (DISP_INVIS_VECTOR (dp
))
653 ? XVECTOR (DISP_INVIS_VECTOR (dp
))->size
: 0);
654 #ifdef USE_TEXT_PROPERTIES
655 /* The next location where the `invisible' property changes */
656 int next_invisible
= from
;
657 Lisp_Object prop
, position
;
660 /* For computing runs of characters with similar widths.
661 Invariant: width_run_width is zero, or all the characters
662 from width_run_start to width_run_end have a fixed width of
664 int width_run_start
= from
;
665 int width_run_end
= from
;
666 int width_run_width
= 0;
667 Lisp_Object
*width_table
;
670 /* The next buffer pos where we should consult the width run cache. */
671 int next_width_run
= from
;
673 XSETBUFFER (buffer
, current_buffer
);
675 width_run_cache_on_off ();
676 if (dp
== buffer_display_table ())
677 width_table
= (VECTORP (current_buffer
->width_table
)
678 ? XVECTOR (current_buffer
->width_table
)->contents
681 /* If the window has its own display table, we can't use the width
682 run cache, because that's based on the buffer's display table. */
685 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
686 for (pos
= from
; pos
< to
; )
688 /* Stop if past the target screen position. */
690 || (vpos
== tovpos
&& hpos
>= tohpos
))
696 #ifdef USE_TEXT_PROPERTIES
697 /* if the `invisible' property is set, we can skip to
698 the next property change */
699 while (pos
== next_invisible
&& pos
< to
)
701 XSETFASTINT (position
, pos
);
703 /* Give faster response for overlay lookup near POS. */
704 recenter_overlay_lists (current_buffer
, pos
);
706 prop
= Fget_char_property (position
,
710 Lisp_Object end
, limit
, proplimit
;
712 /* We must not advance farther than the next overlay change.
713 The overlay change might change the invisible property;
714 we have no way of telling. */
715 limit
= Fnext_overlay_change (position
);
716 /* As for text properties, this gives a lower bound
717 for where the invisible text property could change. */
718 proplimit
= Fnext_property_change (position
, buffer
, Qt
);
719 if (XFASTINT (limit
) < XFASTINT (proplimit
))
721 /* PROPLIMIT is now a lower bound for the next change
722 in invisible status. If that is plenty far away,
723 use that lower bound. */
724 if (XFASTINT (proplimit
) > pos
+ 100 || XFASTINT (proplimit
) >= to
)
725 next_invisible
= XINT (proplimit
);
726 /* Otherwise, scan for the next `invisible' property change. */
729 /* Don't scan terribly far. */
730 XSETFASTINT (proplimit
, min (pos
+ 100, to
));
731 /* No matter what. don't go past next overlay change. */
732 if (XFASTINT (limit
) < XFASTINT (proplimit
))
734 end
= Fnext_single_property_change (position
, Qinvisible
,
736 if (INTEGERP (end
) && XINT (end
) < to
)
737 next_invisible
= XINT (end
);
741 if (TEXT_PROP_MEANS_INVISIBLE (prop
))
742 pos
= next_invisible
;
749 /* Consult the width run cache to see if we can avoid inspecting
750 the text character-by-character. */
751 if (current_buffer
->width_run_cache
&& pos
>= next_width_run
)
755 = region_cache_forward (current_buffer
,
756 current_buffer
->width_run_cache
,
759 /* A width of zero means the character's width varies (like
760 a tab), is meaningless (like a newline), or we just don't
761 want to skip over it for some other reason. */
762 if (common_width
!= 0)
766 /* Don't go past the final buffer posn the user
771 run_end_hpos
= hpos
+ (run_end
- pos
) * common_width
;
773 /* Don't go past the final horizontal position the user
775 if (vpos
== tovpos
&& run_end_hpos
> tohpos
)
777 run_end
= pos
+ (tohpos
- hpos
) / common_width
;
778 run_end_hpos
= hpos
+ (run_end
- pos
) * common_width
;
781 /* Don't go past the margin. */
782 if (run_end_hpos
>= width
)
784 run_end
= pos
+ (width
- hpos
) / common_width
;
785 run_end_hpos
= hpos
+ (run_end
- pos
) * common_width
;
790 prev_hpos
= hpos
- common_width
;
794 next_width_run
= run_end
+ 1;
797 /* We have to scan the text character-by-character. */
800 c
= FETCH_CHAR (pos
);
803 /* Perhaps add some info to the width_run_cache. */
804 if (current_buffer
->width_run_cache
)
806 /* Is this character part of the current run? If so, extend
808 if (pos
- 1 == width_run_end
809 && width_table
[c
] == width_run_width
)
812 /* The previous run is over, since this is a character at a
813 different position, or a different width. */
816 /* Have we accumulated a run to put in the cache?
817 (Currently, we only cache runs of width == 1). */
818 if (width_run_start
< width_run_end
819 && width_run_width
== 1)
820 know_region_cache (current_buffer
,
821 current_buffer
->width_run_cache
,
822 width_run_start
, width_run_end
);
824 /* Start recording a new width run. */
825 width_run_width
= width_table
[c
];
826 width_run_start
= pos
- 1;
831 if (dp
!= 0 && VECTORP (DISP_CHAR_VECTOR (dp
, c
)))
832 hpos
+= XVECTOR (DISP_CHAR_VECTOR (dp
, c
))->size
;
833 else if (c
>= 040 && c
< 0177)
837 hpos
+= tab_width
- ((hpos
+ tab_offset
+ hscroll
- (hscroll
> 0)
838 /* Add tab_width here to make sure
839 positive. hpos can be negative
840 after continuation but can't be
841 less than -tab_width. */
847 if (selective
> 0 && indented_beyond_p (pos
, selective
))
849 /* Skip any number of invisible lines all at once */
851 pos
= find_before_next_newline (pos
, to
, 1) + 1;
853 && indented_beyond_p (pos
, selective
));
854 /* Allow for the " ..." that is displayed for them. */
857 hpos
+= selective_rlen
;
862 /* We have skipped the invis text, but not the
867 /* A visible line. */
871 /* Count the truncation glyph on column 0 */
877 else if (c
== CR
&& selective
< 0)
879 /* In selective display mode,
880 everything from a ^M to the end of the line is invisible.
881 Stop *before* the real newline. */
882 pos
= find_before_next_newline (pos
, to
, 1);
883 /* Allow for the " ..." that is displayed for them. */
886 hpos
+= selective_rlen
;
892 hpos
+= (ctl_arrow
&& c
< 0200) ? 2 : 4;
895 /* Handle right margin. */
899 && FETCH_CHAR (pos
) != '\n')))
902 || (vpos
== tovpos
&& hpos
>= tohpos
))
905 || (truncate_partial_width_windows
906 && width
+ 1 < FRAME_WIDTH (XFRAME (WINDOW_FRAME (win
))))
907 || !NILP (current_buffer
->truncate_lines
))
909 /* Truncating: skip to newline. */
910 pos
= find_before_next_newline (pos
, to
, 1);
924 /* Remember any final width run in the cache. */
925 if (current_buffer
->width_run_cache
926 && width_run_width
== 1
927 && width_run_start
< width_run_end
)
928 know_region_cache (current_buffer
, current_buffer
->width_run_cache
,
929 width_run_start
, width_run_end
);
931 val_compute_motion
.bufpos
= pos
;
932 val_compute_motion
.hpos
= hpos
;
933 val_compute_motion
.vpos
= vpos
;
934 val_compute_motion
.prevhpos
= prev_hpos
;
936 /* Nonzero if have just continued a line */
937 val_compute_motion
.contin
939 && (val_compute_motion
.vpos
!= prev_vpos
)
942 return &val_compute_motion
;
945 #if 0 /* The doc string is too long for some compilers,
946 but make-docfile can find it in this comment. */
947 DEFUN ("compute-motion", Ffoo
, Sfoo
, 7, 7, 0,
948 "Scan through the current buffer, calculating screen position.\n\
949 Scan the current buffer forward from offset FROM,\n\
950 assuming it is at position FROMPOS--a cons of the form (HPOS . VPOS)--\n\
951 to position TO or position TOPOS--another cons of the form (HPOS . VPOS)--\n\
952 and return the ending buffer position and screen location.\n\
954 There are three additional arguments:\n\
956 WIDTH is the number of columns available to display text;\n\
957 this affects handling of continuation lines.\n\
958 This is usually the value returned by `window-width', less one (to allow\n\
959 for the continuation glyph).\n\
961 OFFSETS is either nil or a cons cell (HSCROLL . TAB-OFFSET).\n\
962 HSCROLL is the number of columns not being displayed at the left\n\
963 margin; this is usually taken from a window's hscroll member.\n\
964 TAB-OFFSET is the number of columns of the first tab that aren't\n\
965 being displayed, perhaps because the line was continued within it.\n\
966 If OFFSETS is nil, HSCROLL and TAB-OFFSET are assumed to be zero.\n\
968 WINDOW is the window to operate on. Currently this is used only to\n\
969 find the display table. It does not matter what buffer WINDOW displays;\n\
970 `compute-motion' always operates on the current buffer.\n\
972 The value is a list of five elements:\n\
973 (POS HPOS VPOS PREVHPOS CONTIN)\n\
974 POS is the buffer position where the scan stopped.\n\
975 VPOS is the vertical position where the scan stopped.\n\
976 HPOS is the horizontal position where the scan stopped.\n\
978 PREVHPOS is the horizontal position one character back from POS.\n\
979 CONTIN is t if a line was continued after (or within) the previous character.\n\
981 For example, to find the buffer position of column COL of line LINE\n\
982 of a certain window, pass the window's starting location as FROM\n\
983 and the window's upper-left coordinates as FROMPOS.\n\
984 Pass the buffer's (point-max) as TO, to limit the scan to the end of the\n\
985 visible section of the buffer, and pass LINE and COL as TOPOS.")
986 (from
, frompos
, to
, topos
, width
, offsets
, window
)
989 DEFUN ("compute-motion", Fcompute_motion
, Scompute_motion
, 7, 7, 0,
991 (from
, frompos
, to
, topos
, width
, offsets
, window
)
992 Lisp_Object from
, frompos
, to
, topos
;
993 Lisp_Object width
, offsets
, window
;
995 Lisp_Object bufpos
, hpos
, vpos
, prevhpos
, contin
;
996 struct position
*pos
;
997 int hscroll
, tab_offset
;
999 CHECK_NUMBER_COERCE_MARKER (from
, 0);
1000 CHECK_CONS (frompos
, 0);
1001 CHECK_NUMBER (XCONS (frompos
)->car
, 0);
1002 CHECK_NUMBER (XCONS (frompos
)->cdr
, 0);
1003 CHECK_NUMBER_COERCE_MARKER (to
, 0);
1004 CHECK_CONS (topos
, 0);
1005 CHECK_NUMBER (XCONS (topos
)->car
, 0);
1006 CHECK_NUMBER (XCONS (topos
)->cdr
, 0);
1007 CHECK_NUMBER (width
, 0);
1008 if (!NILP (offsets
))
1010 CHECK_CONS (offsets
, 0);
1011 CHECK_NUMBER (XCONS (offsets
)->car
, 0);
1012 CHECK_NUMBER (XCONS (offsets
)->cdr
, 0);
1013 hscroll
= XINT (XCONS (offsets
)->car
);
1014 tab_offset
= XINT (XCONS (offsets
)->cdr
);
1017 hscroll
= tab_offset
= 0;
1020 window
= Fselected_window ();
1022 CHECK_LIVE_WINDOW (window
, 0);
1024 pos
= compute_motion (XINT (from
), XINT (XCONS (frompos
)->cdr
),
1025 XINT (XCONS (frompos
)->car
),
1026 XINT (to
), XINT (XCONS (topos
)->cdr
),
1027 XINT (XCONS (topos
)->car
),
1028 XINT (width
), hscroll
, tab_offset
,
1031 XSETFASTINT (bufpos
, pos
->bufpos
);
1032 XSETINT (hpos
, pos
->hpos
);
1033 XSETINT (vpos
, pos
->vpos
);
1034 XSETINT (prevhpos
, pos
->prevhpos
);
1036 return Fcons (bufpos
,
1040 Fcons (pos
->contin
? Qt
: Qnil
, Qnil
)))));
1044 /* Return the column of position POS in window W's buffer.
1045 The result is rounded down to a multiple of the internal width of W.
1046 This is the amount of indentation of position POS
1047 that is not visible in its horizontal position in the window. */
1050 pos_tab_offset (w
, pos
)
1056 int width
= window_internal_width (w
) - 1;
1058 if (pos
== BEGV
|| FETCH_CHAR (pos
- 1) == '\n')
1061 col
= current_column ();
1062 TEMP_SET_PT (opoint
);
1063 return col
- (col
% width
);
1067 /* Fvertical_motion and vmotion */
1068 struct position val_vmotion
;
1071 vmotion (from
, vtarget
, width
, hscroll
, window
)
1072 register int from
, vtarget
, width
;
1076 struct position pos
;
1077 /* vpos is cumulative vertical position, changed as from is changed */
1078 register int vpos
= 0;
1079 Lisp_Object prevline
;
1081 int lmargin
= hscroll
> 0 ? 1 - hscroll
: 0;
1083 = (INTEGERP (current_buffer
->selective_display
)
1084 ? XINT (current_buffer
->selective_display
)
1085 : !NILP (current_buffer
->selective_display
) ? -1 : 0);
1086 /* The omission of the clause
1087 && marker_position (XWINDOW (window)->start) == BEG
1088 here is deliberate; I think we want to measure from the prompt
1089 position even if the minibuffer window has scrolled. */
1092 if (EQ (window
, minibuf_window
))
1094 if (minibuf_prompt_width
== 0)
1095 minibuf_prompt_width
= string_width (minibuf_prompt
, Qnil
, Qnil
);
1097 start_hpos
= minibuf_prompt_width
;
1103 /* Moving downward is simple, but must calculate from beg of line
1104 to determine hpos of starting point */
1105 if (from
> BEGV
&& FETCH_CHAR (from
- 1) != '\n')
1107 Lisp_Object propval
;
1109 XSETFASTINT (prevline
, find_next_newline_no_quit (from
, -1));
1110 while (XFASTINT (prevline
) > BEGV
1112 && indented_beyond_p (XFASTINT (prevline
), selective
))
1113 #ifdef USE_TEXT_PROPERTIES
1114 /* watch out for newlines with `invisible' property */
1115 || (propval
= Fget_char_property (prevline
,
1118 TEXT_PROP_MEANS_INVISIBLE (propval
))
1121 XSETFASTINT (prevline
,
1122 find_next_newline_no_quit (XFASTINT (prevline
) - 1,
1124 pos
= *compute_motion (XFASTINT (prevline
), 0,
1125 lmargin
+ (XFASTINT (prevline
) == 1
1127 from
, 1 << (INTBITS
- 2), 0,
1128 width
, hscroll
, 0, XWINDOW (window
));
1132 pos
.hpos
= lmargin
+ (from
== 1 ? start_hpos
: 0);
1135 return compute_motion (from
, vpos
, pos
.hpos
,
1136 ZV
, vtarget
, - (1 << (INTBITS
- 2)),
1137 width
, hscroll
, pos
.vpos
* width
,
1141 /* To move upward, go a line at a time until
1142 we have gone at least far enough */
1146 while ((vpos
> vtarget
|| first
) && from
> BEGV
)
1148 XSETFASTINT (prevline
, from
);
1151 Lisp_Object propval
;
1153 XSETFASTINT (prevline
,
1154 find_next_newline_no_quit (XFASTINT (prevline
) - 1,
1156 if (XFASTINT (prevline
) == BEGV
1158 || ! indented_beyond_p (XFASTINT (prevline
), selective
))
1159 #ifdef USE_TEXT_PROPERTIES
1160 /* watch out for newlines with `invisible' property */
1161 && (propval
= Fget_char_property (prevline
, Qinvisible
,
1163 ! TEXT_PROP_MEANS_INVISIBLE (propval
))
1168 pos
= *compute_motion (XFASTINT (prevline
), 0,
1169 lmargin
+ (XFASTINT (prevline
) == 1
1171 from
, 1 << (INTBITS
- 2), 0,
1172 width
, hscroll
, 0, XWINDOW (window
));
1175 from
= XFASTINT (prevline
);
1178 /* If we made exactly the desired vertical distance,
1179 or if we hit beginning of buffer,
1180 return point found */
1181 if (vpos
>= vtarget
)
1183 val_vmotion
.bufpos
= from
;
1184 val_vmotion
.vpos
= vpos
;
1185 val_vmotion
.hpos
= lmargin
;
1186 val_vmotion
.contin
= 0;
1187 val_vmotion
.prevhpos
= 0;
1188 return &val_vmotion
;
1191 /* Otherwise find the correct spot by moving down */
1195 DEFUN ("vertical-motion", Fvertical_motion
, Svertical_motion
, 1, 2, 0,
1196 "Move to start of screen line LINES lines down.\n\
1197 If LINES is negative, this is moving up.\n\
1199 The optional second argument WINDOW specifies the window to use for\n\
1200 parameters such as width, horizontal scrolling, and so on.\n\
1201 the default is the selected window.\n\
1202 It does not matter what buffer is displayed in WINDOW.\n\
1203 `vertical-motion' always uses the current buffer.\n\
1205 Sets point to position found; this may be start of line\n\
1206 or just the start of a continuation line.\n\
1207 Returns number of lines moved; may be closer to zero than LINES\n\
1208 if beginning or end of buffer was reached.")
1210 Lisp_Object lines
, window
;
1212 struct position pos
;
1213 register struct window
*w
;
1215 CHECK_NUMBER (lines
, 0);
1216 if (! NILP (window
))
1217 CHECK_WINDOW (window
, 0);
1219 window
= selected_window
;
1221 w
= XWINDOW (window
);
1223 pos
= *vmotion (point
, XINT (lines
), window_internal_width (w
) - 1,
1224 /* Not XFASTINT since perhaps could be negative */
1225 XINT (w
->hscroll
), window
);
1227 SET_PT (pos
.bufpos
);
1228 return make_number (pos
.vpos
);
1231 /* file's initialization. */
1235 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode
,
1236 "*Indentation can insert tabs if this is non-nil.\n\
1237 Setting this variable automatically makes it local to the current buffer.");
1238 indent_tabs_mode
= 1;
1240 defsubr (&Scurrent_indentation
);
1241 defsubr (&Sindent_to
);
1242 defsubr (&Scurrent_column
);
1243 defsubr (&Smove_to_column
);
1244 defsubr (&Svertical_motion
);
1245 defsubr (&Scompute_motion
);