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