comparison src/indent.c @ 11853:6578a356c540

(compute_motion): Handle overlay strings. New arg DID_MOTION. All callers changed.
author Karl Heuer <kwzh@gnu.org>
date Thu, 18 May 1995 22:43:03 +0000
parents 5b7a7c92323d
children 73e305c8239b
comparison
equal deleted inserted replaced
11852:35b170692e4a 11853:6578a356c540
574 offset TO or line TOVPOS, column TOHPOS (whichever comes first), 574 offset TO or line TOVPOS, column TOHPOS (whichever comes first),
575 and return the ending buffer position and screen location. If we 575 and return the ending buffer position and screen location. If we
576 can't hit the requested column exactly (because of a tab or other 576 can't hit the requested column exactly (because of a tab or other
577 multi-column character), overshoot. 577 multi-column character), overshoot.
578 578
579 DID_MOTION is 1 if FROMHPOS has already accounted for overlay strings
580 at FROM. This is the case if FROMVPOS and FROMVPOS came from an
581 earlier call to compute_motion. The other common case is that FROMHPOS
582 is zero and FROM is a position that "belongs" at column zero, but might
583 be shifted by overlay strings; in this case DID_MOTION should be 0.
584
579 WIDTH is the number of columns available to display text; 585 WIDTH is the number of columns available to display text;
580 compute_motion uses this to handle continuation lines and such. 586 compute_motion uses this to handle continuation lines and such.
581 HSCROLL is the number of columns not being displayed at the left 587 HSCROLL is the number of columns not being displayed at the left
582 margin; this is usually taken from a window's hscroll member. 588 margin; this is usually taken from a window's hscroll member.
583 TAB_OFFSET is the number of columns of the first tab that aren't 589 TAB_OFFSET is the number of columns of the first tab that aren't
627 The `-1' accounts for the continuation-line backslashes; the rest 633 The `-1' accounts for the continuation-line backslashes; the rest
628 accounts for window borders if the window is split horizontally, and 634 accounts for window borders if the window is split horizontally, and
629 the scroll bars if they are turned on. */ 635 the scroll bars if they are turned on. */
630 636
631 struct position * 637 struct position *
632 compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, tab_offset, win) 638 compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, hscroll, tab_offset, win)
633 int from, fromvpos, fromhpos, to, tovpos, tohpos; 639 int from, fromvpos, fromhpos, to, tovpos, tohpos;
640 int did_motion;
634 register int width; 641 register int width;
635 int hscroll, tab_offset; 642 int hscroll, tab_offset;
636 struct window *win; 643 struct window *win;
637 { 644 {
638 register int hpos = fromhpos; 645 register int hpos = fromhpos;
649 : !NILP (current_buffer->selective_display) ? -1 : 0); 656 : !NILP (current_buffer->selective_display) ? -1 : 0);
650 int prev_vpos = vpos, prev_hpos = 0; 657 int prev_vpos = vpos, prev_hpos = 0;
651 int selective_rlen 658 int selective_rlen
652 = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp)) 659 = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
653 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0); 660 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0);
654 #ifdef USE_TEXT_PROPERTIES 661 /* The next location where the `invisible' property changes, or an
655 /* The next location where the `invisible' property changes */ 662 overlay starts or ends. */
656 int next_invisible = from; 663 int next_boundary = from;
657 Lisp_Object prop, position;
658 #endif
659 664
660 /* For computing runs of characters with similar widths. 665 /* For computing runs of characters with similar widths.
661 Invariant: width_run_width is zero, or all the characters 666 Invariant: width_run_width is zero, or all the characters
662 from width_run_start to width_run_end have a fixed width of 667 from width_run_start to width_run_end have a fixed width of
663 width_run_width. */ 668 width_run_width. */
681 /* If the window has its own display table, we can't use the width 686 /* If the window has its own display table, we can't use the width
682 run cache, because that's based on the buffer's display table. */ 687 run cache, because that's based on the buffer's display table. */
683 width_table = 0; 688 width_table = 0;
684 689
685 if (tab_width <= 0 || tab_width > 1000) tab_width = 8; 690 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
686 for (pos = from; pos < to; ) 691
687 { 692 pos = from;
688 /* Stop if past the target screen position. */ 693 while (1)
689 if (vpos > tovpos 694 {
690 || (vpos == tovpos && hpos >= tohpos)) 695 while (pos == next_boundary)
691 break;
692
693 prev_vpos = vpos;
694 prev_hpos = hpos;
695
696 #ifdef USE_TEXT_PROPERTIES
697 /* if the `invisible' property is set, we can skip to
698 the next property change */
699 while (pos == next_invisible && pos < to)
700 { 696 {
701 XSETFASTINT (position, pos); 697 /* If the caller says that the screen position came from an earlier
702 698 call to compute_motion, then we've already accounted for the
703 /* Give faster response for overlay lookup near POS. */ 699 overlay strings at point. This is only true the first time
704 recenter_overlay_lists (current_buffer, pos); 700 through, so clear the flag after testing it. */
705 701 if (!did_motion)
706 prop = Fget_char_property (position, 702 /* We need to skip past the overlay strings. Currently those
707 Qinvisible, 703 strings must contain single-column printing characters;
708 Fcurrent_buffer ()); 704 if we want to relax that restriction, something will have
705 to be changed here. */
706 hpos += overlay_strings (pos, win, (char **)0);
707 did_motion = 0;
708
709 if (pos >= to)
710 break;
711
709 { 712 {
710 Lisp_Object end, limit, proplimit; 713 Lisp_Object prop, position, end, limit, proplimit;
714
715 XSETFASTINT (position, pos);
716
717 /* Give faster response for overlay lookup near POS. */
718 recenter_overlay_lists (current_buffer, pos);
711 719
712 /* We must not advance farther than the next overlay change. 720 /* We must not advance farther than the next overlay change.
713 The overlay change might change the invisible property; 721 The overlay change might change the invisible property;
714 we have no way of telling. */ 722 or there might be overlay strings to be displayed there. */
715 limit = Fnext_overlay_change (position); 723 limit = Fnext_overlay_change (position);
716 /* As for text properties, this gives a lower bound 724 /* As for text properties, this gives a lower bound
717 for where the invisible text property could change. */ 725 for where the invisible text property could change. */
718 proplimit = Fnext_property_change (position, buffer, Qt); 726 proplimit = Fnext_property_change (position, buffer, Qt);
719 if (XFASTINT (limit) < XFASTINT (proplimit)) 727 if (XFASTINT (limit) < XFASTINT (proplimit))
720 proplimit = limit; 728 proplimit = limit;
721 /* PROPLIMIT is now a lower bound for the next change 729 /* PROPLIMIT is now a lower bound for the next change
722 in invisible status. If that is plenty far away, 730 in invisible status. If that is plenty far away,
723 use that lower bound. */ 731 use that lower bound. */
724 if (XFASTINT (proplimit) > pos + 100 || XFASTINT (proplimit) >= to) 732 if (XFASTINT (proplimit) > pos + 100 || XFASTINT (proplimit) >= to)
725 next_invisible = XINT (proplimit); 733 next_boundary = XFASTINT (proplimit);
726 /* Otherwise, scan for the next `invisible' property change. */ 734 /* Otherwise, scan for the next `invisible' property change. */
727 else 735 else
728 { 736 {
729 /* Don't scan terribly far. */ 737 /* Don't scan terribly far. */
730 XSETFASTINT (proplimit, min (pos + 100, to)); 738 XSETFASTINT (proplimit, min (pos + 100, to));
731 /* No matter what. don't go past next overlay change. */ 739 /* No matter what. don't go past next overlay change. */
732 if (XFASTINT (limit) < XFASTINT (proplimit)) 740 if (XFASTINT (limit) < XFASTINT (proplimit))
733 proplimit = limit; 741 proplimit = limit;
734 end = Fnext_single_property_change (position, Qinvisible, 742 end = Fnext_single_property_change (position, Qinvisible,
735 buffer, proplimit); 743 buffer, proplimit);
736 if (INTEGERP (end) && XINT (end) < to) 744 next_boundary = XFASTINT (end);
737 next_invisible = XINT (end);
738 else
739 next_invisible = to;
740 } 745 }
746 /* if the `invisible' property is set, we can skip to
747 the next property change */
748 prop = Fget_char_property (position, Qinvisible,
749 Fcurrent_buffer ());
741 if (TEXT_PROP_MEANS_INVISIBLE (prop)) 750 if (TEXT_PROP_MEANS_INVISIBLE (prop))
742 pos = next_invisible; 751 pos = next_boundary;
743 } 752 }
744 } 753 }
754
755 /* Handle right margin. */
756 if (hpos >= width
757 && (hpos > width
758 || (pos < ZV && FETCH_CHAR (pos) != '\n')))
759 {
760 if (hscroll
761 || (truncate_partial_width_windows
762 && width + 1 < FRAME_WIDTH (XFRAME (WINDOW_FRAME (win))))
763 || !NILP (current_buffer->truncate_lines))
764 {
765 /* Truncating: skip to newline. */
766 pos = find_before_next_newline (pos, to, 1);
767 hpos = width;
768 }
769 else
770 {
771 /* Continuing. */
772 vpos += hpos / width;
773 tab_offset += hpos - hpos % width;
774 hpos %= width;
775 }
776 }
777
778 /* Stop if past the target buffer position or screen position. */
745 if (pos >= to) 779 if (pos >= to)
746 break; 780 break;
747 #endif 781 if (vpos > tovpos || (vpos == tovpos && hpos >= tohpos))
782 break;
783
784 prev_vpos = vpos;
785 prev_hpos = hpos;
748 786
749 /* Consult the width run cache to see if we can avoid inspecting 787 /* Consult the width run cache to see if we can avoid inspecting
750 the text character-by-character. */ 788 the text character-by-character. */
751 if (current_buffer->width_run_cache && pos >= next_width_run) 789 if (current_buffer->width_run_cache && pos >= next_width_run)
752 { 790 {
794 next_width_run = run_end + 1; 832 next_width_run = run_end + 1;
795 } 833 }
796 834
797 /* We have to scan the text character-by-character. */ 835 /* We have to scan the text character-by-character. */
798 else 836 else
799 { 837 {
800 c = FETCH_CHAR (pos); 838 c = FETCH_CHAR (pos);
801 pos++; 839 pos++;
802 840
803 /* Perhaps add some info to the width_run_cache. */ 841 /* Perhaps add some info to the width_run_cache. */
804 if (current_buffer->width_run_cache) 842 if (current_buffer->width_run_cache)
805 { 843 {
806 /* Is this character part of the current run? If so, extend 844 /* Is this character part of the current run? If so, extend
807 the run. */ 845 the run. */
808 if (pos - 1 == width_run_end 846 if (pos - 1 == width_run_end
809 && width_table[c] == width_run_width) 847 && width_table[c] == width_run_width)
810 width_run_end = pos; 848 width_run_end = pos;
811 849
812 /* The previous run is over, since this is a character at a 850 /* The previous run is over, since this is a character at a
813 different position, or a different width. */ 851 different position, or a different width. */
814 else 852 else
815 { 853 {
816 /* Have we accumulated a run to put in the cache? 854 /* Have we accumulated a run to put in the cache?
817 (Currently, we only cache runs of width == 1). */ 855 (Currently, we only cache runs of width == 1). */
818 if (width_run_start < width_run_end 856 if (width_run_start < width_run_end
819 && width_run_width == 1) 857 && width_run_width == 1)
820 know_region_cache (current_buffer, 858 know_region_cache (current_buffer,
821 current_buffer->width_run_cache, 859 current_buffer->width_run_cache,
822 width_run_start, width_run_end); 860 width_run_start, width_run_end);
823 861
824 /* Start recording a new width run. */ 862 /* Start recording a new width run. */
825 width_run_width = width_table[c]; 863 width_run_width = width_table[c];
826 width_run_start = pos - 1; 864 width_run_start = pos - 1;
827 width_run_end = pos; 865 width_run_end = pos;
828 } 866 }
829 } 867 }
830 868
831 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c))) 869 if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
832 hpos += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size; 870 hpos += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
833 else if (c >= 040 && c < 0177) 871 else if (c >= 040 && c < 0177)
834 hpos++; 872 hpos++;
835 else if (c == '\t') 873 else if (c == '\t')
836 { 874 {
837 hpos += tab_width - ((hpos + tab_offset + hscroll - (hscroll > 0) 875 int tem = (hpos + tab_offset + hscroll - (hscroll > 0)) % tab_width;
838 /* Add tab_width here to make sure 876 if (tem < 0)
839 positive. hpos can be negative 877 tem += tab_width;
840 after continuation but can't be 878 hpos += tab_width - tem;
841 less than -tab_width. */ 879 }
842 + tab_width) 880 else if (c == '\n')
843 % tab_width); 881 {
844 } 882 if (selective > 0 && indented_beyond_p (pos, selective))
845 else if (c == '\n') 883 {
846 { 884 /* Skip any number of invisible lines all at once */
847 if (selective > 0 && indented_beyond_p (pos, selective)) 885 do
848 { 886 pos = find_before_next_newline (pos, to, 1) + 1;
849 /* Skip any number of invisible lines all at once */ 887 while (pos < to
850 do 888 && indented_beyond_p (pos, selective));
851 pos = find_before_next_newline (pos, to, 1) + 1; 889 /* Allow for the " ..." that is displayed for them. */
852 while (pos < to 890 if (selective_rlen)
853 && indented_beyond_p (pos, selective)); 891 {
854 /* Allow for the " ..." that is displayed for them. */ 892 hpos += selective_rlen;
855 if (selective_rlen) 893 if (hpos >= width)
856 { 894 hpos = width;
857 hpos += selective_rlen; 895 }
858 if (hpos >= width)
859 hpos = width;
860 }
861 --pos; 896 --pos;
862 /* We have skipped the invis text, but not the 897 /* We have skipped the invis text, but not the
863 newline after. */ 898 newline after. */
864 } 899 }
865 else 900 else
866 { 901 {
867 /* A visible line. */ 902 /* A visible line. */
868 vpos++; 903 vpos++;
869 hpos = 0; 904 hpos = 0;
870 hpos -= hscroll; 905 hpos -= hscroll;
871 /* Count the truncation glyph on column 0 */ 906 /* Count the truncation glyph on column 0 */
872 if (hscroll > 0) 907 if (hscroll > 0)
873 hpos++; 908 hpos++;
874 tab_offset = 0; 909 tab_offset = 0;
875 } 910 }
876 } 911 }
877 else if (c == CR && selective < 0) 912 else if (c == CR && selective < 0)
878 {
879 /* In selective display mode,
880 everything from a ^M to the end of the line is invisible.
881 Stop *before* the real newline. */
882 pos = find_before_next_newline (pos, to, 1);
883 /* Allow for the " ..." that is displayed for them. */
884 if (selective_rlen)
885 {
886 hpos += selective_rlen;
887 if (hpos >= width)
888 hpos = width;
889 }
890 }
891 else
892 hpos += (ctl_arrow && c < 0200) ? 2 : 4;
893 }
894
895 /* Handle right margin. */
896 if (hpos >= width
897 && (hpos > width
898 || (pos < ZV
899 && FETCH_CHAR (pos) != '\n')))
900 {
901 if (vpos > tovpos
902 || (vpos == tovpos && hpos >= tohpos))
903 break;
904 if (hscroll
905 || (truncate_partial_width_windows
906 && width + 1 < FRAME_WIDTH (XFRAME (WINDOW_FRAME (win))))
907 || !NILP (current_buffer->truncate_lines))
908 { 913 {
909 /* Truncating: skip to newline. */ 914 /* In selective display mode,
910 pos = find_before_next_newline (pos, to, 1); 915 everything from a ^M to the end of the line is invisible.
911 hpos = width; 916 Stop *before* the real newline. */
917 pos = find_before_next_newline (pos, to, 1);
918 /* Allow for the " ..." that is displayed for them. */
919 if (selective_rlen)
920 {
921 hpos += selective_rlen;
922 if (hpos >= width)
923 hpos = width;
924 }
912 } 925 }
913 else 926 else
914 { 927 hpos += (ctl_arrow && c < 0200) ? 2 : 4;
915 /* Continuing. */
916 vpos++;
917 hpos -= width;
918 tab_offset += width;
919 }
920
921 } 928 }
922 } 929 }
923 930
924 /* Remember any final width run in the cache. */ 931 /* Remember any final width run in the cache. */
925 if (current_buffer->width_run_cache 932 if (current_buffer->width_run_cache
1020 window = Fselected_window (); 1027 window = Fselected_window ();
1021 else 1028 else
1022 CHECK_LIVE_WINDOW (window, 0); 1029 CHECK_LIVE_WINDOW (window, 0);
1023 1030
1024 pos = compute_motion (XINT (from), XINT (XCONS (frompos)->cdr), 1031 pos = compute_motion (XINT (from), XINT (XCONS (frompos)->cdr),
1025 XINT (XCONS (frompos)->car), 1032 XINT (XCONS (frompos)->car), 0,
1026 XINT (to), XINT (XCONS (topos)->cdr), 1033 XINT (to), XINT (XCONS (topos)->cdr),
1027 XINT (XCONS (topos)->car), 1034 XINT (XCONS (topos)->car),
1028 XINT (width), hscroll, tab_offset, 1035 XINT (width), hscroll, tab_offset,
1029 XWINDOW (window)); 1036 XWINDOW (window));
1030 1037
1084 = (INTEGERP (current_buffer->selective_display) 1091 = (INTEGERP (current_buffer->selective_display)
1085 ? XINT (current_buffer->selective_display) 1092 ? XINT (current_buffer->selective_display)
1086 : !NILP (current_buffer->selective_display) ? -1 : 0); 1093 : !NILP (current_buffer->selective_display) ? -1 : 0);
1087 Lisp_Object window; 1094 Lisp_Object window;
1088 int start_hpos = 0; 1095 int start_hpos = 0;
1096 int did_motion;
1089 1097
1090 XSETWINDOW (window, w); 1098 XSETWINDOW (window, w);
1091 1099
1092 /* The omission of the clause 1100 /* The omission of the clause
1093 && marker_position (w->start) == BEG 1101 && marker_position (w->start) == BEG
1129 find_next_newline_no_quit (XFASTINT (prevline) - 1, 1137 find_next_newline_no_quit (XFASTINT (prevline) - 1,
1130 -1)); 1138 -1));
1131 pos = *compute_motion (XFASTINT (prevline), 0, 1139 pos = *compute_motion (XFASTINT (prevline), 0,
1132 lmargin + (XFASTINT (prevline) == BEG 1140 lmargin + (XFASTINT (prevline) == BEG
1133 ? start_hpos : 0), 1141 ? start_hpos : 0),
1142 0,
1134 from, 1 << (INTBITS - 2), 0, 1143 from, 1 << (INTBITS - 2), 0,
1135 width, hscroll, 0, w); 1144 width, hscroll, 0, w);
1136 vpos -= pos.vpos; 1145 vpos -= pos.vpos;
1137 first = 0; 1146 first = 0;
1138 from = XFASTINT (prevline); 1147 from = XFASTINT (prevline);
1155 } 1164 }
1156 /* Moving downward is simple, but must calculate from beg of line 1165 /* Moving downward is simple, but must calculate from beg of line
1157 to determine hpos of starting point */ 1166 to determine hpos of starting point */
1158 if (from > BEGV && FETCH_CHAR (from - 1) != '\n') 1167 if (from > BEGV && FETCH_CHAR (from - 1) != '\n')
1159 { 1168 {
1160 Lisp_Object propval; 1169 Lisp_Object propval;
1161 1170
1162 XSETFASTINT (prevline, find_next_newline_no_quit (from, -1)); 1171 XSETFASTINT (prevline, find_next_newline_no_quit (from, -1));
1163 while (XFASTINT (prevline) > BEGV 1172 while (XFASTINT (prevline) > BEGV
1164 && ((selective > 0 1173 && ((selective > 0
1165 && indented_beyond_p (XFASTINT (prevline), selective)) 1174 && indented_beyond_p (XFASTINT (prevline), selective))
1174 find_next_newline_no_quit (XFASTINT (prevline) - 1, 1183 find_next_newline_no_quit (XFASTINT (prevline) - 1,
1175 -1)); 1184 -1));
1176 pos = *compute_motion (XFASTINT (prevline), 0, 1185 pos = *compute_motion (XFASTINT (prevline), 0,
1177 lmargin + (XFASTINT (prevline) == BEG 1186 lmargin + (XFASTINT (prevline) == BEG
1178 ? start_hpos : 0), 1187 ? start_hpos : 0),
1188 0,
1179 from, 1 << (INTBITS - 2), 0, 1189 from, 1 << (INTBITS - 2), 0,
1180 width, hscroll, 0, w); 1190 width, hscroll, 0, w);
1191 did_motion = 1;
1181 } 1192 }
1182 else 1193 else
1183 { 1194 {
1184 pos.hpos = lmargin + (from == BEG ? start_hpos : 0); 1195 pos.hpos = lmargin + (from == BEG ? start_hpos : 0);
1185 pos.vpos = 0; 1196 pos.vpos = 0;
1186 } 1197 did_motion = 0;
1187 return compute_motion (from, vpos, pos.hpos, 1198 }
1199 return compute_motion (from, vpos, pos.hpos, did_motion,
1188 ZV, vtarget, - (1 << (INTBITS - 2)), 1200 ZV, vtarget, - (1 << (INTBITS - 2)),
1189 width, hscroll, pos.vpos * width, w); 1201 width, hscroll, pos.vpos * width, w);
1190 } 1202 }
1191 1203
1192 DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 2, 0, 1204 DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 2, 0,