Initial revision
[emacs.git] / src / indent.c
blob9561927167dd3c5a25c1dc5ae55a603dd461867c
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)
9 any later version.
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. */
21 #include "config.h"
22 #include "lisp.h"
23 #include "buffer.h"
24 #include "indent.h"
25 #include "screen.h"
26 #include "window.h"
27 #include "termchar.h"
28 #include "termopts.h"
29 #include "disptab.h"
31 /* Indentation can insert tabs if this is non-zero;
32 otherwise always uses spaces */
33 int indent_tabs_mode;
35 #define min(a, b) ((a) < (b) ? (a) : (b))
36 #define max(a, b) ((a) > (b) ? (a) : (b))
38 #define CR 015
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. */
54 struct Lisp_Vector *
55 buffer_display_table ()
57 Lisp_Object thisbuf;
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);
66 return 0;
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.")
81 Lisp_Object temp;
82 XFASTINT (temp) = current_column ();
83 return temp;
86 int
87 current_column ()
89 register int col;
90 register unsigned char *ptr, *stop;
91 register int tab_seen;
92 int post_tab;
93 register int c;
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 ();
97 int stopchar;
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. */
107 if (point == BEGV)
108 stop = ptr;
109 else if (point <= GPT || BEGV > GPT)
110 stop = BEGV_ADDR;
111 else
112 stop = GAP_END_ADDR;
114 if (tab_width <= 0 || tab_width > 20) tab_width = 8;
116 col = 0, tab_seen = 0, post_tab = 0;
118 while (1)
120 if (ptr == stop)
122 /* We stopped either for the beginning of the buffer
123 or for the gap. */
124 if (ptr == BEGV_ADDR)
125 break;
126 /* It was the gap. Jump back over it. */
127 stop = BEGV_ADDR;
128 ptr = GPT_ADDR;
129 /* Check whether that brings us to beginning of buffer. */
130 if (BEGV >= GPT) break;
133 c = *--ptr;
134 if (c >= 040 && c < 0177
135 && (dp == 0 || XTYPE (DISP_CHAR_ROPE (dp, c)) != Lisp_String))
137 col++;
139 else if (c == '\n')
140 break;
141 else if (c == '\r' && EQ (current_buffer->selective_display, Qt))
142 break;
143 else if (c == '\t')
145 if (tab_seen)
146 col = ((col + tab_width) / tab_width) * tab_width;
148 post_tab += col;
149 col = 0;
150 tab_seen = 1;
152 else if (dp != 0 && XTYPE (DISP_CHAR_ROPE (dp, c)) == Lisp_String)
153 col += XSTRING (DISP_CHAR_ROPE (dp, c))->size / sizeof (GLYPH);
154 else
155 col += (ctl_arrow && c < 0200) ? 2 : 4;
158 if (tab_seen)
160 col = ((col + tab_width) / tab_width) * tab_width;
161 col += post_tab;
164 last_known_column = col;
165 last_known_column_point = point;
166 last_known_column_modified = MODIFF;
168 return col;
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.")
176 (col, minimum)
177 Lisp_Object col, minimum;
179 int mincol;
180 register int fromcol;
181 register int tab_width = XINT (current_buffer->tab_width);
183 CHECK_NUMBER (col, 0);
184 if (NULL (minimum))
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)
199 Lisp_Object n;
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);
217 return col;
220 DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
221 0, 0, 0,
222 "Return the indentation of the current line.\n\
223 This is the horizontal position of the character\n\
224 following any initial whitespace.")
227 Lisp_Object val;
229 XFASTINT (val) = position_indentation (find_next_newline (point, -1));
230 return val;
233 position_indentation (pos)
234 register int 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);
245 while (1)
247 while (p == stop)
249 if (pos == ZV)
250 return column;
251 pos += p - &FETCH_CHAR (pos);
252 p = &FETCH_CHAR (pos);
253 stop = &FETCH_CHAR (BUFFER_CEILING_OF (pos)) + 1;
255 switch (*p++)
257 case ' ':
258 column++;
259 break;
260 case '\t':
261 column += tab_width - column % tab_width;
262 break;
263 default:
264 return column;
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.")
281 (column, force)
282 Lisp_Object column, force;
284 register int pos;
285 register int col = current_column ();
286 register int goal;
287 register int end;
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 ();
292 Lisp_Object val;
293 int prev_col;
294 int c;
296 if (tab_width <= 0 || tab_width > 20) tab_width = 8;
297 CHECK_NATNUM (column, 0);
298 goal = XINT (column);
300 retry:
301 pos = point;
302 end = ZV;
304 /* If we're starting past the desired column,
305 back up to beginning of line and scan from there. */
306 if (col > goal)
308 pos = find_next_newline (pos, -1);
309 col = 0;
312 while (col < goal && pos < end)
314 c = FETCH_CHAR (pos);
315 if (c == '\n')
316 break;
317 if (c == '\r' && EQ (current_buffer->selective_display, Qt))
318 break;
319 pos++;
320 if (c == '\t')
322 prev_col = col;
323 col += tab_width;
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))
329 col++;
330 else if (c < 040 || c >= 0177)
331 col += 3;
332 else
333 col++;
336 SET_PT (pos);
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));
344 insert_char (' ');
345 goto retry;
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;
357 return val;
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
378 other members are.
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
385 TOHPOS.
387 When displaying in window w, a typical formula for WIDTH is:
389 window_width - 1
390 - (window_width + window_left != screen_width)
392 where
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. */
400 struct position *
401 compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, tab_offset)
402 int from, fromvpos, fromhpos, to, tovpos, tohpos;
403 register int width;
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)
412 #else
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
423 register
424 #endif /* TAHOE_REGISTER_BUG */
425 int cpos = fromhpos + (fromvpos << SHORTBITS);
426 register int target = tohpos + (tovpos << SHORTBITS);
427 register int pos;
428 register int c;
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 ();
432 int selective
433 = XTYPE (current_buffer->selective_display) == Lisp_Int
434 ? XINT (current_buffer->selective_display)
435 : !NULL (current_buffer->selective_display) ? -1 : 0;
436 int prevpos;
437 int selective_rlen
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++)
444 prevpos = cpos;
445 c = FETCH_CHAR (pos);
446 if (c >= 040 && c < 0177
447 && (dp == 0 || XTYPE (DISP_CHAR_ROPE (dp, c)) != Lisp_String))
448 cpos++;
449 else if (c == '\t')
451 cpos += tab_width
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. */
456 + tab_width)
457 % tab_width;
459 else if (c == '\n')
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);
469 pos--;
470 /* Allow for the " ..." that is displayed for them. */
471 if (selective_rlen)
473 cpos += selective_rlen;
474 if (HPOS (cpos) >= width)
475 cpos -= HPOS (cpos) - width;
478 else
479 cpos += (1 << SHORTBITS) - HPOS (cpos);
480 cpos -= hscroll;
481 if (hscroll > 0) cpos++; /* Count the ! on column 0 */
482 tab_offset = 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++;
489 pos--;
490 /* Allow for the " ..." that is displayed for them. */
491 if (selective_rlen)
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);
500 else
501 cpos += (ctl_arrow && c < 0200) ? 2 : 4;
503 if (HPOS (cpos) >= width
504 && (HPOS (cpos) > width
505 || (pos < (ZV - 1)
506 && FETCH_CHAR (pos + 1) != '\n')))
508 if (cpos >= target)
509 break;
510 if (hscroll
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++;
516 pos--;
518 else
520 cpos += (1 << SHORTBITS) - width;
521 tab_offset += 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
534 = pos != from
535 && (val_compute_motion.vpos != VPOS (prevpos))
536 && c != '\n';
538 return &val_compute_motion;
540 #undef HPOS
541 #undef VPOS
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)
551 struct window *w;
552 register int pos;
554 int opoint = point;
555 int col;
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')
561 return 0;
562 SET_PT (pos);
563 col = current_column ();
564 SET_PT (opoint);
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;
574 struct position *
575 vmotion (from, vtarget, width, hscroll, window)
576 register int from, vtarget, width;
577 int hscroll;
578 Lisp_Object window;
580 struct position pos;
581 /* vpos is cumulative vertical position, changed as from is changed */
582 register int vpos = 0;
583 register int prevline;
584 register int first;
585 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
586 int selective
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);
592 retry:
593 if (vtarget > vpos)
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);
600 while (selective > 0
601 && prevline > BEGV
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),
606 from, 10000, 10000,
607 width, hscroll, 0);
609 else
611 pos.hpos = lmargin + (from == 1 ? start_hpos : 0);
612 pos.vpos = 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 */
622 first = 1;
624 while ((vpos > vtarget || first) && from > BEGV)
626 prevline = from;
627 while (1)
629 prevline = find_next_newline (prevline - 1, -1);
630 if (prevline == BEGV
631 || selective <= 0
632 || position_indentation (prevline) < selective)
633 break;
635 pos = *compute_motion (prevline, 0,
636 lmargin + (prevline == 1 ? start_hpos : 0),
637 from, 10000, 10000,
638 width, hscroll, 0);
639 vpos -= pos.vpos;
640 first = 0;
641 from = prevline;
644 /* If we made exactly the desired vertical distance,
645 or if we hit beginning of buffer,
646 return point found */
647 if (vpos >= vtarget)
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;
654 return &val_vmotion;
657 /* Otherwise find the correct spot by moving down */
658 goto retry;
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.")
668 (lines)
669 Lisp_Object lines;
671 struct position pos;
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);
683 SET_PT (pos.bufpos);
684 return make_number (pos.vpos);
687 syms_of_indent ()
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);