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