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 extern int minibuf_prompt_width
;
52 /* Get the display table to use for the current buffer. */
55 buffer_display_table ()
59 thisbuf
= current_buffer
->display_table
;
60 if (XTYPE (thisbuf
) == Lisp_Vector
61 && XVECTOR (thisbuf
)->size
== DISP_TABLE_SIZE
)
62 return XVECTOR (thisbuf
);
63 if (XTYPE (Vstandard_display_table
) == Lisp_Vector
64 && XVECTOR (Vstandard_display_table
)->size
== DISP_TABLE_SIZE
)
65 return XVECTOR (Vstandard_display_table
);
69 DEFUN ("current-column", Fcurrent_column
, Scurrent_column
, 0, 0, 0,
70 "Return the horizontal position of point. Beginning of line is column 0.\n\
71 This is calculated by adding together the widths of all the displayed\n\
72 representations of the character between the start of the previous line\n\
73 and point. (eg control characters will have a width of 2 or 4, tabs\n\
74 will have a variable width)\n\
75 Ignores finite width of screen, which means that this function may return\n\
76 values greater than (screen-width).\n\
77 Whether the line is visible (if `selective-display' is t) has no effect;\n\
78 however, ^M is treated as end of line when `selective-display' is t.")
82 XFASTINT (temp
) = current_column ();
90 register unsigned char *ptr
, *stop
;
91 register int tab_seen
;
94 register int tab_width
= XINT (current_buffer
->tab_width
);
95 int ctl_arrow
= !NULL (current_buffer
->ctl_arrow
);
96 register struct Lisp_Vector
*dp
= buffer_display_table ();
99 if (point
== last_known_column_point
100 && MODIFF
== last_known_column_modified
)
101 return last_known_column
;
103 /* Make a pointer for decrementing through the chars before point. */
104 ptr
= &FETCH_CHAR (point
- 1) + 1;
105 /* Make a pointer to where consecutive chars leave off,
106 going backwards from point. */
109 else if (point
<= GPT
|| BEGV
> GPT
)
114 if (tab_width
<= 0 || tab_width
> 20) tab_width
= 8;
116 col
= 0, tab_seen
= 0, post_tab
= 0;
122 /* We stopped either for the beginning of the buffer
124 if (ptr
== BEGV_ADDR
)
126 /* It was the gap. Jump back over it. */
129 /* Check whether that brings us to beginning of buffer. */
130 if (BEGV
>= GPT
) break;
134 if (c
>= 040 && c
< 0177
135 && (dp
== 0 || XTYPE (DISP_CHAR_ROPE (dp
, c
)) != Lisp_String
))
141 else if (c
== '\r' && EQ (current_buffer
->selective_display
, Qt
))
146 col
= ((col
+ tab_width
) / tab_width
) * tab_width
;
152 else if (dp
!= 0 && XTYPE (DISP_CHAR_ROPE (dp
, c
)) == Lisp_String
)
153 col
+= XSTRING (DISP_CHAR_ROPE (dp
, c
))->size
/ sizeof (GLYPH
);
155 col
+= (ctl_arrow
&& c
< 0200) ? 2 : 4;
160 col
= ((col
+ tab_width
) / tab_width
) * tab_width
;
164 last_known_column
= col
;
165 last_known_column_point
= point
;
166 last_known_column_modified
= MODIFF
;
172 DEFUN ("indent-to", Findent_to
, Sindent_to
, 1, 2, "NIndent to column: ",
173 "Indent from point with tabs and spaces until COLUMN is reached.\n\
174 Optional second argument MIN says always do at least MIN spaces\n\
175 even if that goes past COLUMN; by default, MIN is zero.")
177 Lisp_Object col
, minimum
;
180 register int fromcol
;
181 register int tab_width
= XINT (current_buffer
->tab_width
);
183 CHECK_NUMBER (col
, 0);
185 XFASTINT (minimum
) = 0;
186 CHECK_NUMBER (minimum
, 1);
188 fromcol
= current_column ();
189 mincol
= fromcol
+ XINT (minimum
);
190 if (mincol
< XINT (col
)) mincol
= XINT (col
);
192 if (fromcol
== mincol
)
193 return make_number (mincol
);
195 if (tab_width
<= 0 || tab_width
> 20) tab_width
= 8;
197 if (indent_tabs_mode
)
200 XFASTINT (n
) = mincol
/ tab_width
- fromcol
/ tab_width
;
201 if (XFASTINT (n
) != 0)
203 Finsert_char (make_number ('\t'), n
);
205 fromcol
= (mincol
/ tab_width
) * tab_width
;
209 XFASTINT (col
) = mincol
- fromcol
;
210 Finsert_char (make_number (' '), col
);
212 last_known_column
= mincol
;
213 last_known_column_point
= point
;
214 last_known_column_modified
= MODIFF
;
216 XSETINT (col
, mincol
);
220 DEFUN ("current-indentation", Fcurrent_indentation
, Scurrent_indentation
,
222 "Return the indentation of the current line.\n\
223 This is the horizontal position of the character\n\
224 following any initial whitespace.")
229 XFASTINT (val
) = position_indentation (find_next_newline (point
, -1));
233 position_indentation (pos
)
236 register int column
= 0;
237 register int tab_width
= XINT (current_buffer
->tab_width
);
238 register unsigned char *p
;
239 register unsigned char *stop
;
241 if (tab_width
<= 0 || tab_width
> 20) tab_width
= 8;
243 stop
= &FETCH_CHAR (BUFFER_CEILING_OF (pos
)) + 1;
244 p
= &FETCH_CHAR (pos
);
251 pos
+= p
- &FETCH_CHAR (pos
);
252 p
= &FETCH_CHAR (pos
);
253 stop
= &FETCH_CHAR (BUFFER_CEILING_OF (pos
)) + 1;
261 column
+= tab_width
- column
% tab_width
;
269 DEFUN ("move-to-column", Fmove_to_column
, Smove_to_column
, 1, 2, 0,
270 "Move point to column COLUMN in the current line.\n\
271 The column of a character is calculated by adding together the widths\n\
272 as displayed of the previous characters in the line.\n\
273 This function ignores line-continuation;\n\
274 there is no upper limit on the column number a character can have\n\
275 and horizontal scrolling has no effect.\n\n\
276 If specified column is within a character, point goes after that character.\n\
277 If it's past end of line, point goes to end of line.\n\n\
278 A non-nil second (optional) argument FORCE means, if the line\n\
279 is too short to reach column COLUMN then add spaces/tabs to get there,\n\
280 and if COLUMN is in the middle of a tab character, change it to spaces.")
282 Lisp_Object column
, force
;
285 register int col
= current_column ();
288 register int tab_width
= XINT (current_buffer
->tab_width
);
289 register int ctl_arrow
= !NULL (current_buffer
->ctl_arrow
);
290 register struct Lisp_Vector
*dp
= buffer_display_table ();
296 if (tab_width
<= 0 || tab_width
> 20) tab_width
= 8;
297 CHECK_NATNUM (column
, 0);
298 goal
= XINT (column
);
304 /* If we're starting past the desired column,
305 back up to beginning of line and scan from there. */
308 pos
= find_next_newline (pos
, -1);
312 while (col
< goal
&& pos
< end
)
314 c
= FETCH_CHAR (pos
);
317 if (c
== '\r' && EQ (current_buffer
->selective_display
, Qt
))
324 col
= col
/ tab_width
* tab_width
;
326 else if (dp
!= 0 && XTYPE (DISP_CHAR_ROPE (dp
, c
)) == Lisp_String
)
327 col
+= XSTRING (DISP_CHAR_ROPE (dp
, c
))->size
/ sizeof (GLYPH
);
328 else if (ctl_arrow
&& (c
< 040 || c
== 0177))
330 else if (c
< 040 || c
>= 0177)
338 /* If a tab char made us overshoot, change it to spaces
339 and scan through it again. */
340 if (!NULL (force
) && col
> goal
&& c
== '\t' && prev_col
< goal
)
342 del_range (point
- 1, point
);
343 Findent_to (make_number (col
- 1));
348 /* If line ends prematurely, add space to the end. */
349 if (col
< goal
&& !NULL (force
))
350 Findent_to (make_number (col
= goal
));
352 last_known_column
= col
;
353 last_known_column_point
= point
;
354 last_known_column_modified
= MODIFF
;
356 XFASTINT (val
) = col
;
360 struct position val_compute_motion
;
362 /* Scan the current buffer forward from offset FROM, pretending that
363 this is at line FROMVPOS, column FROMHPOS, until reaching buffer
364 offset TO or line TOVPOS, column TOHPOS (whichever comes first),
365 and return the ending buffer position and screen location.
367 WIDTH is the number of columns available to display text;
368 compute_motion uses this to handle continuation lines and such.
369 HSCROLL is the number of columns not being displayed at the left
370 margin; this is usually taken from a window's hscroll member.
371 TAB_OFFSET is a mysterious value, perhaps the number of columns of
372 the first tab that aren't being displayed, perhaps because of a
373 continuation line or something.
375 compute_motion returns a pointer to a struct position. The bufpos
376 member gives the buffer position at the end of the scan, and hpos
377 and vpos give its cartesian location. I'm not clear on what the
380 For example, to find the buffer position of column COL of line LINE
381 of a certain window, pass the window's starting location as FROM
382 and the window's upper-left coordinates as FROMVPOS and FROMHPOS.
383 Pass the buffer's ZV as TO, to limit the scan to the end of the
384 visible section of the buffer, and pass LINE and COL as TOVPOS and
387 When displaying in window w, a typical formula for WIDTH is:
390 - (window_width + window_left != screen_width)
393 window_width is XFASTINT (w->width),
394 window_left is XFASTINT (w->left),
395 and screen_width = SCREEN_WIDTH (XSCREEN (window->screen))
397 This accounts for the continuation-line backslashes, and the window
398 borders if the window is split vertically. */
401 compute_motion (from
, fromvpos
, fromhpos
, to
, tovpos
, tohpos
, width
, hscroll
, tab_offset
)
402 int from
, fromvpos
, fromhpos
, to
, tovpos
, tohpos
;
404 int hscroll
, tab_offset
;
406 /* Note that `cpos' is CURRENT_VPOS << SHORTBITS + CURRENT_HPOS,
407 and that CURRENT_HPOS may be negative. Use these macros
408 to extract the hpos or the vpos from cpos or anything like it.
410 #ifndef SHORT_CAST_BUG
411 #define HPOS(VAR) (short) (VAR)
413 #define HPOS(VAR) (((VAR) & (1 << (SHORTBITS - 1)) \
414 ? ~((1 << SHORTBITS) - 1) : 0) \
415 | (VAR) & ((1 << SHORTBITS) - 1))
416 /* #define HPOS(VAR) (((VAR) & 0x8000 ? 0xffff0000 : 0) | ((VAR) & 0xffff)) */
417 #endif /* SHORT_CAST_BUG */
419 #define VPOS(VAR) (((VAR) >> SHORTBITS) + (HPOS (VAR) < 0))
422 #ifndef TAHOE_REGISTER_BUG
424 #endif /* TAHOE_REGISTER_BUG */
425 int cpos
= fromhpos
+ (fromvpos
<< SHORTBITS
);
426 register int target
= tohpos
+ (tovpos
<< SHORTBITS
);
429 register int tab_width
= XFASTINT (current_buffer
->tab_width
);
430 register int ctl_arrow
= !NULL (current_buffer
->ctl_arrow
);
431 register struct Lisp_Vector
*dp
= buffer_display_table ();
433 = XTYPE (current_buffer
->selective_display
) == Lisp_Int
434 ? XINT (current_buffer
->selective_display
)
435 : !NULL (current_buffer
->selective_display
) ? -1 : 0;
438 = (selective
&& dp
&& XTYPE (DISP_INVIS_ROPE (dp
)) == Lisp_String
439 ? XSTRING (DISP_INVIS_ROPE (dp
))->size
/ sizeof (GLYPH
) : 0);
441 if (tab_width
<= 0 || tab_width
> 20) tab_width
= 8;
442 for (pos
= from
; pos
< to
&& cpos
< target
; pos
++)
445 c
= FETCH_CHAR (pos
);
446 if (c
>= 040 && c
< 0177
447 && (dp
== 0 || XTYPE (DISP_CHAR_ROPE (dp
, c
)) != Lisp_String
))
452 - HPOS (cpos
+ tab_offset
+ hscroll
- (hscroll
> 0)
453 /* Add tab_width here to make sure positive.
454 cpos can be negative after continuation
455 but can't be less than -tab_width. */
461 if (selective
> 0 && position_indentation (pos
+ 1) >= selective
)
463 /* Skip any number of invisible lines all at once */
466 while (++pos
< to
&& FETCH_CHAR(pos
) != '\n');
468 while (selective
> 0 && position_indentation (pos
+ 1) >= selective
);
470 /* Allow for the " ..." that is displayed for them. */
473 cpos
+= selective_rlen
;
474 if (HPOS (cpos
) >= width
)
475 cpos
-= HPOS (cpos
) - width
;
479 cpos
+= (1 << SHORTBITS
) - HPOS (cpos
);
481 if (hscroll
> 0) cpos
++; /* Count the ! on column 0 */
484 else if (c
== CR
&& selective
< 0)
486 /* In selective display mode,
487 everything from a ^M to the end of the line is invisible */
488 while (pos
< to
&& FETCH_CHAR(pos
) != '\n') pos
++;
490 /* Allow for the " ..." that is displayed for them. */
493 cpos
+= selective_rlen
;
494 if (HPOS (cpos
) >= width
)
495 cpos
-= HPOS (cpos
) - width
;
498 else if (dp
!= 0 && XTYPE (DISP_CHAR_ROPE (dp
, c
)) == Lisp_String
)
499 cpos
+= XSTRING (DISP_CHAR_ROPE (dp
, c
))->size
/ sizeof (GLYPH
);
501 cpos
+= (ctl_arrow
&& c
< 0200) ? 2 : 4;
503 if (HPOS (cpos
) >= width
504 && (HPOS (cpos
) > width
506 && FETCH_CHAR (pos
+ 1) != '\n')))
511 || (truncate_partial_width_windows
512 && width
+ 1 < SCREEN_WIDTH (selected_screen
))
513 || !NULL (current_buffer
->truncate_lines
))
515 while (pos
< to
&& FETCH_CHAR(pos
) != '\n') pos
++;
520 cpos
+= (1 << SHORTBITS
) - width
;
527 val_compute_motion
.bufpos
= pos
;
528 val_compute_motion
.hpos
= HPOS (cpos
);
529 val_compute_motion
.vpos
= VPOS (cpos
);
530 val_compute_motion
.prevhpos
= HPOS (prevpos
);
532 /* Nonzero if have just continued a line */
533 val_compute_motion
.contin
535 && (val_compute_motion
.vpos
!= VPOS (prevpos
))
538 return &val_compute_motion
;
544 /* Return the column of position POS in window W's buffer,
545 rounded down to a multiple of the internal width of W.
546 This is the amount of indentation of position POS
547 that is not visible in its horizontal position in the window. */
550 pos_tab_offset (w
, pos
)
556 int width
= XFASTINT (w
->width
) - 1
557 - (XFASTINT (w
->width
) + XFASTINT (w
->left
)
558 != SCREEN_WIDTH (XSCREEN (w
->screen
)));
560 if (pos
== BEGV
|| FETCH_CHAR (pos
- 1) == '\n')
563 col
= current_column ();
565 return col
- (col
% width
);
568 /* start_hpos is the hpos of the first character of the buffer:
569 zero except for the minibuffer window,
570 where it is the width of the prompt. */
572 struct position val_vmotion
;
575 vmotion (from
, vtarget
, width
, hscroll
, window
)
576 register int from
, vtarget
, width
;
581 /* vpos is cumulative vertical position, changed as from is changed */
582 register int vpos
= 0;
583 register int prevline
;
585 int lmargin
= hscroll
> 0 ? 1 - hscroll
: 0;
587 = XTYPE (current_buffer
->selective_display
) == Lisp_Int
588 ? XINT (current_buffer
->selective_display
)
589 : !NULL (current_buffer
->selective_display
) ? -1 : 0;
590 int start_hpos
= (EQ (window
, minibuf_window
) ? minibuf_prompt_width
: 0);
595 /* Moving downward is simple, but must calculate from beg of line
596 to determine hpos of starting point */
597 if (from
> BEGV
&& FETCH_CHAR (from
- 1) != '\n')
599 prevline
= find_next_newline (from
, -1);
602 && position_indentation (prevline
) >= selective
)
603 prevline
= find_next_newline (prevline
- 1, -1);
604 pos
= *compute_motion (prevline
, 0,
605 lmargin
+ (prevline
== 1 ? start_hpos
: 0),
611 pos
.hpos
= lmargin
+ (from
== 1 ? start_hpos
: 0);
614 return compute_motion (from
, vpos
, pos
.hpos
,
615 ZV
, vtarget
, - (1 << (SHORTBITS
- 1)),
616 width
, hscroll
, pos
.vpos
* width
);
619 /* To move upward, go a line at a time until
620 we have gone at least far enough */
624 while ((vpos
> vtarget
|| first
) && from
> BEGV
)
629 prevline
= find_next_newline (prevline
- 1, -1);
632 || position_indentation (prevline
) < selective
)
635 pos
= *compute_motion (prevline
, 0,
636 lmargin
+ (prevline
== 1 ? start_hpos
: 0),
644 /* If we made exactly the desired vertical distance,
645 or if we hit beginning of buffer,
646 return point found */
649 val_vmotion
.bufpos
= from
;
650 val_vmotion
.vpos
= vpos
;
651 val_vmotion
.hpos
= lmargin
;
652 val_vmotion
.contin
= 0;
653 val_vmotion
.prevhpos
= 0;
657 /* Otherwise find the correct spot by moving down */
661 DEFUN ("vertical-motion", Fvertical_motion
, Svertical_motion
, 1, 1, 0,
662 "Move to start of screen line LINES lines down.\n\
663 If LINES is negative, this is moving up.\n\
664 Sets point to position found; this may be start of line\n\
665 or just the start of a continuation line.\n\
666 Returns number of lines moved; may be closer to zero than LINES\n\
667 if beginning or end of buffer was reached.")
672 register struct window
*w
= XWINDOW (selected_window
);
673 int width
= XFASTINT (w
->width
) - 1
674 - (XFASTINT (w
->width
) + XFASTINT (w
->left
)
675 != SCREEN_WIDTH (XSCREEN (w
->screen
)));
677 CHECK_NUMBER (lines
, 0);
679 pos
= *vmotion (point
, XINT (lines
), width
,
680 /* Not XFASTINT since perhaps could be negative */
681 XINT (w
->hscroll
), selected_window
);
684 return make_number (pos
.vpos
);
689 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode
,
690 "*Indentation can insert tabs if this is non-nil.\n\
691 Setting this variable automatically makes it local to the current buffer.");
692 indent_tabs_mode
= 1;
694 defsubr (&Scurrent_indentation
);
695 defsubr (&Sindent_to
);
696 defsubr (&Scurrent_column
);
697 defsubr (&Smove_to_column
);
698 defsubr (&Svertical_motion
);