]> code.delx.au - gnu-emacs/blob - src/indent.c
(invalidate_current_column): Declare it as void.
[gnu-emacs] / src / indent.c
1 /* Indentation functions.
2 Copyright (C) 1985,86,87,88,93,94,95 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 2, 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, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21
22 #include <config.h>
23 #include "lisp.h"
24 #include "buffer.h"
25 #include "charset.h"
26 #include "category.h"
27 #include "indent.h"
28 #include "frame.h"
29 #include "window.h"
30 #include "termchar.h"
31 #include "termopts.h"
32 #include "disptab.h"
33 #include "intervals.h"
34 #include "region-cache.h"
35
36 /* Indentation can insert tabs if this is non-zero;
37 otherwise always uses spaces */
38 int indent_tabs_mode;
39
40 #define min(a, b) ((a) < (b) ? (a) : (b))
41 #define max(a, b) ((a) > (b) ? (a) : (b))
42
43 #define CR 015
44
45 /* These three values memoize the current column to avoid recalculation */
46 /* Some things in set last_known_column_point to -1
47 to mark the memoized value as invalid */
48 /* Last value returned by current_column */
49 int last_known_column;
50 /* Value of point when current_column was called */
51 int last_known_column_point;
52 /* Value of MODIFF when current_column was called */
53 int last_known_column_modified;
54
55 static int current_column_1 ();
56
57 /* Cache of beginning of line found by the last call of
58 current_column. */
59 int current_column_bol_cache;
60
61 /* Get the display table to use for the current buffer. */
62
63 struct Lisp_Char_Table *
64 buffer_display_table ()
65 {
66 Lisp_Object thisbuf;
67
68 thisbuf = current_buffer->display_table;
69 if (DISP_TABLE_P (thisbuf))
70 return XCHAR_TABLE (thisbuf);
71 if (DISP_TABLE_P (Vstandard_display_table))
72 return XCHAR_TABLE (Vstandard_display_table);
73 return 0;
74 }
75 \f
76 /* Width run cache considerations. */
77
78 /* Return the width of character C under display table DP. */
79
80 static int
81 character_width (c, dp)
82 int c;
83 struct Lisp_Char_Table *dp;
84 {
85 Lisp_Object elt;
86
87 /* These width computations were determined by examining the cases
88 in display_text_line. */
89
90 /* Everything can be handled by the display table, if it's
91 present and the element is right. */
92 if (dp && (elt = DISP_CHAR_VECTOR (dp, c), VECTORP (elt)))
93 return XVECTOR (elt)->size;
94
95 /* Some characters are special. */
96 if (c == '\n' || c == '\t' || c == '\015')
97 return 0;
98
99 /* Printing characters have width 1. */
100 else if (c >= 040 && c < 0177)
101 return 1;
102
103 /* Everybody else (control characters, metacharacters) has other
104 widths. We could return their actual widths here, but they
105 depend on things like ctl_arrow and crud like that, and they're
106 not very common at all. So we'll just claim we don't know their
107 widths. */
108 else
109 return 0;
110 }
111
112 /* Return true iff the display table DISPTAB specifies the same widths
113 for characters as WIDTHTAB. We use this to decide when to
114 invalidate the buffer's width_run_cache. */
115 int
116 disptab_matches_widthtab (disptab, widthtab)
117 struct Lisp_Char_Table *disptab;
118 struct Lisp_Vector *widthtab;
119 {
120 int i;
121
122 if (widthtab->size != 256)
123 abort ();
124
125 for (i = 0; i < 256; i++)
126 if (character_width (i, disptab)
127 != XFASTINT (widthtab->contents[i]))
128 return 0;
129
130 return 1;
131 }
132
133 /* Recompute BUF's width table, using the display table DISPTAB. */
134 void
135 recompute_width_table (buf, disptab)
136 struct buffer *buf;
137 struct Lisp_Char_Table *disptab;
138 {
139 int i;
140 struct Lisp_Vector *widthtab;
141
142 if (!VECTORP (buf->width_table))
143 buf->width_table = Fmake_vector (make_number (256), make_number (0));
144 widthtab = XVECTOR (buf->width_table);
145 if (widthtab->size != 256)
146 abort ();
147
148 for (i = 0; i < 256; i++)
149 XSETFASTINT (widthtab->contents[i], character_width (i, disptab));
150 }
151
152 /* Allocate or free the width run cache, as requested by the current
153 state of current_buffer's cache_long_line_scans variable. */
154 static void
155 width_run_cache_on_off ()
156 {
157 if (NILP (current_buffer->cache_long_line_scans)
158 /* And, for the moment, this feature doesn't work on multibyte
159 characters. */
160 || !NILP (current_buffer->enable_multibyte_characters))
161 {
162 /* It should be off. */
163 if (current_buffer->width_run_cache)
164 {
165 free_region_cache (current_buffer->width_run_cache);
166 current_buffer->width_run_cache = 0;
167 current_buffer->width_table = Qnil;
168 }
169 }
170 else
171 {
172 /* It should be on. */
173 if (current_buffer->width_run_cache == 0)
174 {
175 current_buffer->width_run_cache = new_region_cache ();
176 recompute_width_table (current_buffer, buffer_display_table ());
177 }
178 }
179 }
180
181 \f
182 /* Skip some invisible characters starting from POS.
183 This includes characters invisible because of text properties
184 and characters invisible because of overlays.
185
186 If position POS is followed by invisible characters,
187 skip some of them and return the position after them.
188 Otherwise return POS itself.
189
190 Set *NEXT_BOUNDARY_P to the next position at which
191 it will be necessary to call this function again.
192
193 Don't scan past TO, and don't set *NEXT_BOUNDARY_P
194 to a value greater than TO.
195
196 If WINDOW is non-nil, and this buffer is displayed in WINDOW,
197 take account of overlays that apply only in WINDOW.
198
199 We don't necessarily skip all the invisible characters after POS
200 because that could take a long time. We skip a reasonable number
201 which can be skipped quickly. If there might be more invisible
202 characters immediately following, then *NEXT_BOUNDARY_P
203 will equal the return value. */
204
205 static int
206 skip_invisible (pos, next_boundary_p, to, window)
207 int pos;
208 int *next_boundary_p;
209 int to;
210 Lisp_Object window;
211 {
212 Lisp_Object prop, position, overlay_limit, proplimit;
213 Lisp_Object buffer;
214 int end;
215
216 XSETFASTINT (position, pos);
217 XSETBUFFER (buffer, current_buffer);
218
219 /* Give faster response for overlay lookup near POS. */
220 recenter_overlay_lists (current_buffer, pos);
221
222 /* We must not advance farther than the next overlay change.
223 The overlay change might change the invisible property;
224 or there might be overlay strings to be displayed there. */
225 overlay_limit = Fnext_overlay_change (position);
226 /* As for text properties, this gives a lower bound
227 for where the invisible text property could change. */
228 proplimit = Fnext_property_change (position, buffer, Qt);
229 if (XFASTINT (overlay_limit) < XFASTINT (proplimit))
230 proplimit = overlay_limit;
231 /* PROPLIMIT is now a lower bound for the next change
232 in invisible status. If that is plenty far away,
233 use that lower bound. */
234 if (XFASTINT (proplimit) > pos + 100 || XFASTINT (proplimit) >= to)
235 *next_boundary_p = XFASTINT (proplimit);
236 /* Otherwise, scan for the next `invisible' property change. */
237 else
238 {
239 /* Don't scan terribly far. */
240 XSETFASTINT (proplimit, min (pos + 100, to));
241 /* No matter what. don't go past next overlay change. */
242 if (XFASTINT (overlay_limit) < XFASTINT (proplimit))
243 proplimit = overlay_limit;
244 end = XFASTINT (Fnext_single_property_change (position, Qinvisible,
245 buffer, proplimit));
246 /* Don't put the boundary in the middle of multibyte form if
247 there is no actual property change. */
248 if (end == pos + 100
249 && !NILP (current_buffer->enable_multibyte_characters)
250 && end < ZV)
251 while (pos < end && !CHAR_HEAD_P (POS_ADDR (end)))
252 end--;
253 *next_boundary_p = end;
254 }
255 /* if the `invisible' property is set, we can skip to
256 the next property change */
257 if (!NILP (window) && EQ (XWINDOW (window)->buffer, buffer))
258 prop = Fget_char_property (position, Qinvisible, window);
259 else
260 prop = Fget_char_property (position, Qinvisible, buffer);
261 if (TEXT_PROP_MEANS_INVISIBLE (prop))
262 return *next_boundary_p;
263 return pos;
264 }
265 \f
266 DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
267 "Return the horizontal position of point. Beginning of line is column 0.\n\
268 This is calculated by adding together the widths of all the displayed\n\
269 representations of the character between the start of the previous line\n\
270 and point. (eg control characters will have a width of 2 or 4, tabs\n\
271 will have a variable width)\n\
272 Ignores finite width of frame, which means that this function may return\n\
273 values greater than (frame-width).\n\
274 Whether the line is visible (if `selective-display' is t) has no effect;\n\
275 however, ^M is treated as end of line when `selective-display' is t.")
276 ()
277 {
278 Lisp_Object temp;
279 XSETFASTINT (temp, current_column ());
280 return temp;
281 }
282
283 /* Cancel any recorded value of the horizontal position. */
284
285 void
286 invalidate_current_column ()
287 {
288 last_known_column_point = 0;
289 }
290
291 int
292 current_column ()
293 {
294 register int col;
295 register unsigned char *ptr, *stop;
296 register int tab_seen;
297 int post_tab;
298 register int c;
299 register int tab_width = XINT (current_buffer->tab_width);
300 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
301 register struct Lisp_Char_Table *dp = buffer_display_table ();
302 int stopchar;
303
304 if (PT == last_known_column_point
305 && MODIFF == last_known_column_modified)
306 return last_known_column;
307
308 /* If the buffer has overlays, text properties, or multibyte,
309 use a more general algorithm. */
310 if (BUF_INTERVALS (current_buffer)
311 || !NILP (current_buffer->overlays_before)
312 || !NILP (current_buffer->overlays_after)
313 || !NILP (current_buffer->enable_multibyte_characters))
314 return current_column_1 (PT);
315
316 /* Scan backwards from point to the previous newline,
317 counting width. Tab characters are the only complicated case. */
318
319 /* Make a pointer for decrementing through the chars before point. */
320 ptr = POS_ADDR (PT - 1) + 1;
321 /* Make a pointer to where consecutive chars leave off,
322 going backwards from point. */
323 if (PT == BEGV)
324 stop = ptr;
325 else if (PT <= GPT || BEGV > GPT)
326 stop = BEGV_ADDR;
327 else
328 stop = GAP_END_ADDR;
329
330 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
331
332 col = 0, tab_seen = 0, post_tab = 0;
333
334 while (1)
335 {
336 if (ptr == stop)
337 {
338 /* We stopped either for the beginning of the buffer
339 or for the gap. */
340 if (ptr == BEGV_ADDR)
341 break;
342 /* It was the gap. Jump back over it. */
343 stop = BEGV_ADDR;
344 ptr = GPT_ADDR;
345 /* Check whether that brings us to beginning of buffer. */
346 if (BEGV >= GPT) break;
347 }
348
349 c = *--ptr;
350 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
351 col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
352 else if (c >= 040 && c < 0177)
353 col++;
354 else if (c == '\n'
355 || (c == '\r' && EQ (current_buffer->selective_display, Qt)))
356 {
357 ptr++;
358 break;
359 }
360 else if (c == '\t')
361 {
362 if (tab_seen)
363 col = ((col + tab_width) / tab_width) * tab_width;
364
365 post_tab += col;
366 col = 0;
367 tab_seen = 1;
368 }
369 else
370 col += (ctl_arrow && c < 0200) ? 2 : 4;
371 }
372
373 if (tab_seen)
374 {
375 col = ((col + tab_width) / tab_width) * tab_width;
376 col += post_tab;
377 }
378
379 if (ptr == BEGV_ADDR)
380 current_column_bol_cache = BEGV;
381 else
382 current_column_bol_cache = PTR_CHAR_POS (ptr);
383 last_known_column = col;
384 last_known_column_point = PT;
385 last_known_column_modified = MODIFF;
386
387 return col;
388 }
389 \f
390 /* Return the column number of position POS
391 by scanning forward from the beginning of the line.
392 This function handles characters that are invisible
393 due to text properties or overlays. */
394
395 static int
396 current_column_1 (pos)
397 int pos;
398 {
399 register int tab_width = XINT (current_buffer->tab_width);
400 register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
401 register struct Lisp_Char_Table *dp = buffer_display_table ();
402
403 /* Start the scan at the beginning of this line with column number 0. */
404 register int col = 0;
405 int scan = current_column_bol_cache = find_next_newline (pos, -1);
406 int next_boundary = scan;
407 int multibyte = !NILP (current_buffer->enable_multibyte_characters);
408
409 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
410
411 /* Scan forward to the target position. */
412 while (scan < pos)
413 {
414 int c;
415
416 /* Occasionally we may need to skip invisible text. */
417 while (scan == next_boundary)
418 {
419 /* This updates NEXT_BOUNDARY to the next place
420 where we might need to skip more invisible text. */
421 scan = skip_invisible (scan, &next_boundary, pos, Qnil);
422 if (scan >= pos)
423 goto endloop;
424 }
425
426 c = FETCH_BYTE (scan);
427 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
428 {
429 col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
430 scan++;
431 continue;
432 }
433 if (c == '\n')
434 break;
435 if (c == '\r' && EQ (current_buffer->selective_display, Qt))
436 break;
437 scan++;
438 if (c == '\t')
439 {
440 int prev_col = col;
441 col += tab_width;
442 col = col / tab_width * tab_width;
443 }
444 else if (multibyte && BASE_LEADING_CODE_P (c))
445 {
446 scan--;
447 /* Start of multi-byte form. */
448 if (c == LEADING_CODE_COMPOSITION)
449 {
450 unsigned char *ptr = POS_ADDR (scan);
451
452 int cmpchar_id = str_cmpchar_id (ptr, next_boundary - scan);
453 if (cmpchar_id >= 0)
454 {
455 scan += cmpchar_table[cmpchar_id]->len,
456 col += cmpchar_table[cmpchar_id]->width;
457 }
458 else
459 { /* invalid composite character */
460 scan++;
461 col += 4;
462 }
463 }
464 else
465 {
466 /* Here, we check that the following bytes are valid
467 constituents of multi-byte form. */
468 int len = BYTES_BY_CHAR_HEAD (c), i;
469
470 for (i = 1, scan++; i < len; i++, scan++)
471 /* We don't need range checking for PTR because there
472 are anchors (`\0') at GAP and Z. */
473 if (CHAR_HEAD_P (POS_ADDR (scan))) break;
474 if (i < len)
475 col += 4, scan -= i - 1;
476 else
477 col += WIDTH_BY_CHAR_HEAD (c);
478 }
479 }
480 else if (ctl_arrow && (c < 040 || c == 0177))
481 col += 2;
482 else if (c < 040 || c >= 0177)
483 col += 4;
484 else
485 col++;
486 }
487 endloop:
488
489 last_known_column = col;
490 last_known_column_point = PT;
491 last_known_column_modified = MODIFF;
492
493 return col;
494 }
495 \f
496 /* Return the width in columns of the part of STRING from BEG to END.
497 If BEG is nil, that stands for the beginning of STRING.
498 If END is nil, that stands for the end of STRING. */
499
500 static int
501 string_display_width (string, beg, end)
502 Lisp_Object string, beg, end;
503 {
504 register int col;
505 register unsigned char *ptr, *stop;
506 register int tab_seen;
507 int post_tab;
508 register int c;
509 register int tab_width = XINT (current_buffer->tab_width);
510 int ctl_arrow = !NILP (current_buffer->ctl_arrow);
511 register struct Lisp_Char_Table *dp = buffer_display_table ();
512 int b, e;
513
514 if (NILP (end))
515 e = XSTRING (string)->size;
516 else
517 {
518 CHECK_NUMBER (end, 0);
519 e = XINT (end);
520 }
521
522 if (NILP (beg))
523 b = 0;
524 else
525 {
526 CHECK_NUMBER (beg, 0);
527 b = XINT (beg);
528 }
529
530 /* Make a pointer for decrementing through the chars before point. */
531 ptr = XSTRING (string)->data + e;
532 /* Make a pointer to where consecutive chars leave off,
533 going backwards from point. */
534 stop = XSTRING (string)->data + b;
535
536 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
537
538 col = 0, tab_seen = 0, post_tab = 0;
539
540 while (1)
541 {
542 if (ptr == stop)
543 break;
544
545 c = *--ptr;
546 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
547 col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
548 else if (c >= 040 && c < 0177)
549 col++;
550 else if (c == '\n')
551 break;
552 else if (c == '\t')
553 {
554 if (tab_seen)
555 col = ((col + tab_width) / tab_width) * tab_width;
556
557 post_tab += col;
558 col = 0;
559 tab_seen = 1;
560 }
561 else
562 col += (ctl_arrow && c < 0200) ? 2 : 4;
563 }
564
565 if (tab_seen)
566 {
567 col = ((col + tab_width) / tab_width) * tab_width;
568 col += post_tab;
569 }
570
571 return col;
572 }
573 \f
574 DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
575 "Indent from point with tabs and spaces until COLUMN is reached.\n\
576 Optional second argument MININUM says always do at least MININUM spaces\n\
577 even if that goes past COLUMN; by default, MININUM is zero.")
578 (column, minimum)
579 Lisp_Object column, minimum;
580 {
581 int mincol;
582 register int fromcol;
583 register int tab_width = XINT (current_buffer->tab_width);
584
585 CHECK_NUMBER (column, 0);
586 if (NILP (minimum))
587 XSETFASTINT (minimum, 0);
588 CHECK_NUMBER (minimum, 1);
589
590 fromcol = current_column ();
591 mincol = fromcol + XINT (minimum);
592 if (mincol < XINT (column)) mincol = XINT (column);
593
594 if (fromcol == mincol)
595 return make_number (mincol);
596
597 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
598
599 if (indent_tabs_mode)
600 {
601 Lisp_Object n;
602 XSETFASTINT (n, mincol / tab_width - fromcol / tab_width);
603 if (XFASTINT (n) != 0)
604 {
605 Finsert_char (make_number ('\t'), n, Qt);
606
607 fromcol = (mincol / tab_width) * tab_width;
608 }
609 }
610
611 XSETFASTINT (column, mincol - fromcol);
612 Finsert_char (make_number (' '), column, Qt);
613
614 last_known_column = mincol;
615 last_known_column_point = PT;
616 last_known_column_modified = MODIFF;
617
618 XSETINT (column, mincol);
619 return column;
620 }
621
622 \f
623 DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
624 0, 0, 0,
625 "Return the indentation of the current line.\n\
626 This is the horizontal position of the character\n\
627 following any initial whitespace.")
628 ()
629 {
630 Lisp_Object val;
631
632 XSETFASTINT (val, position_indentation (find_next_newline (PT, -1)));
633 return val;
634 }
635
636 position_indentation (pos)
637 register int pos;
638 {
639 register int column = 0;
640 register int tab_width = XINT (current_buffer->tab_width);
641 register unsigned char *p;
642 register unsigned char *stop;
643 unsigned char *start;
644 int next_boundary = pos;
645 int ceiling = pos;
646
647 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
648
649 p = POS_ADDR (pos);
650 /* STOP records the value of P at which we will need
651 to think about the gap, or about invisible text,
652 or about the end of the buffer. */
653 stop = p;
654 /* START records the starting value of P. */
655 start = p;
656 while (1)
657 {
658 while (p == stop)
659 {
660 int stop_pos;
661
662 /* If we have updated P, set POS to match.
663 The first time we enter the loop, POS is already right. */
664 if (p != start)
665 pos = PTR_CHAR_POS (p);
666 /* Consider the various reasons STOP might have been set here. */
667 if (pos == ZV)
668 return column;
669 if (pos == next_boundary)
670 pos = skip_invisible (pos, &next_boundary, ZV, Qnil);
671 if (pos >= ceiling)
672 ceiling = BUFFER_CEILING_OF (pos) + 1;
673 /* Compute the next place we need to stop and think,
674 and set STOP accordingly. */
675 stop_pos = min (ceiling, next_boundary);
676 /* The -1 and +1 arrange to point at the first byte of gap
677 (if STOP_POS is the position of the gap)
678 rather than at the data after the gap. */
679
680 stop = POS_ADDR (stop_pos - 1) + 1;
681 p = POS_ADDR (pos);
682 }
683 switch (*p++)
684 {
685 case 0240:
686 if (! NILP (current_buffer->enable_multibyte_characters))
687 return column;
688 case ' ':
689 column++;
690 break;
691 case '\t':
692 column += tab_width - column % tab_width;
693 break;
694 default:
695 if (ASCII_BYTE_P (p[-1])
696 || NILP (current_buffer->enable_multibyte_characters))
697 return column;
698 {
699 int pos = PTR_CHAR_POS (p - 1);
700 int c = FETCH_MULTIBYTE_CHAR (pos);
701 if (CHAR_HAS_CATEGORY (c, ' '))
702 {
703 column++;
704 INC_POS (pos);
705 p = POS_ADDR (pos);
706 }
707 else
708 return column;
709 }
710 }
711 }
712 }
713
714 /* Test whether the line beginning at POS is indented beyond COLUMN.
715 Blank lines are treated as if they had the same indentation as the
716 preceding line. */
717 int
718 indented_beyond_p (pos, column)
719 int pos, column;
720 {
721 while (pos > BEGV && FETCH_BYTE (pos) == '\n')
722 pos = find_next_newline_no_quit (pos - 1, -1);
723 return (position_indentation (pos) >= column);
724 }
725 \f
726 DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, "p",
727 "Move point to column COLUMN in the current line.\n\
728 The column of a character is calculated by adding together the widths\n\
729 as displayed of the previous characters in the line.\n\
730 This function ignores line-continuation;\n\
731 there is no upper limit on the column number a character can have\n\
732 and horizontal scrolling has no effect.\n\
733 \n\
734 If specified column is within a character, point goes after that character.\n\
735 If it's past end of line, point goes to end of line.\n\n\
736 A non-nil second (optional) argument FORCE means, if the line\n\
737 is too short to reach column COLUMN then add spaces/tabs to get there,\n\
738 and if COLUMN is in the middle of a tab character, change it to spaces.\n\
739 \n\
740 The return value is the current column.")
741 (column, force)
742 Lisp_Object column, force;
743 {
744 register int pos;
745 register int col = current_column ();
746 register int goal;
747 register int end;
748 register int tab_width = XINT (current_buffer->tab_width);
749 register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
750 register struct Lisp_Char_Table *dp = buffer_display_table ();
751 register int multibyte = !NILP (current_buffer->enable_multibyte_characters);
752
753 Lisp_Object val;
754 int prev_col;
755 int c;
756
757 int next_boundary;
758
759 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
760 CHECK_NATNUM (column, 0);
761 goal = XINT (column);
762
763 pos = PT;
764 end = ZV;
765 next_boundary = pos;
766
767 /* If we're starting past the desired column,
768 back up to beginning of line and scan from there. */
769 if (col > goal)
770 {
771 end = pos;
772 pos = current_column_bol_cache;
773 col = 0;
774 }
775
776 while (pos < end)
777 {
778 while (pos == next_boundary)
779 {
780 pos = skip_invisible (pos, &next_boundary, end, Qnil);
781 if (pos >= end)
782 goto endloop;
783 }
784
785 /* Test reaching the goal column. We do this after skipping
786 invisible characters, so that we put point before the
787 character on which the cursor will appear. */
788 if (col >= goal)
789 break;
790
791 c = FETCH_BYTE (pos);
792 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
793 {
794 col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
795 pos++;
796 continue;
797 }
798 if (c == '\n')
799 break;
800 if (c == '\r' && EQ (current_buffer->selective_display, Qt))
801 break;
802 pos++;
803 if (c == '\t')
804 {
805 prev_col = col;
806 col += tab_width;
807 col = col / tab_width * tab_width;
808 }
809 else if (ctl_arrow && (c < 040 || c == 0177))
810 col += 2;
811 else if (c < 040 || c == 0177)
812 col += 4;
813 else if (c < 0177)
814 col++;
815 else if (multibyte && BASE_LEADING_CODE_P (c))
816 {
817 /* Start of multi-byte form. */
818 unsigned char *ptr;
819
820 pos--; /* rewind to the character head */
821 ptr = POS_ADDR (pos);
822 if (c == LEADING_CODE_COMPOSITION)
823 {
824 int cmpchar_id = str_cmpchar_id (ptr, end - pos);
825
826 if (cmpchar_id >= 0)
827 {
828 col += cmpchar_table[cmpchar_id]->width;
829 pos += cmpchar_table[cmpchar_id]->len;
830 }
831 else
832 { /* invalid composite character */
833 col += 4;
834 pos++;
835 }
836 }
837 else
838 {
839 /* Here, we check that the following bytes are valid
840 constituents of multi-byte form. */
841 int len = BYTES_BY_CHAR_HEAD (c), i;
842
843 for (i = 1, ptr++; i < len; i++, ptr++)
844 /* We don't need range checking for PTR because there
845 are anchors (`\0') both at GPT and Z. */
846 if (CHAR_HEAD_P (ptr)) break;
847 if (i < len)
848 col += 4, pos++;
849 else
850 col += WIDTH_BY_CHAR_HEAD (c), pos += i;
851 }
852 }
853 else
854 col += 4;
855 }
856 endloop:
857
858 SET_PT (pos);
859
860 /* If a tab char made us overshoot, change it to spaces
861 and scan through it again. */
862 if (!NILP (force) && col > goal && c == '\t' && prev_col < goal)
863 {
864 int old_point;
865
866 del_range (PT - 1, PT);
867 Findent_to (make_number (goal), Qnil);
868 old_point = PT;
869 Findent_to (make_number (col), Qnil);
870 SET_PT (old_point);
871 /* Set the last_known... vars consistently. */
872 col = goal;
873 }
874
875 /* If line ends prematurely, add space to the end. */
876 if (col < goal && !NILP (force))
877 Findent_to (make_number (col = goal), Qnil);
878
879 last_known_column = col;
880 last_known_column_point = PT;
881 last_known_column_modified = MODIFF;
882
883 XSETFASTINT (val, col);
884 return val;
885 }
886 \f
887 /* compute_motion: compute buffer posn given screen posn and vice versa */
888
889 struct position val_compute_motion;
890
891 /* Scan the current buffer forward from offset FROM, pretending that
892 this is at line FROMVPOS, column FROMHPOS, until reaching buffer
893 offset TO or line TOVPOS, column TOHPOS (whichever comes first),
894 and return the ending buffer position and screen location. If we
895 can't hit the requested column exactly (because of a tab or other
896 multi-column character), overshoot.
897
898 DID_MOTION is 1 if FROMHPOS has already accounted for overlay strings
899 at FROM. This is the case if FROMVPOS and FROMVPOS came from an
900 earlier call to compute_motion. The other common case is that FROMHPOS
901 is zero and FROM is a position that "belongs" at column zero, but might
902 be shifted by overlay strings; in this case DID_MOTION should be 0.
903
904 WIDTH is the number of columns available to display text;
905 compute_motion uses this to handle continuation lines and such.
906 HSCROLL is the number of columns not being displayed at the left
907 margin; this is usually taken from a window's hscroll member.
908 TAB_OFFSET is the number of columns of the first tab that aren't
909 being displayed, perhaps because of a continuation line or
910 something.
911
912 compute_motion returns a pointer to a struct position. The bufpos
913 member gives the buffer position at the end of the scan, and hpos
914 and vpos give its cartesian location. prevhpos is the column at
915 which the character before bufpos started, and contin is non-zero
916 if we reached the current line by continuing the previous.
917
918 Note that FROMHPOS and TOHPOS should be expressed in real screen
919 columns, taking HSCROLL and the truncation glyph at the left margin
920 into account. That is, beginning-of-line moves you to the hpos
921 -HSCROLL + (HSCROLL > 0).
922
923 For example, to find the buffer position of column COL of line LINE
924 of a certain window, pass the window's starting location as FROM
925 and the window's upper-left coordinates as FROMVPOS and FROMHPOS.
926 Pass the buffer's ZV as TO, to limit the scan to the end of the
927 visible section of the buffer, and pass LINE and COL as TOVPOS and
928 TOHPOS.
929
930 When displaying in window w, a typical formula for WIDTH is:
931
932 window_width - 1
933 - (has_vertical_scroll_bars
934 ? FRAME_SCROLL_BAR_COLS (XFRAME (window->frame))
935 : (window_width + window_left != frame_width))
936
937 where
938 window_width is XFASTINT (w->width),
939 window_left is XFASTINT (w->left),
940 has_vertical_scroll_bars is
941 FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (WINDOW_FRAME (window)))
942 and frame_width = FRAME_WIDTH (XFRAME (window->frame))
943
944 Or you can let window_internal_width do this all for you, and write:
945 window_internal_width (w) - 1
946
947 The `-1' accounts for the continuation-line backslashes; the rest
948 accounts for window borders if the window is split horizontally, and
949 the scroll bars if they are turned on. */
950
951 struct position *
952 compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, hscroll, tab_offset, win)
953 int from, fromvpos, fromhpos, to, tovpos, tohpos;
954 int did_motion;
955 register int width;
956 int hscroll, tab_offset;
957 struct window *win;
958 {
959 register int hpos = fromhpos;
960 register int vpos = fromvpos;
961
962 register int pos;
963 register int c;
964 register int tab_width = XFASTINT (current_buffer->tab_width);
965 register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
966 register struct Lisp_Char_Table *dp = window_display_table (win);
967 int selective
968 = (INTEGERP (current_buffer->selective_display)
969 ? XINT (current_buffer->selective_display)
970 : !NILP (current_buffer->selective_display) ? -1 : 0);
971 int prev_hpos = 0;
972 int selective_rlen
973 = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
974 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0);
975 /* The next location where the `invisible' property changes, or an
976 overlay starts or ends. */
977 int next_boundary = from;
978
979 /* For computing runs of characters with similar widths.
980 Invariant: width_run_width is zero, or all the characters
981 from width_run_start to width_run_end have a fixed width of
982 width_run_width. */
983 int width_run_start = from;
984 int width_run_end = from;
985 int width_run_width = 0;
986 Lisp_Object *width_table;
987 Lisp_Object buffer;
988
989 /* The next buffer pos where we should consult the width run cache. */
990 int next_width_run = from;
991 Lisp_Object window;
992
993 int multibyte = !NILP (current_buffer->enable_multibyte_characters);
994 int wide_column = 0; /* Set to 1 when a previous character
995 is wide-colomn. */
996 int prev_pos; /* Previous buffer position. */
997 int contin_hpos; /* HPOS of last column of continued line. */
998 int prev_tab_offset; /* Previous tab offset. */
999
1000 XSETBUFFER (buffer, current_buffer);
1001 XSETWINDOW (window, win);
1002
1003 width_run_cache_on_off ();
1004 if (dp == buffer_display_table ())
1005 width_table = (VECTORP (current_buffer->width_table)
1006 ? XVECTOR (current_buffer->width_table)->contents
1007 : 0);
1008 else
1009 /* If the window has its own display table, we can't use the width
1010 run cache, because that's based on the buffer's display table. */
1011 width_table = 0;
1012
1013 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
1014
1015 pos = prev_pos = from;
1016 contin_hpos = 0;
1017 prev_tab_offset = tab_offset;
1018 while (1)
1019 {
1020 while (pos == next_boundary)
1021 {
1022 int newpos;
1023
1024 /* If the caller says that the screen position came from an earlier
1025 call to compute_motion, then we've already accounted for the
1026 overlay strings at point. This is only true the first time
1027 through, so clear the flag after testing it. */
1028 if (!did_motion)
1029 /* We need to skip past the overlay strings. Currently those
1030 strings must not contain TAB;
1031 if we want to relax that restriction, something will have
1032 to be changed here. */
1033 {
1034 unsigned char *ovstr;
1035 int ovlen = overlay_strings (pos, win, &ovstr);
1036 hpos += (multibyte ? strwidth (ovstr, ovlen) : ovlen);
1037 }
1038 did_motion = 0;
1039
1040 if (pos >= to)
1041 break;
1042
1043 /* Advance POS past invisible characters
1044 (but not necessarily all that there are here),
1045 and store in next_boundary the next position where
1046 we need to call skip_invisible. */
1047 newpos = skip_invisible (pos, &next_boundary, to, window);
1048
1049 if (newpos >= to)
1050 goto after_loop;
1051
1052 pos = newpos;
1053 }
1054
1055 /* Handle right margin. */
1056 /* Note on a wide-column character.
1057
1058 Characters are classified into the following three categories
1059 according to the width (columns occupied on screen).
1060
1061 (1) single-column character: ex. `a'
1062 (2) multi-column character: ex. `^A', TAB, `\033'
1063 (3) wide-column character: ex. Japanese character, Chinese character
1064 (In the following example, `W_' stands for them.)
1065
1066 Multi-column characters can be divided around the right margin,
1067 but wide-column characters cannot.
1068
1069 NOTE:
1070
1071 (*) The cursor is placed on the next character after the point.
1072
1073 ----------
1074 abcdefghi\
1075 j ^---- next after the point
1076 ^--- next char. after the point.
1077 ----------
1078 In case of sigle-column character
1079
1080 ----------
1081 abcdefgh\\
1082 033 ^---- next after the point, next char. after the point.
1083 ----------
1084 In case of multi-column character
1085
1086 ----------
1087 abcdefgh\\
1088 W_ ^---- next after the point
1089 ^---- next char. after the point.
1090 ----------
1091 In case of wide-column character
1092
1093 The problem here is continuation at a wide-column character.
1094 In this case, the line may shorter less than WIDTH.
1095 And we find the continuation AFTER it occurs.
1096
1097 */
1098
1099 if (hpos > width)
1100 {
1101 if (hscroll
1102 || (truncate_partial_width_windows
1103 && width + 1 < FRAME_WIDTH (XFRAME (WINDOW_FRAME (win))))
1104 || !NILP (current_buffer->truncate_lines))
1105 {
1106 /* Truncating: skip to newline. */
1107 if (pos <= to) /* This IF is needed because we may past TO */
1108 pos = find_before_next_newline (pos, to, 1);
1109 hpos = width;
1110 /* If we just skipped next_boundary,
1111 loop around in the main while
1112 and handle it. */
1113 if (pos >= next_boundary)
1114 next_boundary = pos + 1;
1115 prev_hpos = width;
1116 prev_tab_offset = tab_offset;
1117 }
1118 else
1119 {
1120 /* Continuing. */
1121 /* Remember the previous value. */
1122 prev_tab_offset = tab_offset;
1123
1124 if (wide_column)
1125 {
1126 hpos -= prev_hpos;
1127 tab_offset += prev_hpos;
1128 }
1129 else
1130 {
1131 tab_offset += width;
1132 hpos -= width;
1133 }
1134 vpos++;
1135 contin_hpos = prev_hpos;
1136 prev_hpos = 0;
1137 }
1138 }
1139
1140 /* Stop if past the target buffer position or screen position. */
1141 if (pos > to)
1142 {
1143 /* Go back to the previous position. */
1144 pos = prev_pos;
1145 hpos = prev_hpos;
1146 tab_offset = prev_tab_offset;
1147
1148 /* NOTE on contin_hpos, hpos, and prev_hpos.
1149
1150 ----------
1151 abcdefgh\\
1152 W_ ^---- contin_hpos
1153 | ^----- hpos
1154 \---- prev_hpos
1155 ----------
1156 */
1157
1158 if (contin_hpos && prev_hpos == 0
1159 && contin_hpos < width && !wide_column)
1160 {
1161 /* Line breaking occurs in the middle of multi-column
1162 character. Go back to previous line. */
1163 hpos = contin_hpos;
1164 vpos = vpos - 1;
1165 }
1166 else if (c == '\n')
1167 /* If previous character is NEWLINE,
1168 set VPOS back to previous line */
1169 vpos = vpos - 1;
1170 break;
1171 }
1172
1173 if (vpos > tovpos || vpos == tovpos && hpos >= tohpos)
1174 {
1175 if (contin_hpos && prev_hpos == 0
1176 && ((hpos > tohpos && contin_hpos == width) || wide_column))
1177 { /* Line breaks because we can't put the character at the
1178 previous line any more. It is not the multi-column
1179 character continued in middle. Go back to previous
1180 buffer position, screen position, and set tab offset
1181 to previous value. It's the beginning of the
1182 line. */
1183 pos = prev_pos;
1184 hpos = prev_hpos;
1185 tab_offset = prev_tab_offset;
1186 }
1187 break;
1188 }
1189 if (pos == ZV) /* We cannot go beyond ZV. Stop here. */
1190 break;
1191
1192 prev_hpos = hpos;
1193 prev_pos = pos;
1194 wide_column = 0;
1195
1196 /* Consult the width run cache to see if we can avoid inspecting
1197 the text character-by-character. */
1198 if (current_buffer->width_run_cache && pos >= next_width_run)
1199 {
1200 int run_end;
1201 int common_width
1202 = region_cache_forward (current_buffer,
1203 current_buffer->width_run_cache,
1204 pos, &run_end);
1205
1206 /* A width of zero means the character's width varies (like
1207 a tab), is meaningless (like a newline), or we just don't
1208 want to skip over it for some other reason. */
1209 if (common_width != 0)
1210 {
1211 int run_end_hpos;
1212
1213 /* Don't go past the final buffer posn the user
1214 requested. */
1215 if (run_end > to)
1216 run_end = to;
1217
1218 run_end_hpos = hpos + (run_end - pos) * common_width;
1219
1220 /* Don't go past the final horizontal position the user
1221 requested. */
1222 if (vpos == tovpos && run_end_hpos > tohpos)
1223 {
1224 run_end = pos + (tohpos - hpos) / common_width;
1225 run_end_hpos = hpos + (run_end - pos) * common_width;
1226 }
1227
1228 /* Don't go past the margin. */
1229 if (run_end_hpos >= width)
1230 {
1231 run_end = pos + (width - hpos) / common_width;
1232 run_end_hpos = hpos + (run_end - pos) * common_width;
1233 }
1234
1235 hpos = run_end_hpos;
1236 if (run_end > pos)
1237 prev_hpos = hpos - common_width;
1238 pos = run_end;
1239 }
1240
1241 next_width_run = run_end + 1;
1242 }
1243
1244 /* We have to scan the text character-by-character. */
1245 else
1246 {
1247 c = FETCH_BYTE (pos);
1248 pos++;
1249
1250 /* Perhaps add some info to the width_run_cache. */
1251 if (current_buffer->width_run_cache)
1252 {
1253 /* Is this character part of the current run? If so, extend
1254 the run. */
1255 if (pos - 1 == width_run_end
1256 && XFASTINT (width_table[c]) == width_run_width)
1257 width_run_end = pos;
1258
1259 /* The previous run is over, since this is a character at a
1260 different position, or a different width. */
1261 else
1262 {
1263 /* Have we accumulated a run to put in the cache?
1264 (Currently, we only cache runs of width == 1). */
1265 if (width_run_start < width_run_end
1266 && width_run_width == 1)
1267 know_region_cache (current_buffer,
1268 current_buffer->width_run_cache,
1269 width_run_start, width_run_end);
1270
1271 /* Start recording a new width run. */
1272 width_run_width = XFASTINT (width_table[c]);
1273 width_run_start = pos - 1;
1274 width_run_end = pos;
1275 }
1276 }
1277
1278 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c))
1279 && ! (multibyte && BASE_LEADING_CODE_P (c)))
1280 hpos += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
1281 else if (c >= 040 && c < 0177)
1282 hpos++;
1283 else if (c == '\t')
1284 {
1285 int tem = (hpos + tab_offset + hscroll - (hscroll > 0)) % tab_width;
1286 if (tem < 0)
1287 tem += tab_width;
1288 hpos += tab_width - tem;
1289 }
1290 else if (c == '\n')
1291 {
1292 if (selective > 0 && indented_beyond_p (pos, selective))
1293 {
1294 /* If (pos == to), we don't have to take care of
1295 selective display. */
1296 if (pos < to)
1297 {
1298 /* Skip any number of invisible lines all at once */
1299 do
1300 pos = find_before_next_newline (pos, to, 1) + 1;
1301 while (pos < to
1302 && indented_beyond_p (pos, selective));
1303 /* Allow for the " ..." that is displayed for them. */
1304 if (selective_rlen)
1305 {
1306 hpos += selective_rlen;
1307 if (hpos >= width)
1308 hpos = width;
1309 }
1310 --pos;
1311 /* We have skipped the invis text, but not the
1312 newline after. */
1313 }
1314 }
1315 else
1316 {
1317 /* A visible line. */
1318 vpos++;
1319 hpos = 0;
1320 hpos -= hscroll;
1321 /* Count the truncation glyph on column 0 */
1322 if (hscroll > 0)
1323 hpos++;
1324 tab_offset = 0;
1325 }
1326 contin_hpos = 0;
1327 }
1328 else if (c == CR && selective < 0)
1329 {
1330 /* In selective display mode,
1331 everything from a ^M to the end of the line is invisible.
1332 Stop *before* the real newline. */
1333 if (pos < to)
1334 pos = find_before_next_newline (pos, to, 1);
1335 /* If we just skipped next_boundary,
1336 loop around in the main while
1337 and handle it. */
1338 if (pos > next_boundary)
1339 next_boundary = pos;
1340 /* Allow for the " ..." that is displayed for them. */
1341 if (selective_rlen)
1342 {
1343 hpos += selective_rlen;
1344 if (hpos >= width)
1345 hpos = width;
1346 }
1347 }
1348 else if (multibyte && BASE_LEADING_CODE_P (c))
1349 {
1350 /* Start of multi-byte form. */
1351 unsigned char *ptr;
1352 int len, actual_len;
1353
1354 pos--; /* rewind POS */
1355
1356 ptr = (((pos) >= GPT ? GAP_SIZE : 0) + (pos) + BEG_ADDR - 1);
1357 len = ((pos) >= GPT ? ZV : GPT) - (pos);
1358
1359 c = STRING_CHAR_AND_LENGTH (ptr, len, actual_len);
1360
1361 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
1362 hpos += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
1363 else if (actual_len == 1)
1364 hpos += 4;
1365 else if (COMPOSITE_CHAR_P (c))
1366 {
1367 int id = COMPOSITE_CHAR_ID (c);
1368 int width = (id < n_cmpchars) ? cmpchar_table[id]->width : 0;
1369 hpos += width;
1370 if (width > 1)
1371 wide_column = 1;
1372 }
1373 else
1374 {
1375 int width = WIDTH_BY_CHAR_HEAD (*ptr);
1376 hpos += width;
1377 if (width > 1)
1378 wide_column = 1;
1379 }
1380
1381 pos += actual_len;
1382 }
1383 else
1384 hpos += (ctl_arrow && c < 0200) ? 2 : 4;
1385 }
1386 }
1387
1388 after_loop:
1389
1390 /* Remember any final width run in the cache. */
1391 if (current_buffer->width_run_cache
1392 && width_run_width == 1
1393 && width_run_start < width_run_end)
1394 know_region_cache (current_buffer, current_buffer->width_run_cache,
1395 width_run_start, width_run_end);
1396
1397 val_compute_motion.bufpos = pos;
1398 val_compute_motion.hpos = hpos;
1399 val_compute_motion.vpos = vpos;
1400 val_compute_motion.prevhpos = prev_hpos;
1401 /* We alalways handle all of them here; none of them remain to do. */
1402 val_compute_motion.ovstring_chars_done = 0;
1403
1404 /* Nonzero if have just continued a line */
1405 val_compute_motion.contin = (contin_hpos && prev_hpos == 0);
1406
1407 return &val_compute_motion;
1408 }
1409
1410 #if 0 /* The doc string is too long for some compilers,
1411 but make-docfile can find it in this comment. */
1412 DEFUN ("compute-motion", Ffoo, Sfoo, 7, 7, 0,
1413 "Scan through the current buffer, calculating screen position.\n\
1414 Scan the current buffer forward from offset FROM,\n\
1415 assuming it is at position FROMPOS--a cons of the form (HPOS . VPOS)--\n\
1416 to position TO or position TOPOS--another cons of the form (HPOS . VPOS)--\n\
1417 and return the ending buffer position and screen location.\n\
1418 \n\
1419 There are three additional arguments:\n\
1420 \n\
1421 WIDTH is the number of columns available to display text;\n\
1422 this affects handling of continuation lines.\n\
1423 This is usually the value returned by `window-width', less one (to allow\n\
1424 for the continuation glyph).\n\
1425 \n\
1426 OFFSETS is either nil or a cons cell (HSCROLL . TAB-OFFSET).\n\
1427 HSCROLL is the number of columns not being displayed at the left\n\
1428 margin; this is usually taken from a window's hscroll member.\n\
1429 TAB-OFFSET is the number of columns of the first tab that aren't\n\
1430 being displayed, perhaps because the line was continued within it.\n\
1431 If OFFSETS is nil, HSCROLL and TAB-OFFSET are assumed to be zero.\n\
1432 \n\
1433 WINDOW is the window to operate on. It is used to choose the display table;\n\
1434 if it is showing the current buffer, it is used also for\n\
1435 deciding which overlay properties apply.\n\
1436 Note that `compute-motion' always operates on the current buffer.\n\
1437 \n\
1438 The value is a list of five elements:\n\
1439 (POS HPOS VPOS PREVHPOS CONTIN)\n\
1440 POS is the buffer position where the scan stopped.\n\
1441 VPOS is the vertical position where the scan stopped.\n\
1442 HPOS is the horizontal position where the scan stopped.\n\
1443 \n\
1444 PREVHPOS is the horizontal position one character back from POS.\n\
1445 CONTIN is t if a line was continued after (or within) the previous character.\n\
1446 \n\
1447 For example, to find the buffer position of column COL of line LINE\n\
1448 of a certain window, pass the window's starting location as FROM\n\
1449 and the window's upper-left coordinates as FROMPOS.\n\
1450 Pass the buffer's (point-max) as TO, to limit the scan to the end of the\n\
1451 visible section of the buffer, and pass LINE and COL as TOPOS.")
1452 (from, frompos, to, topos, width, offsets, window)
1453 #endif
1454
1455 DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0,
1456 0)
1457 (from, frompos, to, topos, width, offsets, window)
1458 Lisp_Object from, frompos, to, topos;
1459 Lisp_Object width, offsets, window;
1460 {
1461 Lisp_Object bufpos, hpos, vpos, prevhpos, contin;
1462 struct position *pos;
1463 int hscroll, tab_offset;
1464
1465 CHECK_NUMBER_COERCE_MARKER (from, 0);
1466 CHECK_CONS (frompos, 0);
1467 CHECK_NUMBER (XCONS (frompos)->car, 0);
1468 CHECK_NUMBER (XCONS (frompos)->cdr, 0);
1469 CHECK_NUMBER_COERCE_MARKER (to, 0);
1470 CHECK_CONS (topos, 0);
1471 CHECK_NUMBER (XCONS (topos)->car, 0);
1472 CHECK_NUMBER (XCONS (topos)->cdr, 0);
1473 CHECK_NUMBER (width, 0);
1474 if (!NILP (offsets))
1475 {
1476 CHECK_CONS (offsets, 0);
1477 CHECK_NUMBER (XCONS (offsets)->car, 0);
1478 CHECK_NUMBER (XCONS (offsets)->cdr, 0);
1479 hscroll = XINT (XCONS (offsets)->car);
1480 tab_offset = XINT (XCONS (offsets)->cdr);
1481 }
1482 else
1483 hscroll = tab_offset = 0;
1484
1485 if (NILP (window))
1486 window = Fselected_window ();
1487 else
1488 CHECK_LIVE_WINDOW (window, 0);
1489
1490 pos = compute_motion (XINT (from), XINT (XCONS (frompos)->cdr),
1491 XINT (XCONS (frompos)->car), 0,
1492 XINT (to), XINT (XCONS (topos)->cdr),
1493 XINT (XCONS (topos)->car),
1494 XINT (width), hscroll, tab_offset,
1495 XWINDOW (window));
1496
1497 XSETFASTINT (bufpos, pos->bufpos);
1498 XSETINT (hpos, pos->hpos);
1499 XSETINT (vpos, pos->vpos);
1500 XSETINT (prevhpos, pos->prevhpos);
1501
1502 return Fcons (bufpos,
1503 Fcons (hpos,
1504 Fcons (vpos,
1505 Fcons (prevhpos,
1506 Fcons (pos->contin ? Qt : Qnil, Qnil)))));
1507
1508 }
1509 \f
1510 /* Return the column of position POS in window W's buffer.
1511 The result is rounded down to a multiple of the internal width of W.
1512 This is the amount of indentation of position POS
1513 that is not visible in its horizontal position in the window. */
1514
1515 int
1516 pos_tab_offset (w, pos)
1517 struct window *w;
1518 register int pos;
1519 {
1520 int opoint = PT;
1521 int col;
1522 int width = window_internal_width (w) - 1;
1523
1524 if (pos == BEGV)
1525 return MINI_WINDOW_P (w) ? -minibuf_prompt_width : 0;
1526 if (FETCH_BYTE (pos - 1) == '\n')
1527 return 0;
1528 TEMP_SET_PT (pos);
1529 col = current_column ();
1530 TEMP_SET_PT (opoint);
1531 /* Modulo is no longer valid, as a line may get shorter than WIDTH
1532 columns by continuation of a wide-column character. Just return
1533 COL here. */
1534 #if 0
1535 /* In the continuation of the first line in a minibuffer we must
1536 take the width of the prompt into account. */
1537 if (MINI_WINDOW_P (w) && col >= width - minibuf_prompt_width
1538 && find_next_newline_no_quit (pos, -1) == BEGV)
1539 return col - (col + minibuf_prompt_width) % width;
1540 return col - (col % width);
1541 #endif
1542 return col;
1543 }
1544
1545 \f
1546 /* Fvertical_motion and vmotion */
1547 struct position val_vmotion;
1548
1549 struct position *
1550 vmotion (from, vtarget, w)
1551 register int from, vtarget;
1552 struct window *w;
1553 {
1554 int width = window_internal_width (w) - 1;
1555 int hscroll = XINT (w->hscroll);
1556 struct position pos;
1557 /* vpos is cumulative vertical position, changed as from is changed */
1558 register int vpos = 0;
1559 Lisp_Object prevline;
1560 register int first;
1561 int lmargin = hscroll > 0 ? 1 - hscroll : 0;
1562 int selective
1563 = (INTEGERP (current_buffer->selective_display)
1564 ? XINT (current_buffer->selective_display)
1565 : !NILP (current_buffer->selective_display) ? -1 : 0);
1566 Lisp_Object window;
1567 int start_hpos = 0;
1568 int did_motion;
1569
1570 XSETWINDOW (window, w);
1571
1572 /* The omission of the clause
1573 && marker_position (w->start) == BEG
1574 here is deliberate; I think we want to measure from the prompt
1575 position even if the minibuffer window has scrolled. */
1576 if (EQ (window, minibuf_window))
1577 {
1578 if (minibuf_prompt_width == 0 && STRINGP (minibuf_prompt))
1579 minibuf_prompt_width
1580 = string_display_width (minibuf_prompt, Qnil, Qnil);
1581
1582 start_hpos = minibuf_prompt_width;
1583 }
1584
1585 if (vpos >= vtarget)
1586 {
1587 /* To move upward, go a line at a time until
1588 we have gone at least far enough */
1589
1590 first = 1;
1591
1592 while ((vpos > vtarget || first) && from > BEGV)
1593 {
1594 Lisp_Object propval;
1595
1596 XSETFASTINT (prevline, find_next_newline_no_quit (from - 1, -1));
1597 while (XFASTINT (prevline) > BEGV
1598 && ((selective > 0
1599 && indented_beyond_p (XFASTINT (prevline), selective))
1600 #ifdef USE_TEXT_PROPERTIES
1601 /* watch out for newlines with `invisible' property */
1602 || (propval = Fget_char_property (prevline,
1603 Qinvisible,
1604 window),
1605 TEXT_PROP_MEANS_INVISIBLE (propval))
1606 #endif
1607 ))
1608 XSETFASTINT (prevline,
1609 find_next_newline_no_quit (XFASTINT (prevline) - 1,
1610 -1));
1611 pos = *compute_motion (XFASTINT (prevline), 0,
1612 lmargin + (XFASTINT (prevline) == BEG
1613 ? start_hpos : 0),
1614 0,
1615 from,
1616 /* Don't care for VPOS... */
1617 1 << (BITS_PER_SHORT - 1),
1618 /* ... nor HPOS. */
1619 1 << (BITS_PER_SHORT - 1),
1620 width, hscroll,
1621 /* This compensates for start_hpos
1622 so that a tab as first character
1623 still occupies 8 columns. */
1624 (XFASTINT (prevline) == BEG
1625 ? -start_hpos : 0),
1626 w);
1627 vpos -= pos.vpos;
1628 first = 0;
1629 from = XFASTINT (prevline);
1630 }
1631
1632 /* If we made exactly the desired vertical distance,
1633 or if we hit beginning of buffer,
1634 return point found */
1635 if (vpos >= vtarget)
1636 {
1637 val_vmotion.bufpos = from;
1638 val_vmotion.vpos = vpos;
1639 val_vmotion.hpos = lmargin;
1640 val_vmotion.contin = 0;
1641 val_vmotion.prevhpos = 0;
1642 val_vmotion.ovstring_chars_done = 0;
1643 val_vmotion.tab_offset = 0; /* For accumulating tab offset. */
1644 return &val_vmotion;
1645 }
1646
1647 /* Otherwise find the correct spot by moving down */
1648 }
1649 /* Moving downward is simple, but must calculate from beg of line
1650 to determine hpos of starting point */
1651 if (from > BEGV && FETCH_BYTE (from - 1) != '\n')
1652 {
1653 Lisp_Object propval;
1654
1655 XSETFASTINT (prevline, find_next_newline_no_quit (from, -1));
1656 while (XFASTINT (prevline) > BEGV
1657 && ((selective > 0
1658 && indented_beyond_p (XFASTINT (prevline), selective))
1659 #ifdef USE_TEXT_PROPERTIES
1660 /* watch out for newlines with `invisible' property */
1661 || (propval = Fget_char_property (prevline, Qinvisible,
1662 window),
1663 TEXT_PROP_MEANS_INVISIBLE (propval))
1664 #endif
1665 ))
1666 XSETFASTINT (prevline,
1667 find_next_newline_no_quit (XFASTINT (prevline) - 1,
1668 -1));
1669 pos = *compute_motion (XFASTINT (prevline), 0,
1670 lmargin + (XFASTINT (prevline) == BEG
1671 ? start_hpos : 0),
1672 0,
1673 from,
1674 /* Don't care for VPOS... */
1675 1 << (BITS_PER_SHORT - 1),
1676 /* ... nor HPOS. */
1677 1 << (BITS_PER_SHORT - 1),
1678 width, hscroll,
1679 (XFASTINT (prevline) == BEG ? -start_hpos : 0),
1680 w);
1681 did_motion = 1;
1682 }
1683 else
1684 {
1685 pos.hpos = lmargin + (from == BEG ? start_hpos : 0);
1686 pos.vpos = 0;
1687 pos.tab_offset = 0;
1688 did_motion = 0;
1689 }
1690 return compute_motion (from, vpos, pos.hpos, did_motion,
1691 ZV, vtarget, - (1 << (BITS_PER_SHORT - 1)),
1692 width, hscroll,
1693 pos.tab_offset - (from == BEG ? start_hpos : 0),
1694 w);
1695 }
1696
1697 DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 2, 0,
1698 "Move point to start of the screen line LINES lines down.\n\
1699 If LINES is negative, this means moving up.\n\
1700 \n\
1701 This function is an ordinary cursor motion function\n\
1702 which calculates the new position based on how text would be displayed.\n\
1703 The new position may be the start of a line,\n\
1704 or just the start of a continuation line.\n\
1705 The function returns number of screen lines moved over;\n\
1706 that usually equals LINES, but may be closer to zero\n\
1707 if beginning or end of buffer was reached.\n\
1708 \n\
1709 The optional second argument WINDOW specifies the window to use for\n\
1710 parameters such as width, horizontal scrolling, and so on.\n\
1711 The default is to use the selected window's parameters.\n\
1712 \n\
1713 `vertical-motion' always uses the current buffer,\n\
1714 regardless of which buffer is displayed in WINDOW.\n\
1715 This is consistent with other cursor motion functions\n\
1716 and makes it possible to use `vertical-motion' in any buffer,\n\
1717 whether or not it is currently displayed in some window.")
1718 (lines, window)
1719 Lisp_Object lines, window;
1720 {
1721 struct position pos;
1722
1723 CHECK_NUMBER (lines, 0);
1724 if (! NILP (window))
1725 CHECK_WINDOW (window, 0);
1726 else
1727 window = selected_window;
1728
1729 pos = *vmotion (PT, (int) XINT (lines), XWINDOW (window));
1730
1731 SET_PT (pos.bufpos);
1732 return make_number (pos.vpos);
1733 }
1734 \f
1735 /* file's initialization. */
1736
1737 syms_of_indent ()
1738 {
1739 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
1740 "*Indentation can insert tabs if this is non-nil.\n\
1741 Setting this variable automatically makes it local to the current buffer.");
1742 indent_tabs_mode = 1;
1743
1744 defsubr (&Scurrent_indentation);
1745 defsubr (&Sindent_to);
1746 defsubr (&Scurrent_column);
1747 defsubr (&Smove_to_column);
1748 defsubr (&Svertical_motion);
1749 defsubr (&Scompute_motion);
1750 }