]> code.delx.au - gnu-emacs/blob - src/indent.c
*** empty log message ***
[gnu-emacs] / src / indent.c
1 /* Indentation functions.
2 Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
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.
10
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.
15
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. */
19
20
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"
30
31 /* Indentation can insert tabs if this is non-zero;
32 otherwise always uses spaces */
33 int indent_tabs_mode;
34
35 #define min(a, b) ((a) < (b) ? (a) : (b))
36 #define max(a, b) ((a) > (b) ? (a) : (b))
37
38 #define CR 015
39
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;
49
50 extern int minibuf_prompt_width;
51
52 /* Get the display table to use for the current buffer. */
53
54 struct Lisp_Vector *
55 buffer_display_table ()
56 {
57 Lisp_Object thisbuf;
58
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;
67 }
68 \f
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.")
79 ()
80 {
81 Lisp_Object temp;
82 XFASTINT (temp) = current_column ();
83 return temp;
84 }
85
86 /* Cancel any recorded value of the horizontal position. */
87
88 invalidate_current_column ()
89 {
90 last_known_column_point = 0;
91 }
92
93 int
94 current_column ()
95 {
96 register int col;
97 register unsigned char *ptr, *stop;
98 register int tab_seen;
99 int post_tab;
100 register int c;
101 register int tab_width = XINT (current_buffer->tab_width);
102 int ctl_arrow = !NULL (current_buffer->ctl_arrow);
103 register struct Lisp_Vector *dp = buffer_display_table ();
104 int stopchar;
105
106 if (point == last_known_column_point
107 && MODIFF == last_known_column_modified)
108 return last_known_column;
109
110 /* Make a pointer for decrementing through the chars before point. */
111 ptr = &FETCH_CHAR (point - 1) + 1;
112 /* Make a pointer to where consecutive chars leave off,
113 going backwards from point. */
114 if (point == BEGV)
115 stop = ptr;
116 else if (point <= GPT || BEGV > GPT)
117 stop = BEGV_ADDR;
118 else
119 stop = GAP_END_ADDR;
120
121 if (tab_width <= 0 || tab_width > 20) tab_width = 8;
122
123 col = 0, tab_seen = 0, post_tab = 0;
124
125 while (1)
126 {
127 if (ptr == stop)
128 {
129 /* We stopped either for the beginning of the buffer
130 or for the gap. */
131 if (ptr == BEGV_ADDR)
132 break;
133 /* It was the gap. Jump back over it. */
134 stop = BEGV_ADDR;
135 ptr = GPT_ADDR;
136 /* Check whether that brings us to beginning of buffer. */
137 if (BEGV >= GPT) break;
138 }
139
140 c = *--ptr;
141 if (c >= 040 && c < 0177
142 && (dp == 0 || XTYPE (DISP_CHAR_ROPE (dp, c)) != Lisp_String))
143 {
144 col++;
145 }
146 else if (c == '\n')
147 break;
148 else if (c == '\r' && EQ (current_buffer->selective_display, Qt))
149 break;
150 else if (c == '\t')
151 {
152 if (tab_seen)
153 col = ((col + tab_width) / tab_width) * tab_width;
154
155 post_tab += col;
156 col = 0;
157 tab_seen = 1;
158 }
159 else if (dp != 0 && XTYPE (DISP_CHAR_ROPE (dp, c)) == Lisp_String)
160 col += XSTRING (DISP_CHAR_ROPE (dp, c))->size / sizeof (GLYPH);
161 else
162 col += (ctl_arrow && c < 0200) ? 2 : 4;
163 }
164
165 if (tab_seen)
166 {
167 col = ((col + tab_width) / tab_width) * tab_width;
168 col += post_tab;
169 }
170
171 last_known_column = col;
172 last_known_column_point = point;
173 last_known_column_modified = MODIFF;
174
175 return col;
176 }
177 \f
178
179 DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
180 "Indent from point with tabs and spaces until COLUMN is reached.\n\
181 Optional second argument MIN says always do at least MIN spaces\n\
182 even if that goes past COLUMN; by default, MIN is zero.")
183 (col, minimum)
184 Lisp_Object col, minimum;
185 {
186 int mincol;
187 register int fromcol;
188 register int tab_width = XINT (current_buffer->tab_width);
189
190 CHECK_NUMBER (col, 0);
191 if (NULL (minimum))
192 XFASTINT (minimum) = 0;
193 CHECK_NUMBER (minimum, 1);
194
195 fromcol = current_column ();
196 mincol = fromcol + XINT (minimum);
197 if (mincol < XINT (col)) mincol = XINT (col);
198
199 if (fromcol == mincol)
200 return make_number (mincol);
201
202 if (tab_width <= 0 || tab_width > 20) tab_width = 8;
203
204 if (indent_tabs_mode)
205 {
206 Lisp_Object n;
207 XFASTINT (n) = mincol / tab_width - fromcol / tab_width;
208 if (XFASTINT (n) != 0)
209 {
210 Finsert_char (make_number ('\t'), n);
211
212 fromcol = (mincol / tab_width) * tab_width;
213 }
214 }
215
216 XFASTINT (col) = mincol - fromcol;
217 Finsert_char (make_number (' '), col);
218
219 last_known_column = mincol;
220 last_known_column_point = point;
221 last_known_column_modified = MODIFF;
222
223 XSETINT (col, mincol);
224 return col;
225 }
226 \f
227 DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
228 0, 0, 0,
229 "Return the indentation of the current line.\n\
230 This is the horizontal position of the character\n\
231 following any initial whitespace.")
232 ()
233 {
234 Lisp_Object val;
235
236 XFASTINT (val) = position_indentation (find_next_newline (point, -1));
237 return val;
238 }
239
240 position_indentation (pos)
241 register int pos;
242 {
243 register int column = 0;
244 register int tab_width = XINT (current_buffer->tab_width);
245 register unsigned char *p;
246 register unsigned char *stop;
247
248 if (tab_width <= 0 || tab_width > 20) tab_width = 8;
249
250 stop = &FETCH_CHAR (BUFFER_CEILING_OF (pos)) + 1;
251 p = &FETCH_CHAR (pos);
252 while (1)
253 {
254 while (p == stop)
255 {
256 if (pos == ZV)
257 return column;
258 pos += p - &FETCH_CHAR (pos);
259 p = &FETCH_CHAR (pos);
260 stop = &FETCH_CHAR (BUFFER_CEILING_OF (pos)) + 1;
261 }
262 switch (*p++)
263 {
264 case ' ':
265 column++;
266 break;
267 case '\t':
268 column += tab_width - column % tab_width;
269 break;
270 default:
271 return column;
272 }
273 }
274 }
275 \f
276 DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, 0,
277 "Move point to column COLUMN in the current line.\n\
278 The column of a character is calculated by adding together the widths\n\
279 as displayed of the previous characters in the line.\n\
280 This function ignores line-continuation;\n\
281 there is no upper limit on the column number a character can have\n\
282 and horizontal scrolling has no effect.\n\n\
283 If specified column is within a character, point goes after that character.\n\
284 If it's past end of line, point goes to end of line.\n\n\
285 A non-nil second (optional) argument FORCE means, if the line\n\
286 is too short to reach column COLUMN then add spaces/tabs to get there,\n\
287 and 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);
296 register int ctl_arrow = !NULL (current_buffer->ctl_arrow);
297 register struct Lisp_Vector *dp = buffer_display_table ();
298
299 Lisp_Object val;
300 int prev_col;
301 int c;
302
303 if (tab_width <= 0 || tab_width > 20) tab_width = 8;
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 }
333 else if (dp != 0 && XTYPE (DISP_CHAR_ROPE (dp, c)) == Lisp_String)
334 col += XSTRING (DISP_CHAR_ROPE (dp, c))->size / sizeof (GLYPH);
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. */
347 if (!NULL (force) && col > goal && c == '\t' && prev_col < goal)
348 {
349 del_range (point - 1, point);
350 Findent_to (make_number (col - 1));
351 insert_char (' ');
352 goto retry;
353 }
354
355 /* If line ends prematurely, add space to the end. */
356 if (col < goal && !NULL (force))
357 Findent_to (make_number (col = goal));
358
359 last_known_column = col;
360 last_known_column_point = point;
361 last_known_column_modified = MODIFF;
362
363 XFASTINT (val) = col;
364 return val;
365 }
366 \f
367 struct position val_compute_motion;
368
369 /* Scan the current buffer forward from offset FROM, pretending that
370 this is at line FROMVPOS, column FROMHPOS, until reaching buffer
371 offset TO or line TOVPOS, column TOHPOS (whichever comes first),
372 and return the ending buffer position and screen location.
373
374 WIDTH is the number of columns available to display text;
375 compute_motion uses this to handle continuation lines and such.
376 HSCROLL is the number of columns not being displayed at the left
377 margin; this is usually taken from a window's hscroll member.
378 TAB_OFFSET is a mysterious value, perhaps the number of columns of
379 the first tab that aren't being displayed, perhaps because of a
380 continuation line or something.
381
382 compute_motion returns a pointer to a struct position. The bufpos
383 member gives the buffer position at the end of the scan, and hpos
384 and vpos give its cartesian location. I'm not clear on what the
385 other members are.
386
387 For example, to find the buffer position of column COL of line LINE
388 of a certain window, pass the window's starting location as FROM
389 and the window's upper-left coordinates as FROMVPOS and FROMHPOS.
390 Pass the buffer's ZV as TO, to limit the scan to the end of the
391 visible section of the buffer, and pass LINE and COL as TOVPOS and
392 TOHPOS.
393
394 When displaying in window w, a typical formula for WIDTH is:
395
396 window_width - 1
397 - (window_width + window_left != screen_width)
398
399 where
400 window_width is XFASTINT (w->width),
401 window_left is XFASTINT (w->left),
402 and screen_width = SCREEN_WIDTH (XSCREEN (window->screen))
403
404 This accounts for the continuation-line backslashes, and the window
405 borders if the window is split vertically. */
406
407 struct position *
408 compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, tab_offset)
409 int from, fromvpos, fromhpos, to, tovpos, tohpos;
410 register int width;
411 int hscroll, tab_offset;
412 {
413 /* Note that `cpos' is CURRENT_VPOS << SHORTBITS + CURRENT_HPOS,
414 and that CURRENT_HPOS may be negative. Use these macros
415 to extract the hpos or the vpos from cpos or anything like it.
416 */
417 #ifndef SHORT_CAST_BUG
418 #define HPOS(VAR) (short) (VAR)
419 #else
420 #define HPOS(VAR) (((VAR) & (1 << (SHORTBITS - 1)) \
421 ? ~((1 << SHORTBITS) - 1) : 0) \
422 | (VAR) & ((1 << SHORTBITS) - 1))
423 /* #define HPOS(VAR) (((VAR) & 0x8000 ? 0xffff0000 : 0) | ((VAR) & 0xffff)) */
424 #endif /* SHORT_CAST_BUG */
425
426 #define VPOS(VAR) (((VAR) >> SHORTBITS) + (HPOS (VAR) < 0))
427
428
429 #ifndef TAHOE_REGISTER_BUG
430 register
431 #endif /* TAHOE_REGISTER_BUG */
432 int cpos = fromhpos + (fromvpos << SHORTBITS);
433 register int target = tohpos + (tovpos << SHORTBITS);
434 register int pos;
435 register int c;
436 register int tab_width = XFASTINT (current_buffer->tab_width);
437 register int ctl_arrow = !NULL (current_buffer->ctl_arrow);
438 register struct Lisp_Vector *dp = buffer_display_table ();
439 int selective
440 = XTYPE (current_buffer->selective_display) == Lisp_Int
441 ? XINT (current_buffer->selective_display)
442 : !NULL (current_buffer->selective_display) ? -1 : 0;
443 int prevpos;
444 int selective_rlen
445 = (selective && dp && XTYPE (DISP_INVIS_ROPE (dp)) == Lisp_String
446 ? XSTRING (DISP_INVIS_ROPE (dp))->size / sizeof (GLYPH) : 0);
447
448 if (tab_width <= 0 || tab_width > 20) tab_width = 8;
449 for (pos = from; pos < to && cpos < target; pos++)
450 {
451 prevpos = cpos;
452 c = FETCH_CHAR (pos);
453 if (c >= 040 && c < 0177
454 && (dp == 0 || XTYPE (DISP_CHAR_ROPE (dp, c)) != Lisp_String))
455 cpos++;
456 else if (c == '\t')
457 {
458 cpos += tab_width
459 - HPOS (cpos + tab_offset + hscroll - (hscroll > 0)
460 /* Add tab_width here to make sure positive.
461 cpos can be negative after continuation
462 but can't be less than -tab_width. */
463 + tab_width)
464 % tab_width;
465 }
466 else if (c == '\n')
467 {
468 if (selective > 0 && position_indentation (pos + 1) >= selective)
469 {
470 /* Skip any number of invisible lines all at once */
471 do
472 {
473 while (++pos < to && FETCH_CHAR(pos) != '\n');
474 }
475 while (selective > 0 && position_indentation (pos + 1) >= selective);
476 pos--;
477 /* Allow for the " ..." that is displayed for them. */
478 if (selective_rlen)
479 {
480 cpos += selective_rlen;
481 if (HPOS (cpos) >= width)
482 cpos -= HPOS (cpos) - width;
483 }
484 }
485 else
486 cpos += (1 << SHORTBITS) - HPOS (cpos);
487 cpos -= hscroll;
488 if (hscroll > 0) cpos++; /* Count the ! on column 0 */
489 tab_offset = 0;
490 }
491 else if (c == CR && selective < 0)
492 {
493 /* In selective display mode,
494 everything from a ^M to the end of the line is invisible */
495 while (pos < to && FETCH_CHAR(pos) != '\n') pos++;
496 pos--;
497 /* Allow for the " ..." that is displayed for them. */
498 if (selective_rlen)
499 {
500 cpos += selective_rlen;
501 if (HPOS (cpos) >= width)
502 cpos -= HPOS (cpos) - width;
503 }
504 }
505 else if (dp != 0 && XTYPE (DISP_CHAR_ROPE (dp, c)) == Lisp_String)
506 cpos += XSTRING (DISP_CHAR_ROPE (dp, c))->size / sizeof (GLYPH);
507 else
508 cpos += (ctl_arrow && c < 0200) ? 2 : 4;
509
510 if (HPOS (cpos) >= width
511 && (HPOS (cpos) > width
512 || (pos < (ZV - 1)
513 && FETCH_CHAR (pos + 1) != '\n')))
514 {
515 if (cpos >= target)
516 break;
517 if (hscroll
518 || (truncate_partial_width_windows
519 && width + 1 < SCREEN_WIDTH (selected_screen))
520 || !NULL (current_buffer->truncate_lines))
521 {
522 while (pos < to && FETCH_CHAR(pos) != '\n') pos++;
523 pos--;
524 }
525 else
526 {
527 cpos += (1 << SHORTBITS) - width;
528 tab_offset += width;
529 }
530
531 }
532 }
533
534 val_compute_motion.bufpos = pos;
535 val_compute_motion.hpos = HPOS (cpos);
536 val_compute_motion.vpos = VPOS (cpos);
537 val_compute_motion.prevhpos = HPOS (prevpos);
538
539 /* Nonzero if have just continued a line */
540 val_compute_motion.contin
541 = pos != from
542 && (val_compute_motion.vpos != VPOS (prevpos))
543 && c != '\n';
544
545 return &val_compute_motion;
546 }
547 #undef HPOS
548 #undef VPOS
549
550 \f
551 /* Return the column of position POS in window W's buffer,
552 rounded down to a multiple of the internal width of W.
553 This is the amount of indentation of position POS
554 that is not visible in its horizontal position in the window. */
555
556 int
557 pos_tab_offset (w, pos)
558 struct window *w;
559 register int pos;
560 {
561 int opoint = point;
562 int col;
563 int width = XFASTINT (w->width) - 1
564 - (XFASTINT (w->width) + XFASTINT (w->left)
565 != SCREEN_WIDTH (XSCREEN (w->screen)));
566
567 if (pos == BEGV || FETCH_CHAR (pos - 1) == '\n')
568 return 0;
569 SET_PT (pos);
570 col = current_column ();
571 SET_PT (opoint);
572 return col - (col % width);
573 }
574
575 /* start_hpos is the hpos of the first character of the buffer:
576 zero except for the minibuffer window,
577 where it is the width of the prompt. */
578
579 struct position val_vmotion;
580
581 struct position *
582 vmotion (from, vtarget, width, hscroll, window)
583 register int from, vtarget, width;
584 int hscroll;
585 Lisp_Object window;
586 {
587 struct position pos;
588 /* vpos is cumulative vertical position, changed as from is changed */
589 register int vpos = 0;
590 register int prevline;
591 register int first;
592 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
593 int selective
594 = XTYPE (current_buffer->selective_display) == Lisp_Int
595 ? XINT (current_buffer->selective_display)
596 : !NULL (current_buffer->selective_display) ? -1 : 0;
597 int start_hpos = (EQ (window, minibuf_window) ? minibuf_prompt_width : 0);
598
599 retry:
600 if (vtarget > vpos)
601 {
602 /* Moving downward is simple, but must calculate from beg of line
603 to determine hpos of starting point */
604 if (from > BEGV && FETCH_CHAR (from - 1) != '\n')
605 {
606 prevline = find_next_newline (from, -1);
607 while (selective > 0
608 && prevline > BEGV
609 && position_indentation (prevline) >= selective)
610 prevline = find_next_newline (prevline - 1, -1);
611 pos = *compute_motion (prevline, 0,
612 lmargin + (prevline == 1 ? start_hpos : 0),
613 from, 10000, 10000,
614 width, hscroll, 0);
615 }
616 else
617 {
618 pos.hpos = lmargin + (from == 1 ? start_hpos : 0);
619 pos.vpos = 0;
620 }
621 return compute_motion (from, vpos, pos.hpos,
622 ZV, vtarget, - (1 << (SHORTBITS - 1)),
623 width, hscroll, pos.vpos * width);
624 }
625
626 /* To move upward, go a line at a time until
627 we have gone at least far enough */
628
629 first = 1;
630
631 while ((vpos > vtarget || first) && from > BEGV)
632 {
633 prevline = from;
634 while (1)
635 {
636 prevline = find_next_newline (prevline - 1, -1);
637 if (prevline == BEGV
638 || selective <= 0
639 || position_indentation (prevline) < selective)
640 break;
641 }
642 pos = *compute_motion (prevline, 0,
643 lmargin + (prevline == 1 ? start_hpos : 0),
644 from, 10000, 10000,
645 width, hscroll, 0);
646 vpos -= pos.vpos;
647 first = 0;
648 from = prevline;
649 }
650
651 /* If we made exactly the desired vertical distance,
652 or if we hit beginning of buffer,
653 return point found */
654 if (vpos >= vtarget)
655 {
656 val_vmotion.bufpos = from;
657 val_vmotion.vpos = vpos;
658 val_vmotion.hpos = lmargin;
659 val_vmotion.contin = 0;
660 val_vmotion.prevhpos = 0;
661 return &val_vmotion;
662 }
663
664 /* Otherwise find the correct spot by moving down */
665 goto retry;
666 }
667
668 DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 1, 0,
669 "Move to start of screen line LINES lines down.\n\
670 If LINES is negative, this is moving up.\n\
671 Sets point to position found; this may be start of line\n\
672 or just the start of a continuation line.\n\
673 Returns number of lines moved; may be closer to zero than LINES\n\
674 if beginning or end of buffer was reached.")
675 (lines)
676 Lisp_Object lines;
677 {
678 struct position pos;
679 register struct window *w = XWINDOW (selected_window);
680 int width = XFASTINT (w->width) - 1
681 - (XFASTINT (w->width) + XFASTINT (w->left)
682 != SCREEN_WIDTH (XSCREEN (w->screen)));
683
684 CHECK_NUMBER (lines, 0);
685
686 pos = *vmotion (point, XINT (lines), width,
687 /* Not XFASTINT since perhaps could be negative */
688 XINT (w->hscroll), selected_window);
689
690 SET_PT (pos.bufpos);
691 return make_number (pos.vpos);
692 }
693 \f
694 syms_of_indent ()
695 {
696 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
697 "*Indentation can insert tabs if this is non-nil.\n\
698 Setting this variable automatically makes it local to the current buffer.");
699 indent_tabs_mode = 1;
700
701 defsubr (&Scurrent_indentation);
702 defsubr (&Sindent_to);
703 defsubr (&Scurrent_column);
704 defsubr (&Smove_to_column);
705 defsubr (&Svertical_motion);
706 }