This source file includes following definitions.
- buffer_display_table
- character_width
- disptab_matches_widthtab
- recompute_width_table
- width_run_cache_on_off
- skip_invisible
- DEFUN
- invalidate_current_column
- current_column
- check_display_width
- scan_for_column
- current_column_1
- string_display_width
- DEFUN
- position_indentation
- indented_beyond_p
- compute_motion
- vmotion
- line_number_display_width
- DEFUN
- window_column_x
- restore_window_buffer
- syms_of_indent
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
38
39
40
41
42
43 static ptrdiff_t last_known_column;
44
45
46
47 ptrdiff_t last_known_column_point;
48
49
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
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
72
73
74
75 static int
76 character_width (int c, struct Lisp_Char_Table *dp)
77 {
78 Lisp_Object elt;
79
80
81
82
83
84
85 if (dp && (elt = DISP_CHAR_VECTOR (dp, c), VECTORP (elt)))
86 return ASIZE (elt);
87
88
89 if (c == '\n' || c == '\t' || c == '\015')
90 return 0;
91
92
93 else if (c >= 040 && c < 0177)
94 return 1;
95
96
97
98
99
100
101 else
102 return 0;
103 }
104
105
106
107
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
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
142
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
158
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
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
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
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
228
229
230 overlay_limit = Fnext_overlay_change (position);
231
232
233 proplimit = Fnext_property_change (position, buffer, Qt);
234 if (XFIXNAT (overlay_limit) < XFIXNAT (proplimit))
235 proplimit = overlay_limit;
236
237
238
239 if (XFIXNAT (proplimit) > pos + 100 || XFIXNAT (proplimit) >= to)
240 *next_boundary_p = XFIXNAT (proplimit);
241
242 else
243 {
244
245 XSETFASTINT (proplimit, min (pos + 100, to));
246
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
254
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
264
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
271 if (NILP (window) ? inv_p == 1 : inv_p)
272 return *next_boundary_p;
273 return pos;
274 }
275
276
277
278
279
280
281
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:
300
301
302
303
304
305
306
307
308
309
310
311 )
312 (void)
313 {
314 Lisp_Object temp;
315
316 XSETFASTINT (temp, current_column ());
317 return temp;
318 }
319
320
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
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;
352
353
354 if (buffer_intervals (current_buffer)
355 || buffer_has_overlays ()
356 || Z != Z_BYTE)
357 return current_column_1 ();
358
359
360
361
362
363 ptr = BYTE_POS_ADDR (PT_BYTE - 1) + 1;
364
365
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
383
384 if (ptr == BEGV_ADDR)
385 break;
386
387
388 stop = BEGV_ADDR;
389 ptr = GPT_ADDR;
390
391
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
414
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
443
444
445
446
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
470
471
472
473
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
486 if (CONSP (val) && EQ (Qspace, XCAR (val)))
487 {
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
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
523
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
542
543
544
545
546
547
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
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
587
588 if (lines_truncated)
589 {
590 ptrdiff_t bolpos = scan;
591
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
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
622 while (scan < end)
623 {
624 int c;
625
626
627 while (scan == next_boundary)
628 {
629 ptrdiff_t old_scan = scan;
630
631
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
638
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
645
646
647 if (col >= goal)
648 break;
649 prev_col = col;
650 prev_pos = scan;
651 prev_bpos = scan_byte;
652
653 {
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)
660 {
661 scan = endp;
662 scan_byte = CHAR_TO_BYTE (scan);
663 continue;
664 }
665 }
666 }
667
668
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
694
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
704
705
706 charvec = DISP_CHAR_VECTOR (dp, c);
707 n = ASIZE (charvec);
708
709 for (i = 0; i < n; i++)
710 {
711
712
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
736
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
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
756
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
790
791
792
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
806
807
808
809
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
841 ptr = SDATA (string) + e;
842
843
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
883
884
885 DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
886 doc:
887
888
889
890
891
892 )
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:
938
939
940
941 )
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
963
964
965 stop = p;
966
967 start = p;
968 while (1)
969 {
970 while (p == stop)
971 {
972 ptrdiff_t stop_pos_byte;
973
974
975
976 if (p != start)
977 pos_byte = PTR_BYTE_POS (p);
978
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
992
993 stop_pos_byte = min (ceiling, next_boundary_byte);
994
995
996
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
1035
1036
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:
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072 )
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
1089
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
1100
1101
1102 SET_PT_BOTH (prev_pos, prev_bpos);
1103 Finsert_char (make_fixnum (' '), make_fixnum (goal - prev_col), Qt);
1104
1105
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
1113 col = goal;
1114 }
1115 }
1116
1117
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
1129
1130 static struct position val_compute_motion;
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
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
1218
1219 ptrdiff_t next_boundary = from;
1220
1221
1222
1223
1224
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
1231 ptrdiff_t next_width_run = from;
1232 Lisp_Object window;
1233
1234 bool multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters));
1235
1236
1237 EMACS_INT wide_column_end_hpos = 0;
1238 ptrdiff_t prev_pos;
1239 ptrdiff_t prev_pos_byte;
1240 EMACS_INT prev_hpos = 0;
1241 EMACS_INT prev_vpos = 0;
1242 EMACS_INT contin_hpos;
1243 int prev_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
1264
1265 width_table = 0;
1266
1267
1268 if (width < 0)
1269 {
1270 width = window_body_width (win, WINDOW_BODY_IN_CANONICAL_CHARS);
1271
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;
1282 #endif
1283
1284
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
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 {
1313
1314
1315
1316
1317
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
1328
1329
1330
1331 if (!did_motion)
1332
1333
1334
1335
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
1348
1349
1350
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
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
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
1435
1436 if (pos <= to)
1437 {
1438 pos = find_before_next_newline (pos, to, 1, &pos_byte);
1439 hpos = width;
1440
1441
1442
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
1453
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
1474 if (pos > to)
1475 {
1476
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
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493 if (contin_hpos && prev_hpos == 0
1494 && contin_hpos < width && !wide_column_end_hpos)
1495 {
1496
1497
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 {
1510
1511
1512
1513
1514
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)
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
1533
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
1541
1542
1543 if (common_width != 0)
1544 {
1545 ptrdiff_t run_end_hpos;
1546
1547
1548
1549 if (run_end > to)
1550 run_end = to;
1551
1552 run_end_hpos = hpos + (run_end - pos) * common_width;
1553
1554
1555
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
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
1583 else
1584 {
1585 ptrdiff_t i, n;
1586 Lisp_Object charvec;
1587
1588
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
1614 if (width_cache)
1615 {
1616
1617
1618 if (pos - 1 == width_run_end
1619 && XFIXNAT (width_table[c]) == width_run_width)
1620 width_run_end = pos;
1621
1622
1623
1624 else
1625 {
1626
1627
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
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
1658
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
1683
1684 if (pos < to)
1685 {
1686
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
1698 if (selective_rlen)
1699 {
1700 hpos += selective_rlen;
1701 if (hpos >= width)
1702 hpos = width;
1703 }
1704 dec_both (&pos, &pos_byte);
1705
1706
1707 }
1708 }
1709 else
1710 {
1711
1712 vpos++;
1713 hpos = 0;
1714 hpos -= hscroll;
1715
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
1725
1726
1727 if (pos < to)
1728 pos = find_before_next_newline (pos, to, 1, &pos_byte);
1729
1730
1731
1732 if (pos > next_boundary)
1733 next_boundary = pos;
1734
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
1745 unsigned char *ptr;
1746 int mb_bytes, mb_width;
1747
1748 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
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
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:
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830 )
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
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
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
1924 Lisp_Object text_prop_object;
1925
1926 XSETWINDOW (window, w);
1927
1928
1929
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
1938
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
1955
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
1966 1 << (SHRT_WIDTH - 1),
1967
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
1977
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
1990 }
1991
1992
1993
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
2005
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
2016 1 << (SHRT_WIDTH - 1),
2017
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
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
2053 set_buffer_internal_1 (XBUFFER (w->contents));
2054
2055
2056
2057
2058
2059
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
2074
2075
2076
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:
2091
2092
2093
2094
2095
2096
2097
2098
2099 )
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
2116
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
2124 if (! (INT_MIN <= x && x <= INT_MAX))
2125 args_out_of_range (window, column);
2126
2127 return x;
2128 }
2129
2130
2131
2132
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:
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189 )
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
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
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
2249
2250
2251
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
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
2275
2276
2277 it.area == TEXT_AREA
2278 && it.string_from_display_prop_p
2279
2280
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
2293
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
2305
2306
2307 reseat_at_previous_visible_line_start (&it);
2308 it.current_x = it.hpos = 0;
2309 }
2310 if (IT_CHARPOS (it) != PT)
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
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
2331
2332
2333
2334
2335 if (IT_CHARPOS (it) > it_start)
2336 {
2337
2338
2339
2340
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
2349
2350
2351
2352 it_overshoot_count = 0;
2353 }
2354 else if (disp_string_at_start_p && it.vpos > 0)
2355 {
2356
2357
2358
2359
2360 it_overshoot_count = it.vpos;
2361 }
2362
2363
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
2377
2378
2379
2380
2381 nlines++;
2382
2383
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
2397
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
2411
2412
2413
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
2434 {
2435 it.vpos = 0;
2436 it.current_y = 0;
2437 move_it_by_lines (&it, min (PTRDIFF_MAX, nlines));
2438
2439
2440
2441 if (IT_CHARPOS (it) == CHARPOS (pt) && CHARPOS (pt) == it_start)
2442 it.vpos = 0;
2443 }
2444 }
2445
2446
2447
2448
2449 if (!NILP (lcols))
2450 {
2451 move_it_in_display_line (&it, ZV, first_x + to_x, MOVE_TO_X);
2452
2453
2454
2455
2456
2457
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
2482
2483 void
2484 syms_of_indent (void)
2485 {
2486 DEFVAR_BOOL ("indent-tabs-mode", indent_tabs_mode,
2487 doc: );
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 }