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