(Fmove_to_column): Increments for control characters
[bpt/emacs.git] / src / indent.c
1 /* Indentation functions.
2 Copyright (C) 1985, 1986, 1987, 1988, 1993 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21 #include <config.h>
22 #include "lisp.h"
23 #include "buffer.h"
24 #include "indent.h"
25 #include "frame.h"
26 #include "window.h"
27 #include "termchar.h"
28 #include "termopts.h"
29 #include "disptab.h"
30 #include "intervals.h"
31
32 /* Indentation can insert tabs if this is non-zero;
33 otherwise always uses spaces */
34 int indent_tabs_mode;
35
36 #define min(a, b) ((a) < (b) ? (a) : (b))
37 #define max(a, b) ((a) > (b) ? (a) : (b))
38
39 #define CR 015
40
41 /* These three values memoize the current column to avoid recalculation */
42 /* Some things in set last_known_column_point to -1
43 to mark the memoized value as invalid */
44 /* Last value returned by current_column */
45 int last_known_column;
46 /* Value of point when current_column was called */
47 int last_known_column_point;
48 /* Value of MODIFF when current_column was called */
49 int last_known_column_modified;
50
51 /* Get the display table to use for the current buffer. */
52
53 struct Lisp_Vector *
54 buffer_display_table ()
55 {
56 Lisp_Object thisbuf;
57
58 thisbuf = current_buffer->display_table;
59 if (XTYPE (thisbuf) == Lisp_Vector
60 && XVECTOR (thisbuf)->size == DISP_TABLE_SIZE)
61 return XVECTOR (thisbuf);
62 if (XTYPE (Vstandard_display_table) == Lisp_Vector
63 && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
64 return XVECTOR (Vstandard_display_table);
65 return 0;
66 }
67 \f
68 DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
69 "Return the horizontal position of point. Beginning of line is column 0.\n\
70 This is calculated by adding together the widths of all the displayed\n\
71 representations of the character between the start of the previous line\n\
72 and point. (eg control characters will have a width of 2 or 4, tabs\n\
73 will have a variable width)\n\
74 Ignores finite width of frame, which means that this function may return\n\
75 values greater than (frame-width).\n\
76 Whether the line is visible (if `selective-display' is t) has no effect;\n\
77 however, ^M is treated as end of line when `selective-display' is t.")
78 ()
79 {
80 Lisp_Object temp;
81 XFASTINT (temp) = current_column ();
82 return temp;
83 }
84
85 /* Cancel any recorded value of the horizontal position. */
86
87 invalidate_current_column ()
88 {
89 last_known_column_point = 0;
90 }
91
92 int
93 current_column ()
94 {
95 register int col;
96 register unsigned char *ptr, *stop;
97 register int tab_seen;
98 int post_tab;
99 register int c;
100 register int tab_width = XINT (current_buffer->tab_width);
101 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
102 register struct Lisp_Vector *dp = buffer_display_table ();
103 int stopchar;
104
105 if (point == last_known_column_point
106 && MODIFF == last_known_column_modified)
107 return last_known_column;
108
109 /* Make a pointer for decrementing through the chars before point. */
110 ptr = &FETCH_CHAR (point - 1) + 1;
111 /* Make a pointer to where consecutive chars leave off,
112 going backwards from point. */
113 if (point == BEGV)
114 stop = ptr;
115 else if (point <= GPT || BEGV > GPT)
116 stop = BEGV_ADDR;
117 else
118 stop = GAP_END_ADDR;
119
120 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
121
122 col = 0, tab_seen = 0, post_tab = 0;
123
124 while (1)
125 {
126 if (ptr == stop)
127 {
128 /* We stopped either for the beginning of the buffer
129 or for the gap. */
130 if (ptr == BEGV_ADDR)
131 break;
132 /* It was the gap. Jump back over it. */
133 stop = BEGV_ADDR;
134 ptr = GPT_ADDR;
135 /* Check whether that brings us to beginning of buffer. */
136 if (BEGV >= GPT) break;
137 }
138
139 c = *--ptr;
140 if (c >= 040 && c < 0177
141 && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
142 {
143 col++;
144 }
145 else if (c == '\n')
146 break;
147 else if (c == '\r' && EQ (current_buffer->selective_display, Qt))
148 break;
149 else if (c == '\t')
150 {
151 if (tab_seen)
152 col = ((col + tab_width) / tab_width) * tab_width;
153
154 post_tab += col;
155 col = 0;
156 tab_seen = 1;
157 }
158 else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
159 col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
160 else
161 col += (ctl_arrow && c < 0200) ? 2 : 4;
162 }
163
164 if (tab_seen)
165 {
166 col = ((col + tab_width) / tab_width) * tab_width;
167 col += post_tab;
168 }
169
170 last_known_column = col;
171 last_known_column_point = point;
172 last_known_column_modified = MODIFF;
173
174 return col;
175 }
176 \f
177
178 DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
179 "Indent from point with tabs and spaces until COLUMN is reached.\n\
180 Optional second argument MIN says always do at least MIN spaces\n\
181 even if that goes past COLUMN; by default, MIN is zero.")
182 (col, minimum)
183 Lisp_Object col, minimum;
184 {
185 int mincol;
186 register int fromcol;
187 register int tab_width = XINT (current_buffer->tab_width);
188
189 CHECK_NUMBER (col, 0);
190 if (NILP (minimum))
191 XFASTINT (minimum) = 0;
192 CHECK_NUMBER (minimum, 1);
193
194 fromcol = current_column ();
195 mincol = fromcol + XINT (minimum);
196 if (mincol < XINT (col)) mincol = XINT (col);
197
198 if (fromcol == mincol)
199 return make_number (mincol);
200
201 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
202
203 if (indent_tabs_mode)
204 {
205 Lisp_Object n;
206 XFASTINT (n) = mincol / tab_width - fromcol / tab_width;
207 if (XFASTINT (n) != 0)
208 {
209 Finsert_char (make_number ('\t'), n);
210
211 fromcol = (mincol / tab_width) * tab_width;
212 }
213 }
214
215 XFASTINT (col) = mincol - fromcol;
216 Finsert_char (make_number (' '), col);
217
218 last_known_column = mincol;
219 last_known_column_point = point;
220 last_known_column_modified = MODIFF;
221
222 XSETINT (col, mincol);
223 return col;
224 }
225 \f
226 DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
227 0, 0, 0,
228 "Return the indentation of the current line.\n\
229 This is the horizontal position of the character\n\
230 following any initial whitespace.")
231 ()
232 {
233 Lisp_Object val;
234
235 XFASTINT (val) = position_indentation (find_next_newline (point, -1));
236 return val;
237 }
238
239 position_indentation (pos)
240 register int pos;
241 {
242 register int column = 0;
243 register int tab_width = XINT (current_buffer->tab_width);
244 register unsigned char *p;
245 register unsigned char *stop;
246
247 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
248
249 stop = &FETCH_CHAR (BUFFER_CEILING_OF (pos)) + 1;
250 p = &FETCH_CHAR (pos);
251 while (1)
252 {
253 while (p == stop)
254 {
255 if (pos == ZV)
256 return column;
257 pos += p - &FETCH_CHAR (pos);
258 p = &FETCH_CHAR (pos);
259 stop = &FETCH_CHAR (BUFFER_CEILING_OF (pos)) + 1;
260 }
261 switch (*p++)
262 {
263 case ' ':
264 column++;
265 break;
266 case '\t':
267 column += tab_width - column % tab_width;
268 break;
269 default:
270 return column;
271 }
272 }
273 }
274 \f
275 DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, 0,
276 "Move point to column COLUMN in the current line.\n\
277 The column of a character is calculated by adding together the widths\n\
278 as displayed of the previous characters in the line.\n\
279 This function ignores line-continuation;\n\
280 there is no upper limit on the column number a character can have\n\
281 and horizontal scrolling has no effect.\n\
282 \n\
283 If specified column is within a character, point goes after that character.\n\
284 If it's past end of line, point goes to end of line.\n\n\
285 A non-nil second (optional) argument FORCE means, if the line\n\
286 is too short to reach column COLUMN then add spaces/tabs to get there,\n\
287 and if COLUMN is in the middle of a tab character, change it to spaces.")
288 (column, force)
289 Lisp_Object column, force;
290 {
291 register int pos;
292 register int col = current_column ();
293 register int goal;
294 register int end;
295 register int tab_width = XINT (current_buffer->tab_width);
296 register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
297 register struct Lisp_Vector *dp = buffer_display_table ();
298
299 Lisp_Object val;
300 int prev_col;
301 int c;
302
303 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
304 CHECK_NATNUM (column, 0);
305 goal = XINT (column);
306
307 retry:
308 pos = point;
309 end = ZV;
310
311 /* If we're starting past the desired column,
312 back up to beginning of line and scan from there. */
313 if (col > goal)
314 {
315 pos = find_next_newline (pos, -1);
316 col = 0;
317 }
318
319 while (col < goal && pos < end)
320 {
321 c = FETCH_CHAR (pos);
322 if (c == '\n')
323 break;
324 if (c == '\r' && EQ (current_buffer->selective_display, Qt))
325 break;
326 pos++;
327 if (c == '\t')
328 {
329 prev_col = col;
330 col += tab_width;
331 col = col / tab_width * tab_width;
332 }
333 else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
334 col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
335 else if (ctl_arrow && (c < 040 || c == 0177))
336 col += 2;
337 else if (c < 040 || c >= 0177)
338 col += 4;
339 else
340 col++;
341 }
342
343 SET_PT (pos);
344
345 /* If a tab char made us overshoot, change it to spaces
346 and scan through it again. */
347 if (!NILP (force) && col > goal && c == '\t' && prev_col < goal)
348 {
349 int old_point;
350
351 del_range (point - 1, point);
352 Findent_to (make_number (goal), Qnil);
353 old_point = point;
354 Findent_to (make_number (col), Qnil);
355 SET_PT (old_point);
356 /* Set the last_known... vars consistently. */
357 col = goal;
358 }
359
360 /* If line ends prematurely, add space to the end. */
361 if (col < goal && !NILP (force))
362 Findent_to (make_number (col = goal), Qnil);
363
364 last_known_column = col;
365 last_known_column_point = point;
366 last_known_column_modified = MODIFF;
367
368 XFASTINT (val) = col;
369 return val;
370 }
371 \f
372 struct position val_compute_motion;
373
374 /* Scan the current buffer forward from offset FROM, pretending that
375 this is at line FROMVPOS, column FROMHPOS, until reaching buffer
376 offset TO or line TOVPOS, column TOHPOS (whichever comes first),
377 and return the ending buffer position and screen location.
378
379 WIDTH is the number of columns available to display text;
380 compute_motion uses this to handle continuation lines and such.
381 HSCROLL is the number of columns not being displayed at the left
382 margin; this is usually taken from a window's hscroll member.
383 TAB_OFFSET is the number of columns of the first tab that aren't
384 being displayed, perhaps because of a continuation line or
385 something.
386
387 compute_motion returns a pointer to a struct position. The bufpos
388 member gives the buffer position at the end of the scan, and hpos
389 and vpos give its cartesian location. I'm not clear on what the
390 other members are.
391
392 For example, to find the buffer position of column COL of line LINE
393 of a certain window, pass the window's starting location as FROM
394 and the window's upper-left coordinates as FROMVPOS and FROMHPOS.
395 Pass the buffer's ZV as TO, to limit the scan to the end of the
396 visible section of the buffer, and pass LINE and COL as TOVPOS and
397 TOHPOS.
398
399 When displaying in window w, a typical formula for WIDTH is:
400
401 window_width - 1
402 - (has_vertical_scroll_bars
403 ? VERTICAL_SCROLL_BAR_WIDTH
404 : (window_width + window_left != frame_width))
405
406 where
407 window_width is XFASTINT (w->width),
408 window_left is XFASTINT (w->left),
409 has_vertical_scroll_bars is
410 FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (WINDOW_FRAME (window)))
411 and frame_width = FRAME_WIDTH (XFRAME (window->frame))
412
413 Or,
414 window_internal_width (w) - 1
415
416 The `-1' accounts for the continuation-line backslashes; the rest
417 accounts for window borders if the window is split vertically, and
418 the scroll bars if the frame supports them. */
419
420 struct position *
421 compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, tab_offset)
422 int from, fromvpos, fromhpos, to, tovpos, tohpos;
423 register int width;
424 int hscroll, tab_offset;
425 {
426 register int hpos = fromhpos;
427 register int vpos = fromvpos;
428
429 register int pos;
430 register int c;
431 register int tab_width = XFASTINT (current_buffer->tab_width);
432 register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
433 register struct Lisp_Vector *dp = buffer_display_table ();
434 int selective
435 = XTYPE (current_buffer->selective_display) == Lisp_Int
436 ? XINT (current_buffer->selective_display)
437 : !NILP (current_buffer->selective_display) ? -1 : 0;
438 int prev_vpos, prev_hpos;
439 int selective_rlen
440 = (selective && dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector
441 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0);
442 #ifdef USE_TEXT_PROPERTIES
443 /* The next location where the `invisible' property changes */
444 int next_invisible = from;
445 Lisp_Object prop, position;
446 #endif
447
448 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
449 for (pos = from; pos < to; pos++)
450 {
451 /* Stop if past the target screen position. */
452 if (vpos > tovpos
453 || (vpos == tovpos && hpos >= tohpos))
454 break;
455
456 prev_vpos = vpos;
457 prev_hpos = hpos;
458
459 #ifdef USE_TEXT_PROPERTIES
460 /* if the `invisible' property is set, we can skip to
461 the next property change */
462 while (pos == next_invisible && pos < to)
463 {
464 XFASTINT (position) = pos;
465 prop = Fget_text_property (position,
466 Qinvisible,
467 Fcurrent_buffer ());
468 {
469 Lisp_Object end, limit;
470
471 /* This is just an estimate to give reasonable
472 performance; nothing should go wrong if it is too small. */
473 XFASTINT (limit) = pos + 100;
474 end = Fnext_single_property_change (position, Qinvisible,
475 Fcurrent_buffer (), limit);
476 if (INTEGERP (end))
477 next_invisible = XINT (end);
478 else
479 next_invisible = to;
480 if (! NILP (prop))
481 pos = next_invisible;
482 }
483 }
484 if (pos >= to)
485 break;
486 #endif
487 c = FETCH_CHAR (pos);
488 if (c >= 040 && c < 0177
489 && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
490 hpos++;
491 else if (c == '\t')
492 {
493 hpos += tab_width - ((hpos + tab_offset + hscroll - (hscroll > 0)
494 /* Add tab_width here to make sure positive.
495 hpos can be negative after continuation
496 but can't be less than -tab_width. */
497 + tab_width)
498 % tab_width);
499 }
500 else if (c == '\n')
501 {
502 if (selective > 0 && position_indentation (pos + 1) >= selective)
503 {
504 /* Skip any number of invisible lines all at once */
505 do
506 {
507 while (++pos < to && FETCH_CHAR (pos) != '\n');
508 }
509 while (pos < to && position_indentation (pos + 1) >= selective);
510 pos--;
511 /* Allow for the " ..." that is displayed for them. */
512 if (selective_rlen)
513 {
514 hpos += selective_rlen;
515 if (hpos >= width)
516 hpos = width;
517 }
518 /* We have skipped the invis text, but not the newline after. */
519 }
520 else
521 {
522 /* A visible line. */
523 vpos++;
524 hpos = 0;
525 hpos -= hscroll;
526 if (hscroll > 0) hpos++; /* Count the ! on column 0 */
527 tab_offset = 0;
528 }
529 }
530 else if (c == CR && selective < 0)
531 {
532 /* In selective display mode,
533 everything from a ^M to the end of the line is invisible */
534 while (pos < to && FETCH_CHAR (pos) != '\n') pos++;
535 /* Stop *before* the real newline. */
536 pos--;
537 /* Allow for the " ..." that is displayed for them. */
538 if (selective_rlen)
539 {
540 hpos += selective_rlen;
541 if (hpos >= width)
542 hpos = width;
543 }
544 }
545 else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
546 hpos += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
547 else
548 hpos += (ctl_arrow && c < 0200) ? 2 : 4;
549
550 /* Handle right margin. */
551 if (hpos >= width
552 && (hpos > width
553 || (pos < ZV - 1
554 && FETCH_CHAR (pos + 1) != '\n')))
555 {
556 if (vpos > tovpos
557 || (vpos == tovpos && hpos >= tohpos))
558 break;
559 if (hscroll
560 || (truncate_partial_width_windows
561 && width + 1 < FRAME_WIDTH (selected_frame))
562 || !NILP (current_buffer->truncate_lines))
563 {
564 /* Truncating: skip to newline. */
565 while (pos < to && FETCH_CHAR (pos) != '\n') pos++;
566 pos--;
567 hpos = width;
568 }
569 else
570 {
571 /* Continuing. */
572 vpos++;
573 hpos -= width;
574 tab_offset += width;
575 }
576
577 }
578 }
579
580 val_compute_motion.bufpos = pos;
581 val_compute_motion.hpos = hpos;
582 val_compute_motion.vpos = vpos;
583 val_compute_motion.prevhpos = prev_hpos;
584
585 /* Nonzero if have just continued a line */
586 val_compute_motion.contin
587 = (pos != from
588 && (val_compute_motion.vpos != prev_vpos)
589 && c != '\n');
590
591 return &val_compute_motion;
592 }
593
594 \f
595 /* Return the column of position POS in window W's buffer,
596 rounded down to a multiple of the internal width of W.
597 This is the amount of indentation of position POS
598 that is not visible in its horizontal position in the window. */
599
600 int
601 pos_tab_offset (w, pos)
602 struct window *w;
603 register int pos;
604 {
605 int opoint = point;
606 int col;
607 int width = window_internal_width (w) - 1;
608
609 if (pos == BEGV || FETCH_CHAR (pos - 1) == '\n')
610 return 0;
611 SET_PT (pos);
612 col = current_column ();
613 SET_PT (opoint);
614 return col - (col % width);
615 }
616
617 /* start_hpos is the hpos of the first character of the buffer:
618 zero except for the minibuffer window,
619 where it is the width of the prompt. */
620
621 struct position val_vmotion;
622
623 struct position *
624 vmotion (from, vtarget, width, hscroll, window)
625 register int from, vtarget, width;
626 int hscroll;
627 Lisp_Object window;
628 {
629 struct position pos;
630 /* vpos is cumulative vertical position, changed as from is changed */
631 register int vpos = 0;
632 register int prevline;
633 register int first;
634 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
635 int selective
636 = XTYPE (current_buffer->selective_display) == Lisp_Int
637 ? XINT (current_buffer->selective_display)
638 : !NILP (current_buffer->selective_display) ? -1 : 0;
639 int start_hpos = (EQ (window, minibuf_window) ? minibuf_prompt_width : 0);
640
641 retry:
642 if (vtarget > vpos)
643 {
644 /* Moving downward is simple, but must calculate from beg of line
645 to determine hpos of starting point */
646 if (from > BEGV && FETCH_CHAR (from - 1) != '\n')
647 {
648 prevline = find_next_newline (from, -1);
649 while (prevline > BEGV
650 && ((selective > 0
651 && position_indentation (prevline) >= selective)
652 #ifdef USE_TEXT_PROPERTIES
653 /* watch out for newlines with `invisible' property */
654 || ! NILP (Fget_text_property (XFASTINT (prevline),
655 Qinvisible,
656 Fcurrent_buffer ()))
657 #endif
658 ))
659 prevline = find_next_newline (prevline - 1, -1);
660 pos = *compute_motion (prevline, 0,
661 lmargin + (prevline == 1 ? start_hpos : 0),
662 from, 1 << (INTBITS - 2), 0,
663 width, hscroll, 0);
664 }
665 else
666 {
667 pos.hpos = lmargin + (from == 1 ? start_hpos : 0);
668 pos.vpos = 0;
669 }
670 return compute_motion (from, vpos, pos.hpos,
671 ZV, vtarget, - (1 << (INTBITS - 2)),
672 width, hscroll, pos.vpos * width);
673 }
674
675 /* To move upward, go a line at a time until
676 we have gone at least far enough */
677
678 first = 1;
679
680 while ((vpos > vtarget || first) && from > BEGV)
681 {
682 prevline = from;
683 while (1)
684 {
685 prevline = find_next_newline (prevline - 1, -1);
686 if (prevline == BEGV
687 || ((selective <= 0
688 || position_indentation (prevline) < selective)
689 #ifdef USE_TEXT_PROPERTIES
690 /* watch out for newlines with `invisible' property */
691 && NILP (Fget_text_property (XFASTINT (prevline),
692 Qinvisible,
693 Fcurrent_buffer ()))
694 #endif
695 ))
696 break;
697 }
698 pos = *compute_motion (prevline, 0,
699 lmargin + (prevline == 1 ? start_hpos : 0),
700 from, 1 << (INTBITS - 2), 0,
701 width, hscroll, 0);
702 vpos -= pos.vpos;
703 first = 0;
704 from = prevline;
705 }
706
707 /* If we made exactly the desired vertical distance,
708 or if we hit beginning of buffer,
709 return point found */
710 if (vpos >= vtarget)
711 {
712 val_vmotion.bufpos = from;
713 val_vmotion.vpos = vpos;
714 val_vmotion.hpos = lmargin;
715 val_vmotion.contin = 0;
716 val_vmotion.prevhpos = 0;
717 return &val_vmotion;
718 }
719
720 /* Otherwise find the correct spot by moving down */
721 goto retry;
722 }
723
724 DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 1, 0,
725 "Move to start of screen line LINES lines down.\n\
726 If LINES is negative, this is moving up.\n\
727 Sets point to position found; this may be start of line\n\
728 or just the start of a continuation line.\n\
729 Returns number of lines moved; may be closer to zero than LINES\n\
730 if beginning or end of buffer was reached.")
731 (lines)
732 Lisp_Object lines;
733 {
734 struct position pos;
735 register struct window *w = XWINDOW (selected_window);
736 int width = window_internal_width (w) - 1;
737
738 CHECK_NUMBER (lines, 0);
739
740 pos = *vmotion (point, XINT (lines), width,
741 /* Not XFASTINT since perhaps could be negative */
742 XINT (w->hscroll), selected_window);
743
744 SET_PT (pos.bufpos);
745 return make_number (pos.vpos);
746 }
747 \f
748 syms_of_indent ()
749 {
750 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
751 "*Indentation can insert tabs if this is non-nil.\n\
752 Setting this variable automatically makes it local to the current buffer.");
753 indent_tabs_mode = 1;
754
755 defsubr (&Scurrent_indentation);
756 defsubr (&Sindent_to);
757 defsubr (&Scurrent_column);
758 defsubr (&Smove_to_column);
759 defsubr (&Svertical_motion);
760 }