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. */
33 #include "intervals.h"
34 #include "region-cache.h"
36 /* Indentation can insert tabs if this is non-zero;
37 otherwise always uses spaces */
40 #define min(a, b) ((a) < (b) ? (a) : (b))
41 #define max(a, b) ((a) > (b) ? (a) : (b))
45 /* These three values memoize the current column to avoid recalculation */
46 /* Some things in set last_known_column_point to -1
47 to mark the memoized value as invalid */
48 /* Last value returned by current_column */
49 int last_known_column
;
50 /* Value of point when current_column was called */
51 int last_known_column_point
;
52 /* Value of MODIFF when current_column was called */
53 int last_known_column_modified
;
55 static int current_column_1 ();
57 /* Cache of beginning of line found by the last call of
59 int current_column_bol_cache
;
61 /* Get the display table to use for the current buffer. */
63 struct Lisp_Char_Table
*
64 buffer_display_table ()
68 thisbuf
= current_buffer
->display_table
;
69 if (DISP_TABLE_P (thisbuf
))
70 return XCHAR_TABLE (thisbuf
);
71 if (DISP_TABLE_P (Vstandard_display_table
))
72 return XCHAR_TABLE (Vstandard_display_table
);
76 /* Width run cache considerations. */
78 /* Return the width of character C under display table DP. */
81 character_width (c
, dp
)
83 struct Lisp_Char_Table
*dp
;
87 /* These width computations were determined by examining the cases
88 in display_text_line. */
90 /* Everything can be handled by the display table, if it's
91 present and the element is right. */
92 if (dp
&& (elt
= DISP_CHAR_VECTOR (dp
, c
), VECTORP (elt
)))
93 return XVECTOR (elt
)->size
;
95 /* Some characters are special. */
96 if (c
== '\n' || c
== '\t' || c
== '\015')
99 /* Printing characters have width 1. */
100 else if (c
>= 040 && c
< 0177)
103 /* Everybody else (control characters, metacharacters) has other
104 widths. We could return their actual widths here, but they
105 depend on things like ctl_arrow and crud like that, and they're
106 not very common at all. So we'll just claim we don't know their
112 /* Return true iff the display table DISPTAB specifies the same widths
113 for characters as WIDTHTAB. We use this to decide when to
114 invalidate the buffer's width_run_cache. */
116 disptab_matches_widthtab (disptab
, widthtab
)
117 struct Lisp_Char_Table
*disptab
;
118 struct Lisp_Vector
*widthtab
;
122 if (widthtab
->size
!= 256)
125 for (i
= 0; i
< 256; i
++)
126 if (character_width (i
, disptab
)
127 != XFASTINT (widthtab
->contents
[i
]))
133 /* Recompute BUF's width table, using the display table DISPTAB. */
135 recompute_width_table (buf
, disptab
)
137 struct Lisp_Char_Table
*disptab
;
140 struct Lisp_Vector
*widthtab
;
142 if (!VECTORP (buf
->width_table
))
143 buf
->width_table
= Fmake_vector (make_number (256), make_number (0));
144 widthtab
= XVECTOR (buf
->width_table
);
145 if (widthtab
->size
!= 256)
148 for (i
= 0; i
< 256; i
++)
149 XSETFASTINT (widthtab
->contents
[i
], character_width (i
, disptab
));
152 /* Allocate or free the width run cache, as requested by the current
153 state of current_buffer's cache_long_line_scans variable. */
155 width_run_cache_on_off ()
157 if (NILP (current_buffer
->cache_long_line_scans
)
158 /* And, for the moment, this feature doesn't work on multibyte
160 || !NILP (current_buffer
->enable_multibyte_characters
))
162 /* It should be off. */
163 if (current_buffer
->width_run_cache
)
165 free_region_cache (current_buffer
->width_run_cache
);
166 current_buffer
->width_run_cache
= 0;
167 current_buffer
->width_table
= Qnil
;
172 /* It should be on. */
173 if (current_buffer
->width_run_cache
== 0)
175 current_buffer
->width_run_cache
= new_region_cache ();
176 recompute_width_table (current_buffer
, buffer_display_table ());
182 /* Skip some invisible characters starting from POS.
183 This includes characters invisible because of text properties
184 and characters invisible because of overlays.
186 If position POS is followed by invisible characters,
187 skip some of them and return the position after them.
188 Otherwise return POS itself.
190 Set *NEXT_BOUNDARY_P to the next position at which
191 it will be necessary to call this function again.
193 Don't scan past TO, and don't set *NEXT_BOUNDARY_P
194 to a value greater than TO.
196 If WINDOW is non-nil, and this buffer is displayed in WINDOW,
197 take account of overlays that apply only in WINDOW.
199 We don't necessarily skip all the invisible characters after POS
200 because that could take a long time. We skip a reasonable number
201 which can be skipped quickly. If there might be more invisible
202 characters immediately following, then *NEXT_BOUNDARY_P
203 will equal the return value. */
206 skip_invisible (pos
, next_boundary_p
, to
, window
)
208 int *next_boundary_p
;
212 Lisp_Object prop
, position
, overlay_limit
, proplimit
;
216 XSETFASTINT (position
, pos
);
217 XSETBUFFER (buffer
, current_buffer
);
219 /* Give faster response for overlay lookup near POS. */
220 recenter_overlay_lists (current_buffer
, pos
);
222 /* We must not advance farther than the next overlay change.
223 The overlay change might change the invisible property;
224 or there might be overlay strings to be displayed there. */
225 overlay_limit
= Fnext_overlay_change (position
);
226 /* As for text properties, this gives a lower bound
227 for where the invisible text property could change. */
228 proplimit
= Fnext_property_change (position
, buffer
, Qt
);
229 if (XFASTINT (overlay_limit
) < XFASTINT (proplimit
))
230 proplimit
= overlay_limit
;
231 /* PROPLIMIT is now a lower bound for the next change
232 in invisible status. If that is plenty far away,
233 use that lower bound. */
234 if (XFASTINT (proplimit
) > pos
+ 100 || XFASTINT (proplimit
) >= to
)
235 *next_boundary_p
= XFASTINT (proplimit
);
236 /* Otherwise, scan for the next `invisible' property change. */
239 /* Don't scan terribly far. */
240 XSETFASTINT (proplimit
, min (pos
+ 100, to
));
241 /* No matter what. don't go past next overlay change. */
242 if (XFASTINT (overlay_limit
) < XFASTINT (proplimit
))
243 proplimit
= overlay_limit
;
244 end
= XFASTINT (Fnext_single_property_change (position
, Qinvisible
,
246 /* Don't put the boundary in the middle of multibyte form if
247 there is no actual property change. */
249 && !NILP (current_buffer
->enable_multibyte_characters
)
251 while (pos
< end
&& !CHAR_HEAD_P (POS_ADDR (end
)))
253 *next_boundary_p
= end
;
255 /* if the `invisible' property is set, we can skip to
256 the next property change */
257 if (!NILP (window
) && EQ (XWINDOW (window
)->buffer
, buffer
))
258 prop
= Fget_char_property (position
, Qinvisible
, window
);
260 prop
= Fget_char_property (position
, Qinvisible
, buffer
);
261 if (TEXT_PROP_MEANS_INVISIBLE (prop
))
262 return *next_boundary_p
;
266 DEFUN ("current-column", Fcurrent_column
, Scurrent_column
, 0, 0, 0,
267 "Return the horizontal position of point. Beginning of line is column 0.\n\
268 This is calculated by adding together the widths of all the displayed\n\
269 representations of the character between the start of the previous line\n\
270 and point. (eg control characters will have a width of 2 or 4, tabs\n\
271 will have a variable width)\n\
272 Ignores finite width of frame, which means that this function may return\n\
273 values greater than (frame-width).\n\
274 Whether the line is visible (if `selective-display' is t) has no effect;\n\
275 however, ^M is treated as end of line when `selective-display' is t.")
279 XSETFASTINT (temp
, current_column ());
283 /* Cancel any recorded value of the horizontal position. */
286 invalidate_current_column ()
288 last_known_column_point
= 0;
295 register unsigned char *ptr
, *stop
;
296 register int tab_seen
;
299 register int tab_width
= XINT (current_buffer
->tab_width
);
300 int ctl_arrow
= !NILP (current_buffer
->ctl_arrow
);
301 register struct Lisp_Char_Table
*dp
= buffer_display_table ();
304 if (PT
== last_known_column_point
305 && MODIFF
== last_known_column_modified
)
306 return last_known_column
;
308 /* If the buffer has overlays, text properties, or multibyte,
309 use a more general algorithm. */
310 if (BUF_INTERVALS (current_buffer
)
311 || !NILP (current_buffer
->overlays_before
)
312 || !NILP (current_buffer
->overlays_after
)
313 || !NILP (current_buffer
->enable_multibyte_characters
))
314 return current_column_1 (PT
);
316 /* Scan backwards from point to the previous newline,
317 counting width. Tab characters are the only complicated case. */
319 /* Make a pointer for decrementing through the chars before point. */
320 ptr
= POS_ADDR (PT
- 1) + 1;
321 /* Make a pointer to where consecutive chars leave off,
322 going backwards from point. */
325 else if (PT
<= GPT
|| BEGV
> GPT
)
330 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
332 col
= 0, tab_seen
= 0, post_tab
= 0;
338 /* We stopped either for the beginning of the buffer
340 if (ptr
== BEGV_ADDR
)
342 /* It was the gap. Jump back over it. */
345 /* Check whether that brings us to beginning of buffer. */
346 if (BEGV
>= GPT
) break;
350 if (dp
!= 0 && VECTORP (DISP_CHAR_VECTOR (dp
, c
)))
351 col
+= XVECTOR (DISP_CHAR_VECTOR (dp
, c
))->size
;
352 else if (c
>= 040 && c
< 0177)
355 || (c
== '\r' && EQ (current_buffer
->selective_display
, Qt
)))
363 col
= ((col
+ tab_width
) / tab_width
) * tab_width
;
370 col
+= (ctl_arrow
&& c
< 0200) ? 2 : 4;
375 col
= ((col
+ tab_width
) / tab_width
) * tab_width
;
379 if (ptr
== BEGV_ADDR
)
380 current_column_bol_cache
= BEGV
;
382 current_column_bol_cache
= PTR_CHAR_POS (ptr
);
383 last_known_column
= col
;
384 last_known_column_point
= PT
;
385 last_known_column_modified
= MODIFF
;
390 /* Return the column number of position POS
391 by scanning forward from the beginning of the line.
392 This function handles characters that are invisible
393 due to text properties or overlays. */
396 current_column_1 (pos
)
399 register int tab_width
= XINT (current_buffer
->tab_width
);
400 register int ctl_arrow
= !NILP (current_buffer
->ctl_arrow
);
401 register struct Lisp_Char_Table
*dp
= buffer_display_table ();
403 /* Start the scan at the beginning of this line with column number 0. */
404 register int col
= 0;
405 int scan
= current_column_bol_cache
= find_next_newline (pos
, -1);
406 int next_boundary
= scan
;
407 int multibyte
= !NILP (current_buffer
->enable_multibyte_characters
);
409 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
411 /* Scan forward to the target position. */
416 /* Occasionally we may need to skip invisible text. */
417 while (scan
== next_boundary
)
419 /* This updates NEXT_BOUNDARY to the next place
420 where we might need to skip more invisible text. */
421 scan
= skip_invisible (scan
, &next_boundary
, pos
, Qnil
);
426 c
= FETCH_BYTE (scan
);
427 if (dp
!= 0 && VECTORP (DISP_CHAR_VECTOR (dp
, c
)))
429 col
+= XVECTOR (DISP_CHAR_VECTOR (dp
, c
))->size
;
435 if (c
== '\r' && EQ (current_buffer
->selective_display
, Qt
))
442 col
= col
/ tab_width
* tab_width
;
444 else if (multibyte
&& BASE_LEADING_CODE_P (c
))
447 /* Start of multi-byte form. */
448 if (c
== LEADING_CODE_COMPOSITION
)
450 unsigned char *ptr
= POS_ADDR (scan
);
452 int cmpchar_id
= str_cmpchar_id (ptr
, next_boundary
- scan
);
455 scan
+= cmpchar_table
[cmpchar_id
]->len
,
456 col
+= cmpchar_table
[cmpchar_id
]->width
;
459 { /* invalid composite character */
466 /* Here, we check that the following bytes are valid
467 constituents of multi-byte form. */
468 int len
= BYTES_BY_CHAR_HEAD (c
), i
;
470 for (i
= 1, scan
++; i
< len
; i
++, scan
++)
471 /* We don't need range checking for PTR because there
472 are anchors (`\0') at GAP and Z. */
473 if (CHAR_HEAD_P (POS_ADDR (scan
))) break;
475 col
+= 4, scan
-= i
- 1;
477 col
+= WIDTH_BY_CHAR_HEAD (c
);
480 else if (ctl_arrow
&& (c
< 040 || c
== 0177))
482 else if (c
< 040 || c
>= 0177)
489 last_known_column
= col
;
490 last_known_column_point
= PT
;
491 last_known_column_modified
= MODIFF
;
496 /* Return the width in columns of the part of STRING from BEG to END.
497 If BEG is nil, that stands for the beginning of STRING.
498 If END is nil, that stands for the end of STRING. */
501 string_display_width (string
, beg
, end
)
502 Lisp_Object string
, beg
, end
;
505 register unsigned char *ptr
, *stop
;
506 register int tab_seen
;
509 register int tab_width
= XINT (current_buffer
->tab_width
);
510 int ctl_arrow
= !NILP (current_buffer
->ctl_arrow
);
511 register struct Lisp_Char_Table
*dp
= buffer_display_table ();
515 e
= XSTRING (string
)->size
;
518 CHECK_NUMBER (end
, 0);
526 CHECK_NUMBER (beg
, 0);
530 /* Make a pointer for decrementing through the chars before point. */
531 ptr
= XSTRING (string
)->data
+ e
;
532 /* Make a pointer to where consecutive chars leave off,
533 going backwards from point. */
534 stop
= XSTRING (string
)->data
+ b
;
536 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
538 col
= 0, tab_seen
= 0, post_tab
= 0;
546 if (dp
!= 0 && VECTORP (DISP_CHAR_VECTOR (dp
, c
)))
547 col
+= XVECTOR (DISP_CHAR_VECTOR (dp
, c
))->size
;
548 else if (c
>= 040 && c
< 0177)
555 col
= ((col
+ tab_width
) / tab_width
) * tab_width
;
562 col
+= (ctl_arrow
&& c
< 0200) ? 2 : 4;
567 col
= ((col
+ tab_width
) / tab_width
) * tab_width
;
574 DEFUN ("indent-to", Findent_to
, Sindent_to
, 1, 2, "NIndent to column: ",
575 "Indent from point with tabs and spaces until COLUMN is reached.\n\
576 Optional second argument MININUM says always do at least MININUM spaces\n\
577 even if that goes past COLUMN; by default, MININUM is zero.")
579 Lisp_Object column
, minimum
;
582 register int fromcol
;
583 register int tab_width
= XINT (current_buffer
->tab_width
);
585 CHECK_NUMBER (column
, 0);
587 XSETFASTINT (minimum
, 0);
588 CHECK_NUMBER (minimum
, 1);
590 fromcol
= current_column ();
591 mincol
= fromcol
+ XINT (minimum
);
592 if (mincol
< XINT (column
)) mincol
= XINT (column
);
594 if (fromcol
== mincol
)
595 return make_number (mincol
);
597 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
599 if (indent_tabs_mode
)
602 XSETFASTINT (n
, mincol
/ tab_width
- fromcol
/ tab_width
);
603 if (XFASTINT (n
) != 0)
605 Finsert_char (make_number ('\t'), n
, Qt
);
607 fromcol
= (mincol
/ tab_width
) * tab_width
;
611 XSETFASTINT (column
, mincol
- fromcol
);
612 Finsert_char (make_number (' '), column
, Qt
);
614 last_known_column
= mincol
;
615 last_known_column_point
= PT
;
616 last_known_column_modified
= MODIFF
;
618 XSETINT (column
, mincol
);
623 DEFUN ("current-indentation", Fcurrent_indentation
, Scurrent_indentation
,
625 "Return the indentation of the current line.\n\
626 This is the horizontal position of the character\n\
627 following any initial whitespace.")
632 XSETFASTINT (val
, position_indentation (find_next_newline (PT
, -1)));
636 position_indentation (pos
)
639 register int column
= 0;
640 register int tab_width
= XINT (current_buffer
->tab_width
);
641 register unsigned char *p
;
642 register unsigned char *stop
;
643 unsigned char *start
;
644 int next_boundary
= pos
;
647 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
650 /* STOP records the value of P at which we will need
651 to think about the gap, or about invisible text,
652 or about the end of the buffer. */
654 /* START records the starting value of P. */
662 /* If we have updated P, set POS to match.
663 The first time we enter the loop, POS is already right. */
665 pos
= PTR_CHAR_POS (p
);
666 /* Consider the various reasons STOP might have been set here. */
669 if (pos
== next_boundary
)
670 pos
= skip_invisible (pos
, &next_boundary
, ZV
, Qnil
);
672 ceiling
= BUFFER_CEILING_OF (pos
) + 1;
673 /* Compute the next place we need to stop and think,
674 and set STOP accordingly. */
675 stop_pos
= min (ceiling
, next_boundary
);
676 /* The -1 and +1 arrange to point at the first byte of gap
677 (if STOP_POS is the position of the gap)
678 rather than at the data after the gap. */
680 stop
= POS_ADDR (stop_pos
- 1) + 1;
686 if (! NILP (current_buffer
->enable_multibyte_characters
))
692 column
+= tab_width
- column
% tab_width
;
695 if (ASCII_BYTE_P (p
[-1])
696 || NILP (current_buffer
->enable_multibyte_characters
))
699 int pos
= PTR_CHAR_POS (p
- 1);
700 int c
= FETCH_MULTIBYTE_CHAR (pos
);
701 if (CHAR_HAS_CATEGORY (c
, ' '))
714 /* Test whether the line beginning at POS is indented beyond COLUMN.
715 Blank lines are treated as if they had the same indentation as the
718 indented_beyond_p (pos
, column
)
721 while (pos
> BEGV
&& FETCH_BYTE (pos
) == '\n')
722 pos
= find_next_newline_no_quit (pos
- 1, -1);
723 return (position_indentation (pos
) >= column
);
726 DEFUN ("move-to-column", Fmove_to_column
, Smove_to_column
, 1, 2, "p",
727 "Move point to column COLUMN in the current line.\n\
728 The column of a character is calculated by adding together the widths\n\
729 as displayed of the previous characters in the line.\n\
730 This function ignores line-continuation;\n\
731 there is no upper limit on the column number a character can have\n\
732 and horizontal scrolling has no effect.\n\
734 If specified column is within a character, point goes after that character.\n\
735 If it's past end of line, point goes to end of line.\n\n\
736 A non-nil second (optional) argument FORCE means, if the line\n\
737 is too short to reach column COLUMN then add spaces/tabs to get there,\n\
738 and if COLUMN is in the middle of a tab character, change it to spaces.\n\
740 The return value is the current column.")
742 Lisp_Object column
, force
;
745 register int col
= current_column ();
748 register int tab_width
= XINT (current_buffer
->tab_width
);
749 register int ctl_arrow
= !NILP (current_buffer
->ctl_arrow
);
750 register struct Lisp_Char_Table
*dp
= buffer_display_table ();
751 register int multibyte
= !NILP (current_buffer
->enable_multibyte_characters
);
759 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
760 CHECK_NATNUM (column
, 0);
761 goal
= XINT (column
);
767 /* If we're starting past the desired column,
768 back up to beginning of line and scan from there. */
772 pos
= current_column_bol_cache
;
778 while (pos
== next_boundary
)
780 pos
= skip_invisible (pos
, &next_boundary
, end
, Qnil
);
785 /* Test reaching the goal column. We do this after skipping
786 invisible characters, so that we put point before the
787 character on which the cursor will appear. */
791 c
= FETCH_BYTE (pos
);
792 if (dp
!= 0 && VECTORP (DISP_CHAR_VECTOR (dp
, c
)))
794 col
+= XVECTOR (DISP_CHAR_VECTOR (dp
, c
))->size
;
800 if (c
== '\r' && EQ (current_buffer
->selective_display
, Qt
))
807 col
= col
/ tab_width
* tab_width
;
809 else if (ctl_arrow
&& (c
< 040 || c
== 0177))
811 else if (c
< 040 || c
== 0177)
815 else if (multibyte
&& BASE_LEADING_CODE_P (c
))
817 /* Start of multi-byte form. */
820 pos
--; /* rewind to the character head */
821 ptr
= POS_ADDR (pos
);
822 if (c
== LEADING_CODE_COMPOSITION
)
824 int cmpchar_id
= str_cmpchar_id (ptr
, end
- pos
);
828 col
+= cmpchar_table
[cmpchar_id
]->width
;
829 pos
+= cmpchar_table
[cmpchar_id
]->len
;
832 { /* invalid composite character */
839 /* Here, we check that the following bytes are valid
840 constituents of multi-byte form. */
841 int len
= BYTES_BY_CHAR_HEAD (c
), i
;
843 for (i
= 1, ptr
++; i
< len
; i
++, ptr
++)
844 /* We don't need range checking for PTR because there
845 are anchors (`\0') both at GPT and Z. */
846 if (CHAR_HEAD_P (ptr
)) break;
850 col
+= WIDTH_BY_CHAR_HEAD (c
), pos
+= i
;
860 /* If a tab char made us overshoot, change it to spaces
861 and scan through it again. */
862 if (!NILP (force
) && col
> goal
&& c
== '\t' && prev_col
< goal
)
866 del_range (PT
- 1, PT
);
867 Findent_to (make_number (goal
), Qnil
);
869 Findent_to (make_number (col
), Qnil
);
871 /* Set the last_known... vars consistently. */
875 /* If line ends prematurely, add space to the end. */
876 if (col
< goal
&& !NILP (force
))
877 Findent_to (make_number (col
= goal
), Qnil
);
879 last_known_column
= col
;
880 last_known_column_point
= PT
;
881 last_known_column_modified
= MODIFF
;
883 XSETFASTINT (val
, col
);
887 /* compute_motion: compute buffer posn given screen posn and vice versa */
889 struct position val_compute_motion
;
891 /* Scan the current buffer forward from offset FROM, pretending that
892 this is at line FROMVPOS, column FROMHPOS, until reaching buffer
893 offset TO or line TOVPOS, column TOHPOS (whichever comes first),
894 and return the ending buffer position and screen location. If we
895 can't hit the requested column exactly (because of a tab or other
896 multi-column character), overshoot.
898 DID_MOTION is 1 if FROMHPOS has already accounted for overlay strings
899 at FROM. This is the case if FROMVPOS and FROMVPOS came from an
900 earlier call to compute_motion. The other common case is that FROMHPOS
901 is zero and FROM is a position that "belongs" at column zero, but might
902 be shifted by overlay strings; in this case DID_MOTION should be 0.
904 WIDTH is the number of columns available to display text;
905 compute_motion uses this to handle continuation lines and such.
906 HSCROLL is the number of columns not being displayed at the left
907 margin; this is usually taken from a window's hscroll member.
908 TAB_OFFSET is the number of columns of the first tab that aren't
909 being displayed, perhaps because of a continuation line or
912 compute_motion returns a pointer to a struct position. The bufpos
913 member gives the buffer position at the end of the scan, and hpos
914 and vpos give its cartesian location. prevhpos is the column at
915 which the character before bufpos started, and contin is non-zero
916 if we reached the current line by continuing the previous.
918 Note that FROMHPOS and TOHPOS should be expressed in real screen
919 columns, taking HSCROLL and the truncation glyph at the left margin
920 into account. That is, beginning-of-line moves you to the hpos
921 -HSCROLL + (HSCROLL > 0).
923 For example, to find the buffer position of column COL of line LINE
924 of a certain window, pass the window's starting location as FROM
925 and the window's upper-left coordinates as FROMVPOS and FROMHPOS.
926 Pass the buffer's ZV as TO, to limit the scan to the end of the
927 visible section of the buffer, and pass LINE and COL as TOVPOS and
930 When displaying in window w, a typical formula for WIDTH is:
933 - (has_vertical_scroll_bars
934 ? FRAME_SCROLL_BAR_COLS (XFRAME (window->frame))
935 : (window_width + window_left != frame_width))
938 window_width is XFASTINT (w->width),
939 window_left is XFASTINT (w->left),
940 has_vertical_scroll_bars is
941 FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (WINDOW_FRAME (window)))
942 and frame_width = FRAME_WIDTH (XFRAME (window->frame))
944 Or you can let window_internal_width do this all for you, and write:
945 window_internal_width (w) - 1
947 The `-1' accounts for the continuation-line backslashes; the rest
948 accounts for window borders if the window is split horizontally, and
949 the scroll bars if they are turned on. */
952 compute_motion (from
, fromvpos
, fromhpos
, did_motion
, to
, tovpos
, tohpos
, width
, hscroll
, tab_offset
, win
)
953 int from
, fromvpos
, fromhpos
, to
, tovpos
, tohpos
;
956 int hscroll
, tab_offset
;
959 register int hpos
= fromhpos
;
960 register int vpos
= fromvpos
;
964 register int tab_width
= XFASTINT (current_buffer
->tab_width
);
965 register int ctl_arrow
= !NILP (current_buffer
->ctl_arrow
);
966 register struct Lisp_Char_Table
*dp
= window_display_table (win
);
968 = (INTEGERP (current_buffer
->selective_display
)
969 ? XINT (current_buffer
->selective_display
)
970 : !NILP (current_buffer
->selective_display
) ? -1 : 0);
973 = (selective
&& dp
&& VECTORP (DISP_INVIS_VECTOR (dp
))
974 ? XVECTOR (DISP_INVIS_VECTOR (dp
))->size
: 0);
975 /* The next location where the `invisible' property changes, or an
976 overlay starts or ends. */
977 int next_boundary
= from
;
979 /* For computing runs of characters with similar widths.
980 Invariant: width_run_width is zero, or all the characters
981 from width_run_start to width_run_end have a fixed width of
983 int width_run_start
= from
;
984 int width_run_end
= from
;
985 int width_run_width
= 0;
986 Lisp_Object
*width_table
;
989 /* The next buffer pos where we should consult the width run cache. */
990 int next_width_run
= from
;
993 int multibyte
= !NILP (current_buffer
->enable_multibyte_characters
);
994 int wide_column
= 0; /* Set to 1 when a previous character
996 int prev_pos
; /* Previous buffer position. */
997 int contin_hpos
; /* HPOS of last column of continued line. */
998 int prev_tab_offset
; /* Previous tab offset. */
1000 XSETBUFFER (buffer
, current_buffer
);
1001 XSETWINDOW (window
, win
);
1003 width_run_cache_on_off ();
1004 if (dp
== buffer_display_table ())
1005 width_table
= (VECTORP (current_buffer
->width_table
)
1006 ? XVECTOR (current_buffer
->width_table
)->contents
1009 /* If the window has its own display table, we can't use the width
1010 run cache, because that's based on the buffer's display table. */
1013 if (tab_width
<= 0 || tab_width
> 1000) tab_width
= 8;
1015 pos
= prev_pos
= from
;
1017 prev_tab_offset
= tab_offset
;
1020 while (pos
== next_boundary
)
1024 /* If the caller says that the screen position came from an earlier
1025 call to compute_motion, then we've already accounted for the
1026 overlay strings at point. This is only true the first time
1027 through, so clear the flag after testing it. */
1029 /* We need to skip past the overlay strings. Currently those
1030 strings must not contain TAB;
1031 if we want to relax that restriction, something will have
1032 to be changed here. */
1034 unsigned char *ovstr
;
1035 int ovlen
= overlay_strings (pos
, win
, &ovstr
);
1036 hpos
+= (multibyte
? strwidth (ovstr
, ovlen
) : ovlen
);
1043 /* Advance POS past invisible characters
1044 (but not necessarily all that there are here),
1045 and store in next_boundary the next position where
1046 we need to call skip_invisible. */
1047 newpos
= skip_invisible (pos
, &next_boundary
, to
, window
);
1055 /* Handle right margin. */
1056 /* Note on a wide-column character.
1058 Characters are classified into the following three categories
1059 according to the width (columns occupied on screen).
1061 (1) single-column character: ex. `a'
1062 (2) multi-column character: ex. `^A', TAB, `\033'
1063 (3) wide-column character: ex. Japanese character, Chinese character
1064 (In the following example, `W_' stands for them.)
1066 Multi-column characters can be divided around the right margin,
1067 but wide-column characters cannot.
1071 (*) The cursor is placed on the next character after the point.
1075 j ^---- next after the point
1076 ^--- next char. after the point.
1078 In case of sigle-column character
1082 033 ^---- next after the point, next char. after the point.
1084 In case of multi-column character
1088 W_ ^---- next after the point
1089 ^---- next char. after the point.
1091 In case of wide-column character
1093 The problem here is continuation at a wide-column character.
1094 In this case, the line may shorter less than WIDTH.
1095 And we find the continuation AFTER it occurs.
1102 || (truncate_partial_width_windows
1103 && width
+ 1 < FRAME_WIDTH (XFRAME (WINDOW_FRAME (win
))))
1104 || !NILP (current_buffer
->truncate_lines
))
1106 /* Truncating: skip to newline. */
1107 if (pos
<= to
) /* This IF is needed because we may past TO */
1108 pos
= find_before_next_newline (pos
, to
, 1);
1110 /* If we just skipped next_boundary,
1111 loop around in the main while
1113 if (pos
>= next_boundary
)
1114 next_boundary
= pos
+ 1;
1116 prev_tab_offset
= tab_offset
;
1121 /* Remember the previous value. */
1122 prev_tab_offset
= tab_offset
;
1127 tab_offset
+= prev_hpos
;
1131 tab_offset
+= width
;
1135 contin_hpos
= prev_hpos
;
1140 /* Stop if past the target buffer position or screen position. */
1143 /* Go back to the previous position. */
1146 tab_offset
= prev_tab_offset
;
1148 /* NOTE on contin_hpos, hpos, and prev_hpos.
1152 W_ ^---- contin_hpos
1158 if (contin_hpos
&& prev_hpos
== 0
1159 && contin_hpos
< width
&& !wide_column
)
1161 /* Line breaking occurs in the middle of multi-column
1162 character. Go back to previous line. */
1167 /* If previous character is NEWLINE,
1168 set VPOS back to previous line */
1173 if (vpos
> tovpos
|| vpos
== tovpos
&& hpos
>= tohpos
)
1175 if (contin_hpos
&& prev_hpos
== 0
1176 && ((hpos
> tohpos
&& contin_hpos
== width
) || wide_column
))
1177 { /* Line breaks because we can't put the character at the
1178 previous line any more. It is not the multi-column
1179 character continued in middle. Go back to previous
1180 buffer position, screen position, and set tab offset
1181 to previous value. It's the beginning of the
1185 tab_offset
= prev_tab_offset
;
1189 if (pos
== ZV
) /* We cannot go beyond ZV. Stop here. */
1196 /* Consult the width run cache to see if we can avoid inspecting
1197 the text character-by-character. */
1198 if (current_buffer
->width_run_cache
&& pos
>= next_width_run
)
1202 = region_cache_forward (current_buffer
,
1203 current_buffer
->width_run_cache
,
1206 /* A width of zero means the character's width varies (like
1207 a tab), is meaningless (like a newline), or we just don't
1208 want to skip over it for some other reason. */
1209 if (common_width
!= 0)
1213 /* Don't go past the final buffer posn the user
1218 run_end_hpos
= hpos
+ (run_end
- pos
) * common_width
;
1220 /* Don't go past the final horizontal position the user
1222 if (vpos
== tovpos
&& run_end_hpos
> tohpos
)
1224 run_end
= pos
+ (tohpos
- hpos
) / common_width
;
1225 run_end_hpos
= hpos
+ (run_end
- pos
) * common_width
;
1228 /* Don't go past the margin. */
1229 if (run_end_hpos
>= width
)
1231 run_end
= pos
+ (width
- hpos
) / common_width
;
1232 run_end_hpos
= hpos
+ (run_end
- pos
) * common_width
;
1235 hpos
= run_end_hpos
;
1237 prev_hpos
= hpos
- common_width
;
1241 next_width_run
= run_end
+ 1;
1244 /* We have to scan the text character-by-character. */
1247 c
= FETCH_BYTE (pos
);
1250 /* Perhaps add some info to the width_run_cache. */
1251 if (current_buffer
->width_run_cache
)
1253 /* Is this character part of the current run? If so, extend
1255 if (pos
- 1 == width_run_end
1256 && XFASTINT (width_table
[c
]) == width_run_width
)
1257 width_run_end
= pos
;
1259 /* The previous run is over, since this is a character at a
1260 different position, or a different width. */
1263 /* Have we accumulated a run to put in the cache?
1264 (Currently, we only cache runs of width == 1). */
1265 if (width_run_start
< width_run_end
1266 && width_run_width
== 1)
1267 know_region_cache (current_buffer
,
1268 current_buffer
->width_run_cache
,
1269 width_run_start
, width_run_end
);
1271 /* Start recording a new width run. */
1272 width_run_width
= XFASTINT (width_table
[c
]);
1273 width_run_start
= pos
- 1;
1274 width_run_end
= pos
;
1278 if (dp
!= 0 && VECTORP (DISP_CHAR_VECTOR (dp
, c
))
1279 && ! (multibyte
&& BASE_LEADING_CODE_P (c
)))
1280 hpos
+= XVECTOR (DISP_CHAR_VECTOR (dp
, c
))->size
;
1281 else if (c
>= 040 && c
< 0177)
1285 int tem
= (hpos
+ tab_offset
+ hscroll
- (hscroll
> 0)) % tab_width
;
1288 hpos
+= tab_width
- tem
;
1292 if (selective
> 0 && indented_beyond_p (pos
, selective
))
1294 /* If (pos == to), we don't have to take care of
1295 selective display. */
1298 /* Skip any number of invisible lines all at once */
1300 pos
= find_before_next_newline (pos
, to
, 1) + 1;
1302 && indented_beyond_p (pos
, selective
));
1303 /* Allow for the " ..." that is displayed for them. */
1306 hpos
+= selective_rlen
;
1311 /* We have skipped the invis text, but not the
1317 /* A visible line. */
1321 /* Count the truncation glyph on column 0 */
1328 else if (c
== CR
&& selective
< 0)
1330 /* In selective display mode,
1331 everything from a ^M to the end of the line is invisible.
1332 Stop *before* the real newline. */
1334 pos
= find_before_next_newline (pos
, to
, 1);
1335 /* If we just skipped next_boundary,
1336 loop around in the main while
1338 if (pos
> next_boundary
)
1339 next_boundary
= pos
;
1340 /* Allow for the " ..." that is displayed for them. */
1343 hpos
+= selective_rlen
;
1348 else if (multibyte
&& BASE_LEADING_CODE_P (c
))
1350 /* Start of multi-byte form. */
1352 int len
, actual_len
;
1354 pos
--; /* rewind POS */
1356 ptr
= (((pos
) >= GPT
? GAP_SIZE
: 0) + (pos
) + BEG_ADDR
- 1);
1357 len
= ((pos
) >= GPT
? ZV
: GPT
) - (pos
);
1359 c
= STRING_CHAR_AND_LENGTH (ptr
, len
, actual_len
);
1361 if (dp
!= 0 && VECTORP (DISP_CHAR_VECTOR (dp
, c
)))
1362 hpos
+= XVECTOR (DISP_CHAR_VECTOR (dp
, c
))->size
;
1363 else if (actual_len
== 1)
1365 else if (COMPOSITE_CHAR_P (c
))
1367 int id
= COMPOSITE_CHAR_ID (c
);
1368 int width
= (id
< n_cmpchars
) ? cmpchar_table
[id
]->width
: 0;
1375 int width
= WIDTH_BY_CHAR_HEAD (*ptr
);
1384 hpos
+= (ctl_arrow
&& c
< 0200) ? 2 : 4;
1390 /* Remember any final width run in the cache. */
1391 if (current_buffer
->width_run_cache
1392 && width_run_width
== 1
1393 && width_run_start
< width_run_end
)
1394 know_region_cache (current_buffer
, current_buffer
->width_run_cache
,
1395 width_run_start
, width_run_end
);
1397 val_compute_motion
.bufpos
= pos
;
1398 val_compute_motion
.hpos
= hpos
;
1399 val_compute_motion
.vpos
= vpos
;
1400 val_compute_motion
.prevhpos
= prev_hpos
;
1401 /* We alalways handle all of them here; none of them remain to do. */
1402 val_compute_motion
.ovstring_chars_done
= 0;
1404 /* Nonzero if have just continued a line */
1405 val_compute_motion
.contin
= (contin_hpos
&& prev_hpos
== 0);
1407 return &val_compute_motion
;
1410 #if 0 /* The doc string is too long for some compilers,
1411 but make-docfile can find it in this comment. */
1412 DEFUN ("compute-motion", Ffoo
, Sfoo
, 7, 7, 0,
1413 "Scan through the current buffer, calculating screen position.\n\
1414 Scan the current buffer forward from offset FROM,\n\
1415 assuming it is at position FROMPOS--a cons of the form (HPOS . VPOS)--\n\
1416 to position TO or position TOPOS--another cons of the form (HPOS . VPOS)--\n\
1417 and return the ending buffer position and screen location.\n\
1419 There are three additional arguments:\n\
1421 WIDTH is the number of columns available to display text;\n\
1422 this affects handling of continuation lines.\n\
1423 This is usually the value returned by `window-width', less one (to allow\n\
1424 for the continuation glyph).\n\
1426 OFFSETS is either nil or a cons cell (HSCROLL . TAB-OFFSET).\n\
1427 HSCROLL is the number of columns not being displayed at the left\n\
1428 margin; this is usually taken from a window's hscroll member.\n\
1429 TAB-OFFSET is the number of columns of the first tab that aren't\n\
1430 being displayed, perhaps because the line was continued within it.\n\
1431 If OFFSETS is nil, HSCROLL and TAB-OFFSET are assumed to be zero.\n\
1433 WINDOW is the window to operate on. It is used to choose the display table;\n\
1434 if it is showing the current buffer, it is used also for\n\
1435 deciding which overlay properties apply.\n\
1436 Note that `compute-motion' always operates on the current buffer.\n\
1438 The value is a list of five elements:\n\
1439 (POS HPOS VPOS PREVHPOS CONTIN)\n\
1440 POS is the buffer position where the scan stopped.\n\
1441 VPOS is the vertical position where the scan stopped.\n\
1442 HPOS is the horizontal position where the scan stopped.\n\
1444 PREVHPOS is the horizontal position one character back from POS.\n\
1445 CONTIN is t if a line was continued after (or within) the previous character.\n\
1447 For example, to find the buffer position of column COL of line LINE\n\
1448 of a certain window, pass the window's starting location as FROM\n\
1449 and the window's upper-left coordinates as FROMPOS.\n\
1450 Pass the buffer's (point-max) as TO, to limit the scan to the end of the\n\
1451 visible section of the buffer, and pass LINE and COL as TOPOS.")
1452 (from
, frompos
, to
, topos
, width
, offsets
, window
)
1455 DEFUN ("compute-motion", Fcompute_motion
, Scompute_motion
, 7, 7, 0,
1457 (from
, frompos
, to
, topos
, width
, offsets
, window
)
1458 Lisp_Object from
, frompos
, to
, topos
;
1459 Lisp_Object width
, offsets
, window
;
1461 Lisp_Object bufpos
, hpos
, vpos
, prevhpos
, contin
;
1462 struct position
*pos
;
1463 int hscroll
, tab_offset
;
1465 CHECK_NUMBER_COERCE_MARKER (from
, 0);
1466 CHECK_CONS (frompos
, 0);
1467 CHECK_NUMBER (XCONS (frompos
)->car
, 0);
1468 CHECK_NUMBER (XCONS (frompos
)->cdr
, 0);
1469 CHECK_NUMBER_COERCE_MARKER (to
, 0);
1470 CHECK_CONS (topos
, 0);
1471 CHECK_NUMBER (XCONS (topos
)->car
, 0);
1472 CHECK_NUMBER (XCONS (topos
)->cdr
, 0);
1473 CHECK_NUMBER (width
, 0);
1474 if (!NILP (offsets
))
1476 CHECK_CONS (offsets
, 0);
1477 CHECK_NUMBER (XCONS (offsets
)->car
, 0);
1478 CHECK_NUMBER (XCONS (offsets
)->cdr
, 0);
1479 hscroll
= XINT (XCONS (offsets
)->car
);
1480 tab_offset
= XINT (XCONS (offsets
)->cdr
);
1483 hscroll
= tab_offset
= 0;
1486 window
= Fselected_window ();
1488 CHECK_LIVE_WINDOW (window
, 0);
1490 pos
= compute_motion (XINT (from
), XINT (XCONS (frompos
)->cdr
),
1491 XINT (XCONS (frompos
)->car
), 0,
1492 XINT (to
), XINT (XCONS (topos
)->cdr
),
1493 XINT (XCONS (topos
)->car
),
1494 XINT (width
), hscroll
, tab_offset
,
1497 XSETFASTINT (bufpos
, pos
->bufpos
);
1498 XSETINT (hpos
, pos
->hpos
);
1499 XSETINT (vpos
, pos
->vpos
);
1500 XSETINT (prevhpos
, pos
->prevhpos
);
1502 return Fcons (bufpos
,
1506 Fcons (pos
->contin
? Qt
: Qnil
, Qnil
)))));
1510 /* Return the column of position POS in window W's buffer.
1511 The result is rounded down to a multiple of the internal width of W.
1512 This is the amount of indentation of position POS
1513 that is not visible in its horizontal position in the window. */
1516 pos_tab_offset (w
, pos
)
1522 int width
= window_internal_width (w
) - 1;
1525 return MINI_WINDOW_P (w
) ? -minibuf_prompt_width
: 0;
1526 if (FETCH_BYTE (pos
- 1) == '\n')
1529 col
= current_column ();
1530 TEMP_SET_PT (opoint
);
1531 /* Modulo is no longer valid, as a line may get shorter than WIDTH
1532 columns by continuation of a wide-column character. Just return
1535 /* In the continuation of the first line in a minibuffer we must
1536 take the width of the prompt into account. */
1537 if (MINI_WINDOW_P (w
) && col
>= width
- minibuf_prompt_width
1538 && find_next_newline_no_quit (pos
, -1) == BEGV
)
1539 return col
- (col
+ minibuf_prompt_width
) % width
;
1540 return col
- (col
% width
);
1546 /* Fvertical_motion and vmotion */
1547 struct position val_vmotion
;
1550 vmotion (from
, vtarget
, w
)
1551 register int from
, vtarget
;
1554 int width
= window_internal_width (w
) - 1;
1555 int hscroll
= XINT (w
->hscroll
);
1556 struct position pos
;
1557 /* vpos is cumulative vertical position, changed as from is changed */
1558 register int vpos
= 0;
1559 Lisp_Object prevline
;
1561 int lmargin
= hscroll
> 0 ? 1 - hscroll
: 0;
1563 = (INTEGERP (current_buffer
->selective_display
)
1564 ? XINT (current_buffer
->selective_display
)
1565 : !NILP (current_buffer
->selective_display
) ? -1 : 0);
1570 XSETWINDOW (window
, w
);
1572 /* The omission of the clause
1573 && marker_position (w->start) == BEG
1574 here is deliberate; I think we want to measure from the prompt
1575 position even if the minibuffer window has scrolled. */
1576 if (EQ (window
, minibuf_window
))
1578 if (minibuf_prompt_width
== 0 && STRINGP (minibuf_prompt
))
1579 minibuf_prompt_width
1580 = string_display_width (minibuf_prompt
, Qnil
, Qnil
);
1582 start_hpos
= minibuf_prompt_width
;
1585 if (vpos
>= vtarget
)
1587 /* To move upward, go a line at a time until
1588 we have gone at least far enough */
1592 while ((vpos
> vtarget
|| first
) && from
> BEGV
)
1594 Lisp_Object propval
;
1596 XSETFASTINT (prevline
, find_next_newline_no_quit (from
- 1, -1));
1597 while (XFASTINT (prevline
) > BEGV
1599 && indented_beyond_p (XFASTINT (prevline
), selective
))
1600 #ifdef USE_TEXT_PROPERTIES
1601 /* watch out for newlines with `invisible' property */
1602 || (propval
= Fget_char_property (prevline
,
1605 TEXT_PROP_MEANS_INVISIBLE (propval
))
1608 XSETFASTINT (prevline
,
1609 find_next_newline_no_quit (XFASTINT (prevline
) - 1,
1611 pos
= *compute_motion (XFASTINT (prevline
), 0,
1612 lmargin
+ (XFASTINT (prevline
) == BEG
1616 /* Don't care for VPOS... */
1617 1 << (BITS_PER_SHORT
- 1),
1619 1 << (BITS_PER_SHORT
- 1),
1621 /* This compensates for start_hpos
1622 so that a tab as first character
1623 still occupies 8 columns. */
1624 (XFASTINT (prevline
) == BEG
1629 from
= XFASTINT (prevline
);
1632 /* If we made exactly the desired vertical distance,
1633 or if we hit beginning of buffer,
1634 return point found */
1635 if (vpos
>= vtarget
)
1637 val_vmotion
.bufpos
= from
;
1638 val_vmotion
.vpos
= vpos
;
1639 val_vmotion
.hpos
= lmargin
;
1640 val_vmotion
.contin
= 0;
1641 val_vmotion
.prevhpos
= 0;
1642 val_vmotion
.ovstring_chars_done
= 0;
1643 val_vmotion
.tab_offset
= 0; /* For accumulating tab offset. */
1644 return &val_vmotion
;
1647 /* Otherwise find the correct spot by moving down */
1649 /* Moving downward is simple, but must calculate from beg of line
1650 to determine hpos of starting point */
1651 if (from
> BEGV
&& FETCH_BYTE (from
- 1) != '\n')
1653 Lisp_Object propval
;
1655 XSETFASTINT (prevline
, find_next_newline_no_quit (from
, -1));
1656 while (XFASTINT (prevline
) > BEGV
1658 && indented_beyond_p (XFASTINT (prevline
), selective
))
1659 #ifdef USE_TEXT_PROPERTIES
1660 /* watch out for newlines with `invisible' property */
1661 || (propval
= Fget_char_property (prevline
, Qinvisible
,
1663 TEXT_PROP_MEANS_INVISIBLE (propval
))
1666 XSETFASTINT (prevline
,
1667 find_next_newline_no_quit (XFASTINT (prevline
) - 1,
1669 pos
= *compute_motion (XFASTINT (prevline
), 0,
1670 lmargin
+ (XFASTINT (prevline
) == BEG
1674 /* Don't care for VPOS... */
1675 1 << (BITS_PER_SHORT
- 1),
1677 1 << (BITS_PER_SHORT
- 1),
1679 (XFASTINT (prevline
) == BEG
? -start_hpos
: 0),
1685 pos
.hpos
= lmargin
+ (from
== BEG
? start_hpos
: 0);
1690 return compute_motion (from
, vpos
, pos
.hpos
, did_motion
,
1691 ZV
, vtarget
, - (1 << (BITS_PER_SHORT
- 1)),
1693 pos
.tab_offset
- (from
== BEG
? start_hpos
: 0),
1697 DEFUN ("vertical-motion", Fvertical_motion
, Svertical_motion
, 1, 2, 0,
1698 "Move point to start of the screen line LINES lines down.\n\
1699 If LINES is negative, this means moving up.\n\
1701 This function is an ordinary cursor motion function\n\
1702 which calculates the new position based on how text would be displayed.\n\
1703 The new position may be the start of a line,\n\
1704 or just the start of a continuation line.\n\
1705 The function returns number of screen lines moved over;\n\
1706 that usually equals LINES, but may be closer to zero\n\
1707 if beginning or end of buffer was reached.\n\
1709 The optional second argument WINDOW specifies the window to use for\n\
1710 parameters such as width, horizontal scrolling, and so on.\n\
1711 The default is to use the selected window's parameters.\n\
1713 `vertical-motion' always uses the current buffer,\n\
1714 regardless of which buffer is displayed in WINDOW.\n\
1715 This is consistent with other cursor motion functions\n\
1716 and makes it possible to use `vertical-motion' in any buffer,\n\
1717 whether or not it is currently displayed in some window.")
1719 Lisp_Object lines
, window
;
1721 struct position pos
;
1723 CHECK_NUMBER (lines
, 0);
1724 if (! NILP (window
))
1725 CHECK_WINDOW (window
, 0);
1727 window
= selected_window
;
1729 pos
= *vmotion (PT
, (int) XINT (lines
), XWINDOW (window
));
1731 SET_PT (pos
.bufpos
);
1732 return make_number (pos
.vpos
);
1735 /* file's initialization. */
1739 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode
,
1740 "*Indentation can insert tabs if this is non-nil.\n\
1741 Setting this variable automatically makes it local to the current buffer.");
1742 indent_tabs_mode
= 1;
1744 defsubr (&Scurrent_indentation
);
1745 defsubr (&Sindent_to
);
1746 defsubr (&Scurrent_column
);
1747 defsubr (&Smove_to_column
);
1748 defsubr (&Svertical_motion
);
1749 defsubr (&Scompute_motion
);