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