1 /* Indentation functions.
2 Copyright (C) 1985, 1986, 1987, 1988 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 screen, which means that this function may return\n\
74 values greater than (screen-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
)
347 del_range (point
- 1, point
);
348 Findent_to (make_number (col
- 1));
353 /* If line ends prematurely, add space to the end. */
354 if (col
< goal
&& !NILP (force
))
355 Findent_to (make_number (col
= goal
));
357 last_known_column
= col
;
358 last_known_column_point
= point
;
359 last_known_column_modified
= MODIFF
;
361 XFASTINT (val
) = col
;
365 struct position val_compute_motion
;
367 /* Scan the current buffer forward from offset FROM, pretending that
368 this is at line FROMVPOS, column FROMHPOS, until reaching buffer
369 offset TO or line TOVPOS, column TOHPOS (whichever comes first),
370 and return the ending buffer position and screen location.
372 WIDTH is the number of columns available to display text;
373 compute_motion uses this to handle continuation lines and such.
374 HSCROLL is the number of columns not being displayed at the left
375 margin; this is usually taken from a window's hscroll member.
376 TAB_OFFSET is a mysterious value, perhaps the number of columns of
377 the first tab that aren't being displayed, perhaps because of a
378 continuation line or something.
380 compute_motion returns a pointer to a struct position. The bufpos
381 member gives the buffer position at the end of the scan, and hpos
382 and vpos give its cartesian location. I'm not clear on what the
385 For example, to find the buffer position of column COL of line LINE
386 of a certain window, pass the window's starting location as FROM
387 and the window's upper-left coordinates as FROMVPOS and FROMHPOS.
388 Pass the buffer's ZV as TO, to limit the scan to the end of the
389 visible section of the buffer, and pass LINE and COL as TOVPOS and
392 When displaying in window w, a typical formula for WIDTH is:
395 - (window_width + window_left != screen_width)
398 window_width is XFASTINT (w->width),
399 window_left is XFASTINT (w->left),
400 and screen_width = SCREEN_WIDTH (XSCREEN (window->screen))
402 This accounts for the continuation-line backslashes, and the window
403 borders if the window is split vertically. */
406 compute_motion (from
, fromvpos
, fromhpos
, to
, tovpos
, tohpos
, width
, hscroll
, tab_offset
)
407 int from
, fromvpos
, fromhpos
, to
, tovpos
, tohpos
;
409 int hscroll
, tab_offset
;
411 /* Note that `cpos' is CURRENT_VPOS << SHORTBITS + CURRENT_HPOS,
412 and that CURRENT_HPOS may be negative. Use these macros
413 to extract the hpos or the vpos from cpos or anything like it.
415 #ifndef SHORT_CAST_BUG
416 #define HPOS(VAR) (short) (VAR)
418 #define HPOS(VAR) (((VAR) & (1 << (SHORTBITS - 1)) \
419 ? ~((1 << SHORTBITS) - 1) : 0) \
420 | (VAR) & ((1 << SHORTBITS) - 1))
421 /* #define HPOS(VAR) (((VAR) & 0x8000 ? 0xffff0000 : 0) | ((VAR) & 0xffff)) */
422 #endif /* SHORT_CAST_BUG */
424 #define VPOS(VAR) (((VAR) >> SHORTBITS) + (HPOS (VAR) < 0))
427 #ifndef TAHOE_REGISTER_BUG
429 #endif /* TAHOE_REGISTER_BUG */
430 int cpos
= fromhpos
+ (fromvpos
<< SHORTBITS
);
431 register int target
= tohpos
+ (tovpos
<< SHORTBITS
);
434 register int tab_width
= XFASTINT (current_buffer
->tab_width
);
435 register int ctl_arrow
= !NILP (current_buffer
->ctl_arrow
);
436 register struct Lisp_Vector
*dp
= buffer_display_table ();
438 = XTYPE (current_buffer
->selective_display
) == Lisp_Int
439 ? XINT (current_buffer
->selective_display
)
440 : !NILP (current_buffer
->selective_display
) ? -1 : 0;
443 = (selective
&& dp
&& XTYPE (DISP_INVIS_ROPE (dp
)) == Lisp_String
444 ? XSTRING (DISP_INVIS_ROPE (dp
))->size
/ sizeof (GLYPH
) : 0);
446 if (tab_width
<= 0 || tab_width
> 20) tab_width
= 8;
447 for (pos
= from
; pos
< to
&& cpos
< target
; pos
++)
450 c
= FETCH_CHAR (pos
);
451 if (c
>= 040 && c
< 0177
452 && (dp
== 0 || XTYPE (DISP_CHAR_ROPE (dp
, c
)) != Lisp_String
))
457 - HPOS (cpos
+ tab_offset
+ hscroll
- (hscroll
> 0)
458 /* Add tab_width here to make sure positive.
459 cpos can be negative after continuation
460 but can't be less than -tab_width. */
466 if (selective
> 0 && position_indentation (pos
+ 1) >= selective
)
468 /* Skip any number of invisible lines all at once */
471 while (++pos
< to
&& FETCH_CHAR(pos
) != '\n');
473 while (selective
> 0 && position_indentation (pos
+ 1) >= selective
);
475 /* Allow for the " ..." that is displayed for them. */
478 cpos
+= selective_rlen
;
479 if (HPOS (cpos
) >= width
)
480 cpos
-= HPOS (cpos
) - width
;
484 cpos
+= (1 << SHORTBITS
) - HPOS (cpos
);
486 if (hscroll
> 0) cpos
++; /* Count the ! on column 0 */
489 else if (c
== CR
&& selective
< 0)
491 /* In selective display mode,
492 everything from a ^M to the end of the line is invisible */
493 while (pos
< to
&& FETCH_CHAR(pos
) != '\n') pos
++;
495 /* Allow for the " ..." that is displayed for them. */
498 cpos
+= selective_rlen
;
499 if (HPOS (cpos
) >= width
)
500 cpos
-= HPOS (cpos
) - width
;
503 else if (dp
!= 0 && XTYPE (DISP_CHAR_ROPE (dp
, c
)) == Lisp_String
)
504 cpos
+= XSTRING (DISP_CHAR_ROPE (dp
, c
))->size
/ sizeof (GLYPH
);
506 cpos
+= (ctl_arrow
&& c
< 0200) ? 2 : 4;
508 if (HPOS (cpos
) >= width
509 && (HPOS (cpos
) > width
511 && FETCH_CHAR (pos
+ 1) != '\n')))
516 || (truncate_partial_width_windows
517 && width
+ 1 < SCREEN_WIDTH (selected_screen
))
518 || !NILP (current_buffer
->truncate_lines
))
520 while (pos
< to
&& FETCH_CHAR(pos
) != '\n') pos
++;
525 cpos
+= (1 << SHORTBITS
) - width
;
532 val_compute_motion
.bufpos
= pos
;
533 val_compute_motion
.hpos
= HPOS (cpos
);
534 val_compute_motion
.vpos
= VPOS (cpos
);
535 val_compute_motion
.prevhpos
= HPOS (prevpos
);
537 /* Nonzero if have just continued a line */
538 val_compute_motion
.contin
540 && (val_compute_motion
.vpos
!= VPOS (prevpos
))
543 return &val_compute_motion
;
549 /* Return the column of position POS in window W's buffer,
550 rounded down to a multiple of the internal width of W.
551 This is the amount of indentation of position POS
552 that is not visible in its horizontal position in the window. */
555 pos_tab_offset (w
, pos
)
561 int width
= XFASTINT (w
->width
) - 1
562 - (XFASTINT (w
->width
) + XFASTINT (w
->left
)
563 != SCREEN_WIDTH (XSCREEN (w
->screen
)));
565 if (pos
== BEGV
|| FETCH_CHAR (pos
- 1) == '\n')
568 col
= current_column ();
570 return col
- (col
% width
);
573 /* start_hpos is the hpos of the first character of the buffer:
574 zero except for the minibuffer window,
575 where it is the width of the prompt. */
577 struct position val_vmotion
;
580 vmotion (from
, vtarget
, width
, hscroll
, window
)
581 register int from
, vtarget
, width
;
586 /* vpos is cumulative vertical position, changed as from is changed */
587 register int vpos
= 0;
588 register int prevline
;
590 int lmargin
= hscroll
> 0 ? 1 - hscroll
: 0;
592 = XTYPE (current_buffer
->selective_display
) == Lisp_Int
593 ? XINT (current_buffer
->selective_display
)
594 : !NILP (current_buffer
->selective_display
) ? -1 : 0;
595 int start_hpos
= (EQ (window
, minibuf_window
) ? minibuf_prompt_width
: 0);
600 /* Moving downward is simple, but must calculate from beg of line
601 to determine hpos of starting point */
602 if (from
> BEGV
&& FETCH_CHAR (from
- 1) != '\n')
604 prevline
= find_next_newline (from
, -1);
607 && position_indentation (prevline
) >= selective
)
608 prevline
= find_next_newline (prevline
- 1, -1);
609 pos
= *compute_motion (prevline
, 0,
610 lmargin
+ (prevline
== 1 ? start_hpos
: 0),
616 pos
.hpos
= lmargin
+ (from
== 1 ? start_hpos
: 0);
619 return compute_motion (from
, vpos
, pos
.hpos
,
620 ZV
, vtarget
, - (1 << (SHORTBITS
- 1)),
621 width
, hscroll
, pos
.vpos
* width
);
624 /* To move upward, go a line at a time until
625 we have gone at least far enough */
629 while ((vpos
> vtarget
|| first
) && from
> BEGV
)
634 prevline
= find_next_newline (prevline
- 1, -1);
637 || position_indentation (prevline
) < selective
)
640 pos
= *compute_motion (prevline
, 0,
641 lmargin
+ (prevline
== 1 ? start_hpos
: 0),
649 /* If we made exactly the desired vertical distance,
650 or if we hit beginning of buffer,
651 return point found */
654 val_vmotion
.bufpos
= from
;
655 val_vmotion
.vpos
= vpos
;
656 val_vmotion
.hpos
= lmargin
;
657 val_vmotion
.contin
= 0;
658 val_vmotion
.prevhpos
= 0;
662 /* Otherwise find the correct spot by moving down */
666 DEFUN ("vertical-motion", Fvertical_motion
, Svertical_motion
, 1, 1, 0,
667 "Move to start of screen line LINES lines down.\n\
668 If LINES is negative, this is moving up.\n\
669 Sets point to position found; this may be start of line\n\
670 or just the start of a continuation line.\n\
671 Returns number of lines moved; may be closer to zero than LINES\n\
672 if beginning or end of buffer was reached.")
677 register struct window
*w
= XWINDOW (selected_window
);
678 int width
= XFASTINT (w
->width
) - 1
679 - (XFASTINT (w
->width
) + XFASTINT (w
->left
)
680 != SCREEN_WIDTH (XSCREEN (w
->screen
)));
682 CHECK_NUMBER (lines
, 0);
684 pos
= *vmotion (point
, XINT (lines
), width
,
685 /* Not XFASTINT since perhaps could be negative */
686 XINT (w
->hscroll
), selected_window
);
689 return make_number (pos
.vpos
);
694 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode
,
695 "*Indentation can insert tabs if this is non-nil.\n\
696 Setting this variable automatically makes it local to the current buffer.");
697 indent_tabs_mode
= 1;
699 defsubr (&Scurrent_indentation
);
700 defsubr (&Sindent_to
);
701 defsubr (&Scurrent_column
);
702 defsubr (&Smove_to_column
);
703 defsubr (&Svertical_motion
);