1 /* Indentation functions.
2 Copyright (C) 1985, 1986, 1987, 1988, 1992 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
31 /* Indentation can insert tabs if this is non-zero;
32 otherwise always uses spaces */
35 #define min(a, b) ((a) < (b) ? (a) : (b))
36 #define max(a, b) ((a) > (b) ? (a) : (b))
40 /* These three values memoize the current column to avoid recalculation */
41 /* Some things in set last_known_column_point to -1
42 to mark the memoized value as invalid */
43 /* Last value returned by current_column */
44 int last_known_column
;
45 /* Value of point when current_column was called */
46 int last_known_column_point
;
47 /* Value of MODIFF when current_column was called */
48 int last_known_column_modified
;
50 /* Get the display table to use for the current buffer. */
53 buffer_display_table ()
57 thisbuf
= current_buffer
->display_table
;
58 if (XTYPE (thisbuf
) == Lisp_Vector
59 && XVECTOR (thisbuf
)->size
== DISP_TABLE_SIZE
)
60 return XVECTOR (thisbuf
);
61 if (XTYPE (Vstandard_display_table
) == Lisp_Vector
62 && XVECTOR (Vstandard_display_table
)->size
== DISP_TABLE_SIZE
)
63 return XVECTOR (Vstandard_display_table
);
67 DEFUN ("current-column", Fcurrent_column
, Scurrent_column
, 0, 0, 0,
68 "Return the horizontal position of point. Beginning of line is column 0.\n\
69 This is calculated by adding together the widths of all the displayed\n\
70 representations of the character between the start of the previous line\n\
71 and point. (eg control characters will have a width of 2 or 4, tabs\n\
72 will have a variable width)\n\
73 Ignores finite width of frame, which means that this function may return\n\
74 values greater than (frame-width).\n\
75 Whether the line is visible (if `selective-display' is t) has no effect;\n\
76 however, ^M is treated as end of line when `selective-display' is t.")
80 XFASTINT (temp
) = current_column ();
84 /* Cancel any recorded value of the horizontal position. */
86 invalidate_current_column ()
88 last_known_column_point
= 0;
95 register unsigned char *ptr
, *stop
;
96 register int tab_seen
;
99 register int tab_width
= XINT (current_buffer
->tab_width
);
100 int ctl_arrow
= !NILP (current_buffer
->ctl_arrow
);
101 register struct Lisp_Vector
*dp
= buffer_display_table ();
104 if (point
== last_known_column_point
105 && MODIFF
== last_known_column_modified
)
106 return last_known_column
;
108 /* Make a pointer for decrementing through the chars before point. */
109 ptr
= &FETCH_CHAR (point
- 1) + 1;
110 /* Make a pointer to where consecutive chars leave off,
111 going backwards from point. */
114 else if (point
<= GPT
|| BEGV
> GPT
)
119 if (tab_width
<= 0 || tab_width
> 20) tab_width
= 8;
121 col
= 0, tab_seen
= 0, post_tab
= 0;
127 /* We stopped either for the beginning of the buffer
129 if (ptr
== BEGV_ADDR
)
131 /* It was the gap. Jump back over it. */
134 /* Check whether that brings us to beginning of buffer. */
135 if (BEGV
>= GPT
) break;
139 if (c
>= 040 && c
< 0177
140 && (dp
== 0 || XTYPE (DISP_CHAR_ROPE (dp
, c
)) != Lisp_String
))
146 else if (c
== '\r' && EQ (current_buffer
->selective_display
, Qt
))
151 col
= ((col
+ tab_width
) / tab_width
) * tab_width
;
157 else if (dp
!= 0 && XTYPE (DISP_CHAR_ROPE (dp
, c
)) == Lisp_String
)
158 col
+= XSTRING (DISP_CHAR_ROPE (dp
, c
))->size
/ sizeof (GLYPH
);
160 col
+= (ctl_arrow
&& c
< 0200) ? 2 : 4;
165 col
= ((col
+ tab_width
) / tab_width
) * tab_width
;
169 last_known_column
= col
;
170 last_known_column_point
= point
;
171 last_known_column_modified
= MODIFF
;
177 DEFUN ("indent-to", Findent_to
, Sindent_to
, 1, 2, "NIndent to column: ",
178 "Indent from point with tabs and spaces until COLUMN is reached.\n\
179 Optional second argument MIN says always do at least MIN spaces\n\
180 even if that goes past COLUMN; by default, MIN is zero.")
182 Lisp_Object col
, minimum
;
185 register int fromcol
;
186 register int tab_width
= XINT (current_buffer
->tab_width
);
188 CHECK_NUMBER (col
, 0);
190 XFASTINT (minimum
) = 0;
191 CHECK_NUMBER (minimum
, 1);
193 fromcol
= current_column ();
194 mincol
= fromcol
+ XINT (minimum
);
195 if (mincol
< XINT (col
)) mincol
= XINT (col
);
197 if (fromcol
== mincol
)
198 return make_number (mincol
);
200 if (tab_width
<= 0 || tab_width
> 20) tab_width
= 8;
202 if (indent_tabs_mode
)
205 XFASTINT (n
) = mincol
/ tab_width
- fromcol
/ tab_width
;
206 if (XFASTINT (n
) != 0)
208 Finsert_char (make_number ('\t'), n
);
210 fromcol
= (mincol
/ tab_width
) * tab_width
;
214 XFASTINT (col
) = mincol
- fromcol
;
215 Finsert_char (make_number (' '), col
);
217 last_known_column
= mincol
;
218 last_known_column_point
= point
;
219 last_known_column_modified
= MODIFF
;
221 XSETINT (col
, mincol
);
225 DEFUN ("current-indentation", Fcurrent_indentation
, Scurrent_indentation
,
227 "Return the indentation of the current line.\n\
228 This is the horizontal position of the character\n\
229 following any initial whitespace.")
234 XFASTINT (val
) = position_indentation (find_next_newline (point
, -1));
238 position_indentation (pos
)
241 register int column
= 0;
242 register int tab_width
= XINT (current_buffer
->tab_width
);
243 register unsigned char *p
;
244 register unsigned char *stop
;
246 if (tab_width
<= 0 || tab_width
> 20) tab_width
= 8;
248 stop
= &FETCH_CHAR (BUFFER_CEILING_OF (pos
)) + 1;
249 p
= &FETCH_CHAR (pos
);
256 pos
+= p
- &FETCH_CHAR (pos
);
257 p
= &FETCH_CHAR (pos
);
258 stop
= &FETCH_CHAR (BUFFER_CEILING_OF (pos
)) + 1;
266 column
+= tab_width
- column
% tab_width
;
274 DEFUN ("move-to-column", Fmove_to_column
, Smove_to_column
, 1, 2, 0,
275 "Move point to column COLUMN in the current line.\n\
276 The column of a character is calculated by adding together the widths\n\
277 as displayed of the previous characters in the line.\n\
278 This function ignores line-continuation;\n\
279 there is no upper limit on the column number a character can have\n\
280 and horizontal scrolling has no effect.\n\n\
281 If specified column is within a character, point goes after that character.\n\
282 If it's past end of line, point goes to end of line.\n\n\
283 A non-nil second (optional) argument FORCE means, if the line\n\
284 is too short to reach column COLUMN then add spaces/tabs to get there,\n\
285 and if COLUMN is in the middle of a tab character, change it to spaces.")
287 Lisp_Object column
, force
;
290 register int col
= current_column ();
293 register int tab_width
= XINT (current_buffer
->tab_width
);
294 register int ctl_arrow
= !NILP (current_buffer
->ctl_arrow
);
295 register struct Lisp_Vector
*dp
= buffer_display_table ();
301 if (tab_width
<= 0 || tab_width
> 20) tab_width
= 8;
302 CHECK_NATNUM (column
, 0);
303 goal
= XINT (column
);
309 /* If we're starting past the desired column,
310 back up to beginning of line and scan from there. */
313 pos
= find_next_newline (pos
, -1);
317 while (col
< goal
&& pos
< end
)
319 c
= FETCH_CHAR (pos
);
322 if (c
== '\r' && EQ (current_buffer
->selective_display
, Qt
))
329 col
= col
/ tab_width
* tab_width
;
331 else if (dp
!= 0 && XTYPE (DISP_CHAR_ROPE (dp
, c
)) == Lisp_String
)
332 col
+= XSTRING (DISP_CHAR_ROPE (dp
, c
))->size
/ sizeof (GLYPH
);
333 else if (ctl_arrow
&& (c
< 040 || c
== 0177))
335 else if (c
< 040 || c
>= 0177)
343 /* If a tab char made us overshoot, change it to spaces
344 and scan through it again. */
345 if (!NILP (force
) && col
> goal
&& c
== '\t' && prev_col
< goal
)
349 del_range (point
- 1, point
);
350 Findent_to (make_number (goal
), Qnil
);
352 Findent_to (make_number (col
), Qnil
);
356 /* If line ends prematurely, add space to the end. */
357 if (col
< goal
&& !NILP (force
))
358 Findent_to (make_number (col
= goal
));
360 last_known_column
= col
;
361 last_known_column_point
= point
;
362 last_known_column_modified
= MODIFF
;
364 XFASTINT (val
) = col
;
368 struct position val_compute_motion
;
370 /* Scan the current buffer forward from offset FROM, pretending that
371 this is at line FROMVPOS, column FROMHPOS, until reaching buffer
372 offset TO or line TOVPOS, column TOHPOS (whichever comes first),
373 and return the ending buffer position and screen location.
375 WIDTH is the number of columns available to display text;
376 compute_motion uses this to handle continuation lines and such.
377 HSCROLL is the number of columns not being displayed at the left
378 margin; this is usually taken from a window's hscroll member.
379 TAB_OFFSET is the number of columns of the first tab that aren't
380 being displayed, perhaps because of a continuation line or
383 compute_motion returns a pointer to a struct position. The bufpos
384 member gives the buffer position at the end of the scan, and hpos
385 and vpos give its cartesian location. I'm not clear on what the
388 For example, to find the buffer position of column COL of line LINE
389 of a certain window, pass the window's starting location as FROM
390 and the window's upper-left coordinates as FROMVPOS and FROMHPOS.
391 Pass the buffer's ZV as TO, to limit the scan to the end of the
392 visible section of the buffer, and pass LINE and COL as TOVPOS and
395 When displaying in window w, a typical formula for WIDTH is:
398 - (window_width + window_left != frame_width)
401 window_width is XFASTINT (w->width),
402 window_left is XFASTINT (w->left),
403 and frame_width = FRAME_WIDTH (XFRAME (window->frame))
405 This accounts for the continuation-line backslashes, and the window
406 borders if the window is split vertically. */
409 compute_motion (from
, fromvpos
, fromhpos
, to
, tovpos
, tohpos
, width
, hscroll
, tab_offset
)
410 int from
, fromvpos
, fromhpos
, to
, tovpos
, tohpos
;
412 int hscroll
, tab_offset
;
414 register int hpos
= fromhpos
;
415 register int vpos
= fromvpos
;
419 register int tab_width
= XFASTINT (current_buffer
->tab_width
);
420 register int ctl_arrow
= !NILP (current_buffer
->ctl_arrow
);
421 register struct Lisp_Vector
*dp
= buffer_display_table ();
423 = XTYPE (current_buffer
->selective_display
) == Lisp_Int
424 ? XINT (current_buffer
->selective_display
)
425 : !NILP (current_buffer
->selective_display
) ? -1 : 0;
426 int prev_vpos
, prev_hpos
;
428 = (selective
&& dp
&& XTYPE (DISP_INVIS_ROPE (dp
)) == Lisp_String
429 ? XSTRING (DISP_INVIS_ROPE (dp
))->size
/ sizeof (GLYPH
) : 0);
431 if (tab_width
<= 0 || tab_width
> 20) tab_width
= 8;
432 for (pos
= from
; pos
< to
; pos
++)
434 /* Stop if past the target screen position. */
436 || (vpos
== tovpos
&& hpos
>= tohpos
))
442 c
= FETCH_CHAR (pos
);
443 if (c
>= 040 && c
< 0177
444 && (dp
== 0 || XTYPE (DISP_CHAR_ROPE (dp
, c
)) != Lisp_String
))
448 hpos
+= tab_width
- ((hpos
+ tab_offset
+ hscroll
- (hscroll
> 0)
449 /* Add tab_width here to make sure positive.
450 hpos can be negative after continuation
451 but can't be less than -tab_width. */
457 if (selective
> 0 && position_indentation (pos
+ 1) >= selective
)
459 /* Skip any number of invisible lines all at once */
462 while (++pos
< to
&& FETCH_CHAR (pos
) != '\n');
464 while (pos
< to
&& position_indentation (pos
+ 1) >= selective
);
466 /* Allow for the " ..." that is displayed for them. */
469 hpos
+= selective_rlen
;
473 /* We have skipped the invis text, but not the newline after. */
477 /* A visible line. */
481 if (hscroll
> 0) hpos
++; /* Count the ! on column 0 */
485 else if (c
== CR
&& selective
< 0)
487 /* In selective display mode,
488 everything from a ^M to the end of the line is invisible */
489 while (pos
< to
&& FETCH_CHAR (pos
) != '\n') pos
++;
490 /* Stop *before* the real newline. */
492 /* Allow for the " ..." that is displayed for them. */
495 hpos
+= selective_rlen
;
500 else if (dp
!= 0 && XTYPE (DISP_CHAR_ROPE (dp
, c
)) == Lisp_String
)
501 hpos
+= XSTRING (DISP_CHAR_ROPE (dp
, c
))->size
/ sizeof (GLYPH
);
503 hpos
+= (ctl_arrow
&& c
< 0200) ? 2 : 4;
505 /* Handle right margin. */
509 && FETCH_CHAR (pos
+ 1) != '\n')))
512 || (vpos
== tovpos
&& hpos
>= tohpos
))
515 || (truncate_partial_width_windows
516 && width
+ 1 < FRAME_WIDTH (selected_frame
))
517 || !NILP (current_buffer
->truncate_lines
))
519 /* Truncating: skip to newline. */
520 while (pos
< to
&& FETCH_CHAR (pos
) != '\n') pos
++;
535 val_compute_motion
.bufpos
= pos
;
536 val_compute_motion
.hpos
= hpos
;
537 val_compute_motion
.vpos
= vpos
;
538 val_compute_motion
.prevhpos
= prev_hpos
;
540 /* Nonzero if have just continued a line */
541 val_compute_motion
.contin
543 && (val_compute_motion
.vpos
!= prev_vpos
)
546 return &val_compute_motion
;
550 /* Return the column of position POS in window W's buffer,
551 rounded down to a multiple of the internal width of W.
552 This is the amount of indentation of position POS
553 that is not visible in its horizontal position in the window. */
556 pos_tab_offset (w
, pos
)
562 int width
= XFASTINT (w
->width
) - 1
563 - (XFASTINT (w
->width
) + XFASTINT (w
->left
)
564 != FRAME_WIDTH (XFRAME (w
->frame
)));
566 if (pos
== BEGV
|| FETCH_CHAR (pos
- 1) == '\n')
569 col
= current_column ();
571 return col
- (col
% width
);
574 /* start_hpos is the hpos of the first character of the buffer:
575 zero except for the minibuffer window,
576 where it is the width of the prompt. */
578 struct position val_vmotion
;
581 vmotion (from
, vtarget
, width
, hscroll
, window
)
582 register int from
, vtarget
, width
;
587 /* vpos is cumulative vertical position, changed as from is changed */
588 register int vpos
= 0;
589 register int prevline
;
591 int lmargin
= hscroll
> 0 ? 1 - hscroll
: 0;
593 = XTYPE (current_buffer
->selective_display
) == Lisp_Int
594 ? XINT (current_buffer
->selective_display
)
595 : !NILP (current_buffer
->selective_display
) ? -1 : 0;
596 int start_hpos
= (EQ (window
, minibuf_window
) ? minibuf_prompt_width
: 0);
601 /* Moving downward is simple, but must calculate from beg of line
602 to determine hpos of starting point */
603 if (from
> BEGV
&& FETCH_CHAR (from
- 1) != '\n')
605 prevline
= find_next_newline (from
, -1);
608 && position_indentation (prevline
) >= selective
)
609 prevline
= find_next_newline (prevline
- 1, -1);
610 pos
= *compute_motion (prevline
, 0,
611 lmargin
+ (prevline
== 1 ? start_hpos
: 0),
612 from
, 1 << (INTBITS
- 2), 0,
617 pos
.hpos
= lmargin
+ (from
== 1 ? start_hpos
: 0);
620 return compute_motion (from
, vpos
, pos
.hpos
,
621 ZV
, vtarget
, - (1 << (INTBITS
- 2)),
622 width
, hscroll
, pos
.vpos
* width
);
625 /* To move upward, go a line at a time until
626 we have gone at least far enough */
630 while ((vpos
> vtarget
|| first
) && from
> BEGV
)
635 prevline
= find_next_newline (prevline
- 1, -1);
638 || position_indentation (prevline
) < selective
)
641 pos
= *compute_motion (prevline
, 0,
642 lmargin
+ (prevline
== 1 ? start_hpos
: 0),
643 from
, 1 << (INTBITS
- 2), 0,
650 /* If we made exactly the desired vertical distance,
651 or if we hit beginning of buffer,
652 return point found */
655 val_vmotion
.bufpos
= from
;
656 val_vmotion
.vpos
= vpos
;
657 val_vmotion
.hpos
= lmargin
;
658 val_vmotion
.contin
= 0;
659 val_vmotion
.prevhpos
= 0;
663 /* Otherwise find the correct spot by moving down */
667 DEFUN ("vertical-motion", Fvertical_motion
, Svertical_motion
, 1, 1, 0,
668 "Move to start of screen line LINES lines down.\n\
669 If LINES is negative, this is moving up.\n\
670 Sets point to position found; this may be start of line\n\
671 or just the start of a continuation line.\n\
672 Returns number of lines moved; may be closer to zero than LINES\n\
673 if beginning or end of buffer was reached.")
678 register struct window
*w
= XWINDOW (selected_window
);
679 int width
= XFASTINT (w
->width
) - 1
680 - (XFASTINT (w
->width
) + XFASTINT (w
->left
)
681 != FRAME_WIDTH (XFRAME (w
->frame
)));
683 CHECK_NUMBER (lines
, 0);
685 pos
= *vmotion (point
, XINT (lines
), width
,
686 /* Not XFASTINT since perhaps could be negative */
687 XINT (w
->hscroll
), selected_window
);
690 return make_number (pos
.vpos
);
695 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode
,
696 "*Indentation can insert tabs if this is non-nil.\n\
697 Setting this variable automatically makes it local to the current buffer.");
698 indent_tabs_mode
= 1;
700 defsubr (&Scurrent_indentation
);
701 defsubr (&Sindent_to
);
702 defsubr (&Scurrent_column
);
703 defsubr (&Smove_to_column
);
704 defsubr (&Svertical_motion
);