(x_get_customization_string): Don't use value of strcpy.
[bpt/emacs.git] / src / indent.c
CommitLineData
993b6404 1/* Indentation functions.
c6c5df7f 2 Copyright (C) 1985, 1986, 1987, 1988, 1993 Free Software Foundation, Inc.
993b6404
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the 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"
502b9b64 25#include "frame.h"
993b6404
JB
26#include "window.h"
27#include "termchar.h"
28#include "termopts.h"
29#include "disptab.h"
5a05d3d2 30#include "intervals.h"
993b6404
JB
31
32/* Indentation can insert tabs if this is non-zero;
33 otherwise always uses spaces */
34int 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 */
45int last_known_column;
46/* Value of point when current_column was called */
47int last_known_column_point;
48/* Value of MODIFF when current_column was called */
49int last_known_column_modified;
50
993b6404
JB
51/* Get the display table to use for the current buffer. */
52
53struct Lisp_Vector *
54buffer_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
68DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
69 "Return the horizontal position of point. Beginning of line is column 0.\n\
70This is calculated by adding together the widths of all the displayed\n\
71representations of the character between the start of the previous line\n\
72and point. (eg control characters will have a width of 2 or 4, tabs\n\
73will have a variable width)\n\
502b9b64
JB
74Ignores finite width of frame, which means that this function may return\n\
75values greater than (frame-width).\n\
993b6404
JB
76Whether the line is visible (if `selective-display' is t) has no effect;\n\
77however, ^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
e74928fc
JB
85/* Cancel any recorded value of the horizontal position. */
86
87invalidate_current_column ()
88{
89 last_known_column_point = 0;
90}
91
993b6404
JB
92int
93current_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);
56a98455 101 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
993b6404
JB
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
ccdcf1f5 120 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
993b6404
JB
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
dea4d2e6 141 && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
993b6404
JB
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 }
dea4d2e6
RS
158 else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
159 col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
993b6404
JB
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
178DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
179 "Indent from point with tabs and spaces until COLUMN is reached.\n\
180Optional second argument MIN says always do at least MIN spaces\n\
181even 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);
56a98455 190 if (NILP (minimum))
993b6404
JB
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
ccdcf1f5 201 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
993b6404
JB
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
226DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
227 0, 0, 0,
228 "Return the indentation of the current line.\n\
229This is the horizontal position of the character\n\
230following 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
239position_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
ccdcf1f5 247 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
993b6404
JB
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
275DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, 0,
276 "Move point to column COLUMN in the current line.\n\
277The column of a character is calculated by adding together the widths\n\
278as displayed of the previous characters in the line.\n\
279This function ignores line-continuation;\n\
280there is no upper limit on the column number a character can have\n\
230a4cbd
JB
281and horizontal scrolling has no effect.\n\
282\n\
993b6404
JB
283If specified column is within a character, point goes after that character.\n\
284If it's past end of line, point goes to end of line.\n\n\
285A non-nil second (optional) argument FORCE means, if the line\n\
286is too short to reach column COLUMN then add spaces/tabs to get there,\n\
287and 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);
56a98455 296 register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
993b6404
JB
297 register struct Lisp_Vector *dp = buffer_display_table ();
298
299 Lisp_Object val;
300 int prev_col;
301 int c;
302
ccdcf1f5 303 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
993b6404
JB
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 }
dea4d2e6
RS
333 else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
334 col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
993b6404
JB
335 else if (ctl_arrow && (c < 040 || c == 0177))
336 col++;
337 else if (c < 040 || c >= 0177)
338 col += 3;
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. */
56a98455 347 if (!NILP (force) && col > goal && c == '\t' && prev_col < goal)
993b6404 348 {
70ee42f7
JB
349 int old_point;
350
993b6404 351 del_range (point - 1, point);
70ee42f7
JB
352 Findent_to (make_number (goal), Qnil);
353 old_point = point;
354 Findent_to (make_number (col), Qnil);
355 SET_PT (old_point);
5a05d3d2
RS
356 /* Set the last_known... vars consistently. */
357 col = goal;
993b6404
JB
358 }
359
360 /* If line ends prematurely, add space to the end. */
56a98455 361 if (col < goal && !NILP (force))
230a4cbd 362 Findent_to (make_number (col = goal), Qnil);
993b6404
JB
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
372struct 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.
a9764248
JB
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.
993b6404
JB
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
a3c87d4e
JB
402 - (has_vertical_scroll_bars
403 ? VERTICAL_SCROLL_BAR_WIDTH
fa61c701 404 : (window_width + window_left != frame_width))
993b6404
JB
405
406 where
407 window_width is XFASTINT (w->width),
408 window_left is XFASTINT (w->left),
a3c87d4e
JB
409 has_vertical_scroll_bars is
410 FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (WINDOW_FRAME (window)))
fa61c701 411 and frame_width = FRAME_WIDTH (XFRAME (window->frame))
993b6404 412
fa61c701
JB
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
a3c87d4e 418 the scroll bars if the frame supports them. */
993b6404
JB
419
420struct position *
421compute_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{
cde9337b
JB
426 register int hpos = fromhpos;
427 register int vpos = fromvpos;
428
993b6404
JB
429 register int pos;
430 register int c;
431 register int tab_width = XFASTINT (current_buffer->tab_width);
56a98455 432 register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
993b6404
JB
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)
56a98455 437 : !NILP (current_buffer->selective_display) ? -1 : 0;
cde9337b 438 int prev_vpos, prev_hpos;
993b6404 439 int selective_rlen
dea4d2e6
RS
440 = (selective && dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector
441 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0);
5a05d3d2
RS
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
993b6404 447
ccdcf1f5 448 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
cde9337b 449 for (pos = from; pos < to; pos++)
993b6404 450 {
cde9337b
JB
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
5a05d3d2
RS
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;
470
471 end = Fnext_single_property_change (position,
472 Qinvisible,
473 Fcurrent_buffer ());
474 if (INTEGERP (end))
475 next_invisible = XINT (end);
476 else
477 next_invisible = to;
478 if (! NILP (prop))
479 pos = next_invisible;
480 }
481 }
482 if (pos >= to)
483 break;
484#endif
993b6404
JB
485 c = FETCH_CHAR (pos);
486 if (c >= 040 && c < 0177
dea4d2e6 487 && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
cde9337b 488 hpos++;
993b6404
JB
489 else if (c == '\t')
490 {
cde9337b
JB
491 hpos += tab_width - ((hpos + tab_offset + hscroll - (hscroll > 0)
492 /* Add tab_width here to make sure positive.
493 hpos can be negative after continuation
494 but can't be less than -tab_width. */
495 + tab_width)
496 % tab_width);
993b6404
JB
497 }
498 else if (c == '\n')
499 {
500 if (selective > 0 && position_indentation (pos + 1) >= selective)
501 {
502 /* Skip any number of invisible lines all at once */
503 do
504 {
cde9337b 505 while (++pos < to && FETCH_CHAR (pos) != '\n');
993b6404 506 }
e51eab7c 507 while (pos < to && position_indentation (pos + 1) >= selective);
993b6404
JB
508 pos--;
509 /* Allow for the " ..." that is displayed for them. */
510 if (selective_rlen)
511 {
cde9337b
JB
512 hpos += selective_rlen;
513 if (hpos >= width)
514 hpos = width;
993b6404 515 }
e51eab7c 516 /* We have skipped the invis text, but not the newline after. */
993b6404
JB
517 }
518 else
cde9337b
JB
519 {
520 /* A visible line. */
521 vpos++;
522 hpos = 0;
46947372
JB
523 hpos -= hscroll;
524 if (hscroll > 0) hpos++; /* Count the ! on column 0 */
525 tab_offset = 0;
526 }
993b6404
JB
527 }
528 else if (c == CR && selective < 0)
529 {
530 /* In selective display mode,
531 everything from a ^M to the end of the line is invisible */
cde9337b
JB
532 while (pos < to && FETCH_CHAR (pos) != '\n') pos++;
533 /* Stop *before* the real newline. */
993b6404
JB
534 pos--;
535 /* Allow for the " ..." that is displayed for them. */
536 if (selective_rlen)
537 {
cde9337b
JB
538 hpos += selective_rlen;
539 if (hpos >= width)
540 hpos = width;
993b6404
JB
541 }
542 }
dea4d2e6
RS
543 else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
544 hpos += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
993b6404 545 else
cde9337b 546 hpos += (ctl_arrow && c < 0200) ? 2 : 4;
993b6404 547
cde9337b
JB
548 /* Handle right margin. */
549 if (hpos >= width
550 && (hpos > width
551 || (pos < ZV - 1
993b6404
JB
552 && FETCH_CHAR (pos + 1) != '\n')))
553 {
cde9337b
JB
554 if (vpos > tovpos
555 || (vpos == tovpos && hpos >= tohpos))
993b6404
JB
556 break;
557 if (hscroll
558 || (truncate_partial_width_windows
502b9b64 559 && width + 1 < FRAME_WIDTH (selected_frame))
56a98455 560 || !NILP (current_buffer->truncate_lines))
993b6404 561 {
cde9337b
JB
562 /* Truncating: skip to newline. */
563 while (pos < to && FETCH_CHAR (pos) != '\n') pos++;
993b6404 564 pos--;
e51eab7c 565 hpos = width;
993b6404
JB
566 }
567 else
568 {
cde9337b
JB
569 /* Continuing. */
570 vpos++;
571 hpos -= width;
993b6404
JB
572 tab_offset += width;
573 }
574
575 }
576 }
577
578 val_compute_motion.bufpos = pos;
cde9337b
JB
579 val_compute_motion.hpos = hpos;
580 val_compute_motion.vpos = vpos;
581 val_compute_motion.prevhpos = prev_hpos;
993b6404
JB
582
583 /* Nonzero if have just continued a line */
584 val_compute_motion.contin
cde9337b
JB
585 = (pos != from
586 && (val_compute_motion.vpos != prev_vpos)
587 && c != '\n');
993b6404
JB
588
589 return &val_compute_motion;
590}
993b6404
JB
591
592\f
593/* Return the column of position POS in window W's buffer,
594 rounded down to a multiple of the internal width of W.
595 This is the amount of indentation of position POS
596 that is not visible in its horizontal position in the window. */
597
598int
599pos_tab_offset (w, pos)
600 struct window *w;
601 register int pos;
602{
603 int opoint = point;
604 int col;
fa61c701 605 int width = window_internal_width (w) - 1;
993b6404
JB
606
607 if (pos == BEGV || FETCH_CHAR (pos - 1) == '\n')
608 return 0;
609 SET_PT (pos);
610 col = current_column ();
611 SET_PT (opoint);
612 return col - (col % width);
613}
614
615/* start_hpos is the hpos of the first character of the buffer:
616 zero except for the minibuffer window,
617 where it is the width of the prompt. */
618
619struct position val_vmotion;
620
621struct position *
622vmotion (from, vtarget, width, hscroll, window)
623 register int from, vtarget, width;
624 int hscroll;
625 Lisp_Object window;
626{
627 struct position pos;
628 /* vpos is cumulative vertical position, changed as from is changed */
629 register int vpos = 0;
630 register int prevline;
631 register int first;
632 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
633 int selective
634 = XTYPE (current_buffer->selective_display) == Lisp_Int
635 ? XINT (current_buffer->selective_display)
56a98455 636 : !NILP (current_buffer->selective_display) ? -1 : 0;
993b6404
JB
637 int start_hpos = (EQ (window, minibuf_window) ? minibuf_prompt_width : 0);
638
639 retry:
640 if (vtarget > vpos)
641 {
642 /* Moving downward is simple, but must calculate from beg of line
643 to determine hpos of starting point */
644 if (from > BEGV && FETCH_CHAR (from - 1) != '\n')
645 {
646 prevline = find_next_newline (from, -1);
5a05d3d2
RS
647 while (prevline > BEGV
648 && ((selective > 0
649 && position_indentation (prevline) >= selective)
650#ifdef USE_TEXT_PROPERTIES
651 /* watch out for newlines with `invisible' property */
652 || ! NILP (Fget_text_property (XFASTINT (prevline),
653 Qinvisible,
654 Fcurrent_buffer ()))
655#endif
656 ))
993b6404
JB
657 prevline = find_next_newline (prevline - 1, -1);
658 pos = *compute_motion (prevline, 0,
659 lmargin + (prevline == 1 ? start_hpos : 0),
cde9337b 660 from, 1 << (INTBITS - 2), 0,
993b6404
JB
661 width, hscroll, 0);
662 }
663 else
664 {
665 pos.hpos = lmargin + (from == 1 ? start_hpos : 0);
666 pos.vpos = 0;
667 }
668 return compute_motion (from, vpos, pos.hpos,
cde9337b 669 ZV, vtarget, - (1 << (INTBITS - 2)),
993b6404
JB
670 width, hscroll, pos.vpos * width);
671 }
672
673 /* To move upward, go a line at a time until
674 we have gone at least far enough */
675
676 first = 1;
677
678 while ((vpos > vtarget || first) && from > BEGV)
679 {
680 prevline = from;
681 while (1)
682 {
683 prevline = find_next_newline (prevline - 1, -1);
684 if (prevline == BEGV
5a05d3d2
RS
685 || ((selective <= 0
686 || position_indentation (prevline) < selective)
687#ifdef USE_TEXT_PROPERTIES
688 /* watch out for newlines with `invisible' property */
689 && NILP (Fget_text_property (XFASTINT (prevline),
690 Qinvisible,
691 Fcurrent_buffer ()))
692#endif
693 ))
993b6404
JB
694 break;
695 }
696 pos = *compute_motion (prevline, 0,
697 lmargin + (prevline == 1 ? start_hpos : 0),
cde9337b 698 from, 1 << (INTBITS - 2), 0,
993b6404
JB
699 width, hscroll, 0);
700 vpos -= pos.vpos;
701 first = 0;
702 from = prevline;
703 }
704
705 /* If we made exactly the desired vertical distance,
706 or if we hit beginning of buffer,
707 return point found */
708 if (vpos >= vtarget)
709 {
710 val_vmotion.bufpos = from;
711 val_vmotion.vpos = vpos;
712 val_vmotion.hpos = lmargin;
713 val_vmotion.contin = 0;
714 val_vmotion.prevhpos = 0;
715 return &val_vmotion;
716 }
717
718 /* Otherwise find the correct spot by moving down */
719 goto retry;
720}
721
722DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 1, 0,
723 "Move to start of screen line LINES lines down.\n\
724If LINES is negative, this is moving up.\n\
725Sets point to position found; this may be start of line\n\
726 or just the start of a continuation line.\n\
727Returns number of lines moved; may be closer to zero than LINES\n\
728 if beginning or end of buffer was reached.")
729 (lines)
730 Lisp_Object lines;
731{
732 struct position pos;
733 register struct window *w = XWINDOW (selected_window);
fa61c701 734 int width = window_internal_width (w) - 1;
993b6404
JB
735
736 CHECK_NUMBER (lines, 0);
737
738 pos = *vmotion (point, XINT (lines), width,
739 /* Not XFASTINT since perhaps could be negative */
740 XINT (w->hscroll), selected_window);
741
742 SET_PT (pos.bufpos);
743 return make_number (pos.vpos);
744}
745\f
746syms_of_indent ()
747{
748 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
749 "*Indentation can insert tabs if this is non-nil.\n\
750Setting this variable automatically makes it local to the current buffer.");
751 indent_tabs_mode = 1;
752
753 defsubr (&Scurrent_indentation);
754 defsubr (&Sindent_to);
755 defsubr (&Scurrent_column);
756 defsubr (&Smove_to_column);
757 defsubr (&Svertical_motion);
758}