Mercurial > emacs
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, |