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