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 2, 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, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
31 #include "intervals.h"
32 #include "region-cache.h"
34 /* Indentation can insert tabs if this is non-zero;
35 otherwise always uses spaces */
38 #define min(a, b) ((a) < (b) ? (a) : (b))
39 #define max(a, b) ((a) > (b) ? (a) : (b))
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
;
53 /* Get the display table to use for the current buffer. */
55 struct Lisp_Char_Table
*
56 buffer_display_table ()
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
);
68 /* Width run cache considerations. */
70 /* Return the width of character C under display table DP. */
73 character_width (c
, dp
)
75 struct Lisp_Char_Table
*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_Char_Table
*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_Char_Table
*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_Char_Table
*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_display_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_Char_Table
*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 MININUM says always do at least MININUM spaces\n\
358 even if that goes past COLUMN; by default, MININUM is zero.")
360 Lisp_Object column
, minimum
;
363 register int fromcol
;
364 register int tab_width
= XINT (current_buffer
->tab_width
);
366 CHECK_NUMBER (column
, 0);
368 XSETFASTINT (minimum
, 0);
369 CHECK_NUMBER (minimum
, 1);
371 fromcol
= current_column ();
372 mincol
= fromcol
+ XINT (minimum
);
373 if (mincol
< XINT (column
)) mincol
= XINT (column
);
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 (column
, mincol
- fromcol
);
393 Finsert_char (make_number (' '), column
, Qt
);
395 last_known_column
= mincol
;
396 last_known_column_point
= point
;
397 last_known_column_modified
= MODIFF
;
399 XSETINT (column
, 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, "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\
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\
480 The return value is the current column.")
482 Lisp_Object column
, force
;
485 register int col
= current_column ();
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 ();
496 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
497 CHECK_NATNUM (column
, 0);
498 goal
= XINT (column
);
504 /* If we're starting past the desired column,
505 back up to beginning of line and scan from there. */
508 pos
= find_next_newline (pos
, -1);
512 while (col
< goal
&& pos
< end
)
514 c
= FETCH_CHAR (pos
);
515 if (dp
!= 0 && VECTORP (DISP_CHAR_VECTOR (dp
, c
)))
517 col
+= XVECTOR (DISP_CHAR_VECTOR (dp
, c
))->size
;
523 if (c
== '\r' && EQ (current_buffer
->selective_display
, Qt
))
530 col
= col
/ tab_width
* tab_width
;
532 else if (ctl_arrow
&& (c
< 040 || c
== 0177))
534 else if (c
< 040 || c
>= 0177)
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
)
548 del_range (point
- 1, point
);
549 Findent_to (make_number (goal
), Qnil
);
551 Findent_to (make_number (col
), Qnil
);
553 /* Set the last_known... vars consistently. */
557 /* If line ends prematurely, add space to the end. */
558 if (col
< goal
&& !NILP (force
))
559 Findent_to (make_number (col
= goal
), Qnil
);
561 last_known_column
= col
;
562 last_known_column_point
= point
;
563 last_known_column_modified
= MODIFF
;
565 XSETFASTINT (val
, col
);
570 /* compute_motion: compute buffer posn given screen posn and vice versa */
572 struct position val_compute_motion
;
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.
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.
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
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.
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).
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).
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
618 When displaying in window w, a typical formula for WIDTH is:
621 - (has_vertical_scroll_bars
622 ? FRAME_SCROLL_BAR_COLS (XFRAME (window->frame))
623 : (window_width + window_left != frame_width))
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))
632 Or you can let window_internal_width do this all for you, and write:
633 window_internal_width (w) - 1
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. */
640 compute_motion (from
, fromvpos
, fromhpos
, did_motion
, to
, tovpos
, tohpos
, width
, hscroll
, tab_offset
, win
)
641 int from
, fromvpos
, fromhpos
, to
, tovpos
, tohpos
;
644 int hscroll
, tab_offset
;
647 register int hpos
= fromhpos
;
648 register int vpos
= fromvpos
;
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
);
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;
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
;
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
671 int width_run_start
= from
;
672 int width_run_end
= from
;
673 int width_run_width
= 0;
674 Lisp_Object
*width_table
;
677 /* The next buffer pos where we should consult the width run cache. */
678 int next_width_run
= from
;
680 XSETBUFFER (buffer
, current_buffer
);
682 width_run_cache_on_off ();
683 if (dp
== buffer_display_table ())
684 width_table
= (VECTORP (current_buffer
->width_table
)
685 ? XVECTOR (current_buffer
->width_table
)->contents
688 /* If the window has its own display table, we can't use the width
689 run cache, because that's based on the buffer's display table. */
692 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
697 while (pos
== next_boundary
)
699 /* If the caller says that the screen position came from an earlier
700 call to compute_motion, then we've already accounted for the
701 overlay strings at point. This is only true the first time
702 through, so clear the flag after testing it. */
704 /* We need to skip past the overlay strings. Currently those
705 strings must contain single-column printing characters;
706 if we want to relax that restriction, something will have
707 to be changed here. */
708 hpos
+= overlay_strings (pos
, win
, (char **)0);
715 Lisp_Object prop
, position
, end
, limit
, proplimit
;
717 XSETFASTINT (position
, pos
);
719 /* Give faster response for overlay lookup near POS. */
720 recenter_overlay_lists (current_buffer
, pos
);
722 /* We must not advance farther than the next overlay change.
723 The overlay change might change the invisible property;
724 or there might be overlay strings to be displayed there. */
725 limit
= Fnext_overlay_change (position
);
726 /* As for text properties, this gives a lower bound
727 for where the invisible text property could change. */
728 proplimit
= Fnext_property_change (position
, buffer
, Qt
);
729 if (XFASTINT (limit
) < XFASTINT (proplimit
))
731 /* PROPLIMIT is now a lower bound for the next change
732 in invisible status. If that is plenty far away,
733 use that lower bound. */
734 if (XFASTINT (proplimit
) > pos
+ 100 || XFASTINT (proplimit
) >= to
)
735 next_boundary
= XFASTINT (proplimit
);
736 /* Otherwise, scan for the next `invisible' property change. */
739 /* Don't scan terribly far. */
740 XSETFASTINT (proplimit
, min (pos
+ 100, to
));
741 /* No matter what. don't go past next overlay change. */
742 if (XFASTINT (limit
) < XFASTINT (proplimit
))
744 end
= Fnext_single_property_change (position
, Qinvisible
,
746 next_boundary
= XFASTINT (end
);
748 /* if the `invisible' property is set, we can skip to
749 the next property change */
750 prop
= Fget_char_property (position
, Qinvisible
,
752 if (TEXT_PROP_MEANS_INVISIBLE (prop
))
757 /* Handle right margin. */
760 || (pos
< ZV
&& FETCH_CHAR (pos
) != '\n')))
763 || (truncate_partial_width_windows
764 && width
+ 1 < FRAME_WIDTH (XFRAME (WINDOW_FRAME (win
))))
765 || !NILP (current_buffer
->truncate_lines
))
767 /* Truncating: skip to newline. */
768 pos
= find_before_next_newline (pos
, to
, 1);
770 /* If we just skipped next_boundary,
771 loop around in the main while
773 if (pos
>= next_boundary
)
774 next_boundary
= pos
+ 1;
779 vpos
+= hpos
/ width
;
780 tab_offset
+= hpos
- hpos
% width
;
785 /* Stop if past the target buffer position or screen position. */
788 if (vpos
> tovpos
|| (vpos
== tovpos
&& hpos
>= tohpos
))
794 /* Consult the width run cache to see if we can avoid inspecting
795 the text character-by-character. */
796 if (current_buffer
->width_run_cache
&& pos
>= next_width_run
)
800 = region_cache_forward (current_buffer
,
801 current_buffer
->width_run_cache
,
804 /* A width of zero means the character's width varies (like
805 a tab), is meaningless (like a newline), or we just don't
806 want to skip over it for some other reason. */
807 if (common_width
!= 0)
811 /* Don't go past the final buffer posn the user
816 run_end_hpos
= hpos
+ (run_end
- pos
) * common_width
;
818 /* Don't go past the final horizontal position the user
820 if (vpos
== tovpos
&& run_end_hpos
> tohpos
)
822 run_end
= pos
+ (tohpos
- hpos
) / common_width
;
823 run_end_hpos
= hpos
+ (run_end
- pos
) * common_width
;
826 /* Don't go past the margin. */
827 if (run_end_hpos
>= width
)
829 run_end
= pos
+ (width
- hpos
) / common_width
;
830 run_end_hpos
= hpos
+ (run_end
- pos
) * common_width
;
835 prev_hpos
= hpos
- common_width
;
839 next_width_run
= run_end
+ 1;
842 /* We have to scan the text character-by-character. */
845 c
= FETCH_CHAR (pos
);
848 /* Perhaps add some info to the width_run_cache. */
849 if (current_buffer
->width_run_cache
)
851 /* Is this character part of the current run? If so, extend
853 if (pos
- 1 == width_run_end
854 && width_table
[c
] == width_run_width
)
857 /* The previous run is over, since this is a character at a
858 different position, or a different width. */
861 /* Have we accumulated a run to put in the cache?
862 (Currently, we only cache runs of width == 1). */
863 if (width_run_start
< width_run_end
864 && width_run_width
== 1)
865 know_region_cache (current_buffer
,
866 current_buffer
->width_run_cache
,
867 width_run_start
, width_run_end
);
869 /* Start recording a new width run. */
870 width_run_width
= width_table
[c
];
871 width_run_start
= pos
- 1;
876 if (dp
!= 0 && VECTORP (DISP_CHAR_VECTOR (dp
, c
)))
877 hpos
+= XVECTOR (DISP_CHAR_VECTOR (dp
, c
))->size
;
878 else if (c
>= 040 && c
< 0177)
882 int tem
= (hpos
+ tab_offset
+ hscroll
- (hscroll
> 0)) % tab_width
;
885 hpos
+= tab_width
- tem
;
889 if (selective
> 0 && indented_beyond_p (pos
, selective
))
891 /* Skip any number of invisible lines all at once */
893 pos
= find_before_next_newline (pos
, to
, 1) + 1;
895 && indented_beyond_p (pos
, selective
));
896 /* Allow for the " ..." that is displayed for them. */
899 hpos
+= selective_rlen
;
904 /* We have skipped the invis text, but not the
909 /* A visible line. */
913 /* Count the truncation glyph on column 0 */
919 else if (c
== CR
&& selective
< 0)
921 /* In selective display mode,
922 everything from a ^M to the end of the line is invisible.
923 Stop *before* the real newline. */
924 pos
= find_before_next_newline (pos
, to
, 1);
925 /* If we just skipped next_boundary,
926 loop around in the main while
928 if (pos
> next_boundary
)
930 /* Allow for the " ..." that is displayed for them. */
933 hpos
+= selective_rlen
;
939 hpos
+= (ctl_arrow
&& c
< 0200) ? 2 : 4;
943 /* Remember any final width run in the cache. */
944 if (current_buffer
->width_run_cache
945 && width_run_width
== 1
946 && width_run_start
< width_run_end
)
947 know_region_cache (current_buffer
, current_buffer
->width_run_cache
,
948 width_run_start
, width_run_end
);
950 val_compute_motion
.bufpos
= pos
;
951 val_compute_motion
.hpos
= hpos
;
952 val_compute_motion
.vpos
= vpos
;
953 val_compute_motion
.prevhpos
= prev_hpos
;
955 /* Nonzero if have just continued a line */
956 val_compute_motion
.contin
958 && (val_compute_motion
.vpos
!= prev_vpos
)
961 return &val_compute_motion
;
964 #if 0 /* The doc string is too long for some compilers,
965 but make-docfile can find it in this comment. */
966 DEFUN ("compute-motion", Ffoo
, Sfoo
, 7, 7, 0,
967 "Scan through the current buffer, calculating screen position.\n\
968 Scan the current buffer forward from offset FROM,\n\
969 assuming it is at position FROMPOS--a cons of the form (HPOS . VPOS)--\n\
970 to position TO or position TOPOS--another cons of the form (HPOS . VPOS)--\n\
971 and return the ending buffer position and screen location.\n\
973 There are three additional arguments:\n\
975 WIDTH is the number of columns available to display text;\n\
976 this affects handling of continuation lines.\n\
977 This is usually the value returned by `window-width', less one (to allow\n\
978 for the continuation glyph).\n\
980 OFFSETS is either nil or a cons cell (HSCROLL . TAB-OFFSET).\n\
981 HSCROLL is the number of columns not being displayed at the left\n\
982 margin; this is usually taken from a window's hscroll member.\n\
983 TAB-OFFSET is the number of columns of the first tab that aren't\n\
984 being displayed, perhaps because the line was continued within it.\n\
985 If OFFSETS is nil, HSCROLL and TAB-OFFSET are assumed to be zero.\n\
987 WINDOW is the window to operate on. Currently this is used only to\n\
988 find the display table. It does not matter what buffer WINDOW displays;\n\
989 `compute-motion' always operates on the current buffer.\n\
991 The value is a list of five elements:\n\
992 (POS HPOS VPOS PREVHPOS CONTIN)\n\
993 POS is the buffer position where the scan stopped.\n\
994 VPOS is the vertical position where the scan stopped.\n\
995 HPOS is the horizontal position where the scan stopped.\n\
997 PREVHPOS is the horizontal position one character back from POS.\n\
998 CONTIN is t if a line was continued after (or within) the previous character.\n\
1000 For example, to find the buffer position of column COL of line LINE\n\
1001 of a certain window, pass the window's starting location as FROM\n\
1002 and the window's upper-left coordinates as FROMPOS.\n\
1003 Pass the buffer's (point-max) as TO, to limit the scan to the end of the\n\
1004 visible section of the buffer, and pass LINE and COL as TOPOS.")
1005 (from
, frompos
, to
, topos
, width
, offsets
, window
)
1008 DEFUN ("compute-motion", Fcompute_motion
, Scompute_motion
, 7, 7, 0,
1010 (from
, frompos
, to
, topos
, width
, offsets
, window
)
1011 Lisp_Object from
, frompos
, to
, topos
;
1012 Lisp_Object width
, offsets
, window
;
1014 Lisp_Object bufpos
, hpos
, vpos
, prevhpos
, contin
;
1015 struct position
*pos
;
1016 int hscroll
, tab_offset
;
1018 CHECK_NUMBER_COERCE_MARKER (from
, 0);
1019 CHECK_CONS (frompos
, 0);
1020 CHECK_NUMBER (XCONS (frompos
)->car
, 0);
1021 CHECK_NUMBER (XCONS (frompos
)->cdr
, 0);
1022 CHECK_NUMBER_COERCE_MARKER (to
, 0);
1023 CHECK_CONS (topos
, 0);
1024 CHECK_NUMBER (XCONS (topos
)->car
, 0);
1025 CHECK_NUMBER (XCONS (topos
)->cdr
, 0);
1026 CHECK_NUMBER (width
, 0);
1027 if (!NILP (offsets
))
1029 CHECK_CONS (offsets
, 0);
1030 CHECK_NUMBER (XCONS (offsets
)->car
, 0);
1031 CHECK_NUMBER (XCONS (offsets
)->cdr
, 0);
1032 hscroll
= XINT (XCONS (offsets
)->car
);
1033 tab_offset
= XINT (XCONS (offsets
)->cdr
);
1036 hscroll
= tab_offset
= 0;
1039 window
= Fselected_window ();
1041 CHECK_LIVE_WINDOW (window
, 0);
1043 pos
= compute_motion (XINT (from
), XINT (XCONS (frompos
)->cdr
),
1044 XINT (XCONS (frompos
)->car
), 0,
1045 XINT (to
), XINT (XCONS (topos
)->cdr
),
1046 XINT (XCONS (topos
)->car
),
1047 XINT (width
), hscroll
, tab_offset
,
1050 XSETFASTINT (bufpos
, pos
->bufpos
);
1051 XSETINT (hpos
, pos
->hpos
);
1052 XSETINT (vpos
, pos
->vpos
);
1053 XSETINT (prevhpos
, pos
->prevhpos
);
1055 return Fcons (bufpos
,
1059 Fcons (pos
->contin
? Qt
: Qnil
, Qnil
)))));
1063 /* Return the column of position POS in window W's buffer.
1064 The result is rounded down to a multiple of the internal width of W.
1065 This is the amount of indentation of position POS
1066 that is not visible in its horizontal position in the window. */
1069 pos_tab_offset (w
, pos
)
1075 int width
= window_internal_width (w
) - 1;
1077 if (pos
== BEGV
|| FETCH_CHAR (pos
- 1) == '\n')
1080 col
= current_column ();
1081 TEMP_SET_PT (opoint
);
1082 return col
- (col
% width
);
1086 /* Fvertical_motion and vmotion */
1087 struct position val_vmotion
;
1090 vmotion (from
, vtarget
, w
)
1091 register int from
, vtarget
;
1094 int width
= window_internal_width (w
) - 1;
1095 int hscroll
= XINT (w
->hscroll
);
1096 struct position pos
;
1097 /* vpos is cumulative vertical position, changed as from is changed */
1098 register int vpos
= 0;
1099 Lisp_Object prevline
;
1101 int lmargin
= hscroll
> 0 ? 1 - hscroll
: 0;
1103 = (INTEGERP (current_buffer
->selective_display
)
1104 ? XINT (current_buffer
->selective_display
)
1105 : !NILP (current_buffer
->selective_display
) ? -1 : 0);
1110 XSETWINDOW (window
, w
);
1112 /* The omission of the clause
1113 && marker_position (w->start) == BEG
1114 here is deliberate; I think we want to measure from the prompt
1115 position even if the minibuffer window has scrolled. */
1116 if (EQ (window
, minibuf_window
))
1118 if (minibuf_prompt_width
== 0 && STRINGP (minibuf_prompt
))
1119 minibuf_prompt_width
1120 = string_display_width (minibuf_prompt
, Qnil
, Qnil
);
1122 start_hpos
= minibuf_prompt_width
;
1125 if (vpos
>= vtarget
)
1127 /* To move upward, go a line at a time until
1128 we have gone at least far enough */
1132 while ((vpos
> vtarget
|| first
) && from
> BEGV
)
1134 Lisp_Object propval
;
1136 XSETFASTINT (prevline
, find_next_newline_no_quit (from
- 1, -1));
1137 while (XFASTINT (prevline
) > BEGV
1139 && indented_beyond_p (XFASTINT (prevline
), selective
))
1140 #ifdef USE_TEXT_PROPERTIES
1141 /* watch out for newlines with `invisible' property */
1142 || (propval
= Fget_char_property (prevline
,
1145 TEXT_PROP_MEANS_INVISIBLE (propval
))
1148 XSETFASTINT (prevline
,
1149 find_next_newline_no_quit (XFASTINT (prevline
) - 1,
1151 pos
= *compute_motion (XFASTINT (prevline
), 0,
1152 lmargin
+ (XFASTINT (prevline
) == BEG
1155 from
, 1 << (BITS_PER_INT
- 2), 0,
1156 width
, hscroll
, 0, w
);
1159 from
= XFASTINT (prevline
);
1162 /* If we made exactly the desired vertical distance,
1163 or if we hit beginning of buffer,
1164 return point found */
1165 if (vpos
>= vtarget
)
1167 val_vmotion
.bufpos
= from
;
1168 val_vmotion
.vpos
= vpos
;
1169 val_vmotion
.hpos
= lmargin
;
1170 val_vmotion
.contin
= 0;
1171 val_vmotion
.prevhpos
= 0;
1172 return &val_vmotion
;
1175 /* Otherwise find the correct spot by moving down */
1177 /* Moving downward is simple, but must calculate from beg of line
1178 to determine hpos of starting point */
1179 if (from
> BEGV
&& FETCH_CHAR (from
- 1) != '\n')
1181 Lisp_Object propval
;
1183 XSETFASTINT (prevline
, find_next_newline_no_quit (from
, -1));
1184 while (XFASTINT (prevline
) > BEGV
1186 && indented_beyond_p (XFASTINT (prevline
), selective
))
1187 #ifdef USE_TEXT_PROPERTIES
1188 /* watch out for newlines with `invisible' property */
1189 || (propval
= Fget_char_property (prevline
, Qinvisible
,
1191 TEXT_PROP_MEANS_INVISIBLE (propval
))
1194 XSETFASTINT (prevline
,
1195 find_next_newline_no_quit (XFASTINT (prevline
) - 1,
1197 pos
= *compute_motion (XFASTINT (prevline
), 0,
1198 lmargin
+ (XFASTINT (prevline
) == BEG
1201 from
, 1 << (BITS_PER_INT
- 2), 0,
1202 width
, hscroll
, 0, w
);
1207 pos
.hpos
= lmargin
+ (from
== BEG
? start_hpos
: 0);
1211 return compute_motion (from
, vpos
, pos
.hpos
, did_motion
,
1212 ZV
, vtarget
, - (1 << (BITS_PER_INT
- 2)),
1213 width
, hscroll
, pos
.vpos
* width
, w
);
1216 DEFUN ("vertical-motion", Fvertical_motion
, Svertical_motion
, 1, 2, 0,
1217 "Move to start of screen line LINES lines down.\n\
1218 If LINES is negative, this is moving up.\n\
1220 The optional second argument WINDOW specifies the window to use for\n\
1221 parameters such as width, horizontal scrolling, and so on.\n\
1222 the default is the selected window.\n\
1223 It does not matter what buffer is displayed in WINDOW.\n\
1224 `vertical-motion' always uses the current buffer.\n\
1226 Sets point to position found; this may be start of line\n\
1227 or just the start of a continuation line.\n\
1228 Returns number of lines moved; may be closer to zero than LINES\n\
1229 if beginning or end of buffer was reached.")
1231 Lisp_Object lines
, window
;
1233 struct position pos
;
1235 CHECK_NUMBER (lines
, 0);
1236 if (! NILP (window
))
1237 CHECK_WINDOW (window
, 0);
1239 window
= selected_window
;
1241 pos
= *vmotion (point
, (int) XINT (lines
), XWINDOW (window
));
1243 SET_PT (pos
.bufpos
);
1244 return make_number (pos
.vpos
);
1247 /* file's initialization. */
1251 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode
,
1252 "*Indentation can insert tabs if this is non-nil.\n\
1253 Setting this variable automatically makes it local to the current buffer.");
1254 indent_tabs_mode
= 1;
1256 defsubr (&Scurrent_indentation
);
1257 defsubr (&Sindent_to
);
1258 defsubr (&Scurrent_column
);
1259 defsubr (&Smove_to_column
);
1260 defsubr (&Svertical_motion
);
1261 defsubr (&Scompute_motion
);