diff options
Diffstat (limited to 'src/treesit.c')
| -rw-r--r-- | src/treesit.c | 433 |
1 files changed, 405 insertions, 28 deletions
diff --git a/src/treesit.c b/src/treesit.c index b0979397d35..583a01b7f38 100644 --- a/src/treesit.c +++ b/src/treesit.c | |||
| @@ -864,6 +864,176 @@ loaded or the file name couldn't be determined, return nil. */) | |||
| 864 | } | 864 | } |
| 865 | 865 | ||
| 866 | 866 | ||
| 867 | /*** Linecol functions */ | ||
| 868 | |||
| 869 | #define TREE_SITTER_DEBUG_LINECOL true | ||
| 870 | |||
| 871 | static void | ||
| 872 | treesit_print_linecol (struct ts_linecol linecol) | ||
| 873 | { | ||
| 874 | printf ("{ line=%ld col=%ld pos=%ld byte_pos=%ld }\n", linecol.line, linecol.col, linecol.pos, linecol.byte_pos); | ||
| 875 | } | ||
| 876 | |||
| 877 | static void | ||
| 878 | treesit_validate_linecol (const char *name, struct ts_linecol linecol) | ||
| 879 | { | ||
| 880 | eassert (linecol.pos <= Z); | ||
| 881 | |||
| 882 | if (linecol.pos > Z) | ||
| 883 | { | ||
| 884 | printf ("OUT OF RANGE\n"); | ||
| 885 | treesit_print_linecol (linecol); | ||
| 886 | printf ("Z: %ld\n", Z); | ||
| 887 | } | ||
| 888 | |||
| 889 | ptrdiff_t true_line_count = count_lines (BEG, linecol.byte_pos) + 1; | ||
| 890 | eassert (true_line_count == linecol.line); | ||
| 891 | |||
| 892 | if (true_line_count != linecol.line) | ||
| 893 | { | ||
| 894 | printf ("MISMATCH\n"); | ||
| 895 | printf ("%s: ", name); | ||
| 896 | treesit_print_linecol (linecol); | ||
| 897 | printf ("true: %ld\n", true_line_count); | ||
| 898 | } | ||
| 899 | } | ||
| 900 | |||
| 901 | /* Calculate and return the line and column number of BYTE_POS by | ||
| 902 | scanning newlines from CACHE. CACHE must be valid. */ | ||
| 903 | static struct ts_linecol | ||
| 904 | treesit_linecol_of_pos (ptrdiff_t target_pos, ptrdiff_t target_byte_pos, | ||
| 905 | struct ts_linecol cache) | ||
| 906 | { | ||
| 907 | eassert (target_pos == target_byte_pos); | ||
| 908 | |||
| 909 | if (TREE_SITTER_DEBUG_LINECOL) | ||
| 910 | { | ||
| 911 | /* eassert (true_line_count == cache.line); */ | ||
| 912 | treesit_validate_linecol ("cache", cache); | ||
| 913 | } | ||
| 914 | |||
| 915 | /* When we finished searching for newlines between CACHE and | ||
| 916 | TARGET_POS, BYTE_POS_2 is at TARGET_POS, and BYTE_POS_1 is at the | ||
| 917 | previous newline. If TARGET_POS happends to be on a newline, | ||
| 918 | BYTE_POS_1 will be on that position. BYTE_POS_1 is used for | ||
| 919 | calculating the column. (If CACHE and TARGET_POS are in the same | ||
| 920 | line, BYTE_POS_1 is unset and we don't use it.) */ | ||
| 921 | ptrdiff_t byte_pos_1 = 0; | ||
| 922 | ptrdiff_t pos_2 = 0; | ||
| 923 | ptrdiff_t byte_pos_2 = 0; | ||
| 924 | /* Number of lines between CACHE and TARGET_POS. */ | ||
| 925 | ptrdiff_t line_delta = 0; | ||
| 926 | |||
| 927 | if (target_byte_pos == cache.byte_pos) | ||
| 928 | return cache; | ||
| 929 | |||
| 930 | /* Search forward. */ | ||
| 931 | if (cache.byte_pos < target_byte_pos) | ||
| 932 | { | ||
| 933 | pos_2 = cache.pos; | ||
| 934 | byte_pos_2 = cache.byte_pos; | ||
| 935 | while (byte_pos_2 < target_byte_pos) | ||
| 936 | { | ||
| 937 | ptrdiff_t counted = 0; | ||
| 938 | pos_2 = find_newline (pos_2, byte_pos_2, target_pos, target_byte_pos, | ||
| 939 | 1, &counted, &byte_pos_2, false); | ||
| 940 | |||
| 941 | if (counted > 0) byte_pos_1 = byte_pos_2; | ||
| 942 | line_delta += counted; | ||
| 943 | /* printf ("byte_pos_2=%ld counted=%ld line_delta=%ld\n", byte_pos_2, counted, line_delta); */ | ||
| 944 | } | ||
| 945 | eassert (byte_pos_2 == target_byte_pos); | ||
| 946 | /* At this point, byte_pos_2 is at target_pos, and byte_pos_1 is | ||
| 947 | at the previous newline if we went across any. */ | ||
| 948 | |||
| 949 | struct ts_linecol target_linecol; | ||
| 950 | target_linecol.pos = target_pos; | ||
| 951 | target_linecol.byte_pos = target_byte_pos; | ||
| 952 | target_linecol.line = cache.line + line_delta; | ||
| 953 | /* If we moved across any newline, use the previous newline to | ||
| 954 | calculate the column; if we stayed at the same line, use the | ||
| 955 | cached column to calculate the new column. */ | ||
| 956 | target_linecol.col = line_delta > 0 | ||
| 957 | ? target_byte_pos - byte_pos_1 | ||
| 958 | : target_byte_pos - cache.byte_pos + cache.col; | ||
| 959 | |||
| 960 | if (TREE_SITTER_DEBUG_LINECOL) | ||
| 961 | { | ||
| 962 | /* eassert (true_line_count == target_linecol.line); */ | ||
| 963 | treesit_validate_linecol ("target", target_linecol); | ||
| 964 | } | ||
| 965 | |||
| 966 | return target_linecol; | ||
| 967 | } | ||
| 968 | |||
| 969 | /* Search backward. */ | ||
| 970 | printf ("BACK\n"); | ||
| 971 | pos_2 = cache.pos + 1; | ||
| 972 | /* The "+1" Cancels out with the "-1" in the first iteration. */ | ||
| 973 | byte_pos_2 = cache.byte_pos + 1; | ||
| 974 | while (byte_pos_2 > target_byte_pos) | ||
| 975 | { | ||
| 976 | ptrdiff_t counted = 0; | ||
| 977 | /* pos_2 - 1 won't underflow because of the loop condition. */ | ||
| 978 | pos_2 = find_newline (pos_2 - 1, byte_pos_2 - 1, | ||
| 979 | target_pos, target_byte_pos, | ||
| 980 | -1, &counted, &byte_pos_2, false); | ||
| 981 | line_delta += counted; | ||
| 982 | } | ||
| 983 | eassert (byte_pos_2 == target_byte_pos); | ||
| 984 | /* At this point, pos_2 is at target_pos. */ | ||
| 985 | |||
| 986 | struct ts_linecol target_linecol; | ||
| 987 | target_linecol.pos = target_pos; | ||
| 988 | target_linecol.byte_pos = target_byte_pos; | ||
| 989 | target_linecol.line = cache.line + line_delta; | ||
| 990 | eassert (cache.line + line_delta > 0); | ||
| 991 | |||
| 992 | /* Calculate the column. */ | ||
| 993 | if (line_delta == 0) | ||
| 994 | { | ||
| 995 | target_linecol.col = cache.col - (cache.byte_pos - target_byte_pos); | ||
| 996 | } | ||
| 997 | else | ||
| 998 | { | ||
| 999 | /* We need to find the previous newline in order to calculate the | ||
| 1000 | column. Use POS_2 instead of POS_2 - 1, this way, if POS_2 is | ||
| 1001 | at BOL, we stay in the same place. */ | ||
| 1002 | pos_2 = find_newline (pos_2, byte_pos_2, BEG, BEG_BYTE, -1, | ||
| 1003 | NULL, &byte_pos_2, false); | ||
| 1004 | target_linecol.col = target_byte_pos - byte_pos_2; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | if (TREE_SITTER_DEBUG_LINECOL) | ||
| 1008 | { | ||
| 1009 | treesit_validate_linecol ("target", target_linecol); | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | return target_linecol; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | /* Return a TSPoint given POS and VISIBLE_BEG. VISIBLE_BEG must be | ||
| 1016 | before POS. */ | ||
| 1017 | static TSPoint | ||
| 1018 | treesit_make_ts_point (struct ts_linecol visible_beg, | ||
| 1019 | struct ts_linecol pos) | ||
| 1020 | { | ||
| 1021 | TSPoint point; | ||
| 1022 | if (visible_beg.line == pos.line) | ||
| 1023 | { | ||
| 1024 | point.row = 0; | ||
| 1025 | point.column = pos.col - visible_beg.col; | ||
| 1026 | eassert (point.column >= 0); | ||
| 1027 | } | ||
| 1028 | else | ||
| 1029 | { | ||
| 1030 | point.row = pos.line - visible_beg.line; | ||
| 1031 | eassert (point.row > 0); | ||
| 1032 | point.column = pos.col; | ||
| 1033 | } | ||
| 1034 | return point; | ||
| 1035 | } | ||
| 1036 | |||
| 867 | /*** Parsing functions */ | 1037 | /*** Parsing functions */ |
| 868 | 1038 | ||
| 869 | static void | 1039 | static void |
| @@ -879,28 +1049,34 @@ treesit_check_parser (Lisp_Object obj) | |||
| 879 | larger than UINT32_MAX. */ | 1049 | larger than UINT32_MAX. */ |
| 880 | static inline void | 1050 | static inline void |
| 881 | treesit_tree_edit_1 (TSTree *tree, ptrdiff_t start_byte, | 1051 | treesit_tree_edit_1 (TSTree *tree, ptrdiff_t start_byte, |
| 882 | ptrdiff_t old_end_byte, ptrdiff_t new_end_byte) | 1052 | ptrdiff_t old_end_byte, ptrdiff_t new_end_byte, |
| 1053 | TSPoint start_point, TSPoint old_end_point, | ||
| 1054 | TSPoint new_end_point) | ||
| 883 | { | 1055 | { |
| 884 | eassert (start_byte >= 0); | 1056 | eassert (start_byte >= 0); |
| 885 | eassert (start_byte <= old_end_byte); | 1057 | eassert (start_byte <= old_end_byte); |
| 886 | eassert (start_byte <= new_end_byte); | 1058 | eassert (start_byte <= new_end_byte); |
| 887 | TSPoint dummy_point = {0, 0}; | ||
| 888 | eassert (start_byte <= UINT32_MAX); | 1059 | eassert (start_byte <= UINT32_MAX); |
| 889 | eassert (old_end_byte <= UINT32_MAX); | 1060 | eassert (old_end_byte <= UINT32_MAX); |
| 890 | eassert (new_end_byte <= UINT32_MAX); | 1061 | eassert (new_end_byte <= UINT32_MAX); |
| 891 | TSInputEdit edit = {(uint32_t) start_byte, | 1062 | TSInputEdit edit = {(uint32_t) start_byte, |
| 892 | (uint32_t) old_end_byte, | 1063 | (uint32_t) old_end_byte, |
| 893 | (uint32_t) new_end_byte, | 1064 | (uint32_t) new_end_byte, |
| 894 | dummy_point, dummy_point, dummy_point}; | 1065 | start_point, old_end_point, new_end_point}; |
| 895 | ts_tree_edit (tree, &edit); | 1066 | ts_tree_edit (tree, &edit); |
| 896 | } | 1067 | } |
| 897 | 1068 | ||
| 898 | /* Update each parser's tree after the user made an edit. This | 1069 | /* Update each parser's tree after the user made an edit. This function |
| 899 | function does not parse the buffer and only updates the tree, so it | 1070 | does not parse the buffer and only updates the tree, so it should be |
| 900 | should be very fast. */ | 1071 | very fast. If the caller knows there's no parser in the current |
| 901 | void | 1072 | buffer, they can pass empty linecol for |
| 902 | treesit_record_change (ptrdiff_t start_byte, ptrdiff_t old_end_byte, | 1073 | START/OLD_END/NEW_END_linecol. */ |
| 903 | ptrdiff_t new_end_byte) | 1074 | static void |
| 1075 | treesit_record_change_1 (ptrdiff_t start_byte, ptrdiff_t old_end_byte, | ||
| 1076 | ptrdiff_t new_end_byte, | ||
| 1077 | struct ts_linecol start_linecol, | ||
| 1078 | struct ts_linecol old_end_linecol, | ||
| 1079 | struct ts_linecol new_end_linecol) | ||
| 904 | { | 1080 | { |
| 905 | struct buffer *base_buffer = current_buffer; | 1081 | struct buffer *base_buffer = current_buffer; |
| 906 | if (current_buffer->base_buffer) | 1082 | if (current_buffer->base_buffer) |
| @@ -920,12 +1096,15 @@ treesit_record_change (ptrdiff_t start_byte, ptrdiff_t old_end_byte, | |||
| 920 | { | 1096 | { |
| 921 | eassert (start_byte <= old_end_byte); | 1097 | eassert (start_byte <= old_end_byte); |
| 922 | eassert (start_byte <= new_end_byte); | 1098 | eassert (start_byte <= new_end_byte); |
| 923 | /* Think the recorded change as a delete followed by an | 1099 | /* Before sending the edit to tree-sitter, we need to first |
| 924 | insert, and think of them as moving unchanged text back | 1100 | clip the beg/end to visible_beg and visible_end of the |
| 925 | and forth. After all, the whole point of updating the | 1101 | parser. A tip for understanding the code below: think the |
| 926 | tree is to update the position of unchanged text. */ | 1102 | recorded change as a delete followed by an insert, and |
| 927 | ptrdiff_t visible_beg = XTS_PARSER (lisp_parser)->visible_beg; | 1103 | think of them as moving unchanged text back and forth. |
| 928 | ptrdiff_t visible_end = XTS_PARSER (lisp_parser)->visible_end; | 1104 | After all, the whole point of updating the tree is to |
| 1105 | update the position of unchanged text. */ | ||
| 1106 | const ptrdiff_t visible_beg = XTS_PARSER (lisp_parser)->visible_beg; | ||
| 1107 | const ptrdiff_t visible_end = XTS_PARSER (lisp_parser)->visible_end; | ||
| 929 | eassert (visible_beg >= 0); | 1108 | eassert (visible_beg >= 0); |
| 930 | eassert (visible_beg <= visible_end); | 1109 | eassert (visible_beg <= visible_end); |
| 931 | 1110 | ||
| @@ -949,9 +1128,9 @@ treesit_record_change (ptrdiff_t start_byte, ptrdiff_t old_end_byte, | |||
| 949 | eassert (start_offset <= old_end_offset); | 1128 | eassert (start_offset <= old_end_offset); |
| 950 | eassert (start_offset <= new_end_offset); | 1129 | eassert (start_offset <= new_end_offset); |
| 951 | 1130 | ||
| 952 | treesit_tree_edit_1 (tree, start_offset, old_end_offset, | 1131 | /* We have the correct offset for start/end now, but don't |
| 953 | new_end_offset); | 1132 | update the tree yet, because we still need to calculate the |
| 954 | XTS_PARSER (lisp_parser)->need_reparse = true; | 1133 | TSPoint, which needs the updated visible_beg linecol. */ |
| 955 | 1134 | ||
| 956 | /* VISIBLE_BEG/END records tree-sitter's range of view in | 1135 | /* VISIBLE_BEG/END records tree-sitter's range of view in |
| 957 | the buffer. We need to adjust them when tree-sitter's | 1136 | the buffer. We need to adjust them when tree-sitter's |
| @@ -966,19 +1145,99 @@ treesit_record_change (ptrdiff_t start_byte, ptrdiff_t old_end_byte, | |||
| 966 | visi_beg_delta = (old_end_byte < visible_beg | 1145 | visi_beg_delta = (old_end_byte < visible_beg |
| 967 | ? new_end_byte - old_end_byte : 0); | 1146 | ? new_end_byte - old_end_byte : 0); |
| 968 | 1147 | ||
| 969 | XTS_PARSER (lisp_parser)->visible_beg = visible_beg + visi_beg_delta; | 1148 | ptrdiff_t old_visi_beg = visible_beg; |
| 970 | XTS_PARSER (lisp_parser)->visible_end = (visible_end | 1149 | struct ts_linecol old_visi_beg_linecol |
| 971 | + visi_beg_delta | 1150 | = XTS_PARSER (lisp_parser)->visi_beg_linecol; |
| 972 | + (new_end_offset | 1151 | /* struct ts_linecol old_visi_end_linecol */ |
| 973 | - old_end_offset)); | 1152 | /* = XTS_PARSER (lisp_parser)->visi_end_linecol; */ |
| 1153 | |||
| 1154 | const ptrdiff_t new_visible_beg = visible_beg + visi_beg_delta; | ||
| 1155 | const ptrdiff_t new_visible_end | ||
| 1156 | = (visible_end + visi_beg_delta | ||
| 1157 | + (new_end_offset - old_end_offset)); | ||
| 1158 | |||
| 1159 | XTS_PARSER (lisp_parser)->visible_beg = new_visible_beg; | ||
| 1160 | XTS_PARSER (lisp_parser)->visible_end = new_visible_end; | ||
| 1161 | XTS_PARSER (lisp_parser)->visi_beg_linecol | ||
| 1162 | = treesit_linecol_of_pos (BYTE_TO_CHAR (new_visible_beg), | ||
| 1163 | new_visible_beg, | ||
| 1164 | old_visi_beg <= start_byte | ||
| 1165 | ? old_visi_beg_linecol | ||
| 1166 | : start_linecol); | ||
| 1167 | /* FIXME: computing visi_end_linecol from new_end_linecol | ||
| 1168 | could be expensive, we need a more efficient way to compute | ||
| 1169 | it. */ | ||
| 1170 | XTS_PARSER (lisp_parser)->visi_end_linecol | ||
| 1171 | = treesit_linecol_of_pos (BYTE_TO_CHAR (new_visible_end), | ||
| 1172 | new_visible_end, | ||
| 1173 | new_end_linecol); | ||
| 974 | 1174 | ||
| 975 | eassert (XTS_PARSER (lisp_parser)->visible_beg >= 0); | 1175 | eassert (XTS_PARSER (lisp_parser)->visible_beg >= 0); |
| 976 | eassert (XTS_PARSER (lisp_parser)->visible_beg | 1176 | eassert (XTS_PARSER (lisp_parser)->visible_beg |
| 977 | <= XTS_PARSER (lisp_parser)->visible_end); | 1177 | <= XTS_PARSER (lisp_parser)->visible_end); |
| 1178 | |||
| 1179 | /* Now, calculate TSPoints and finally update the tree. */ | ||
| 1180 | struct ts_linecol new_begv_linecol | ||
| 1181 | = XTS_PARSER (lisp_parser)->visi_beg_linecol; | ||
| 1182 | TSPoint old_end_point = treesit_make_ts_point (old_visi_beg_linecol, | ||
| 1183 | old_end_linecol); | ||
| 1184 | TSPoint start_point = treesit_make_ts_point (new_begv_linecol, | ||
| 1185 | start_linecol); | ||
| 1186 | TSPoint new_end_point = treesit_make_ts_point (new_begv_linecol, | ||
| 1187 | new_end_linecol); | ||
| 1188 | |||
| 1189 | treesit_tree_edit_1 (tree, start_offset, old_end_offset, | ||
| 1190 | new_end_offset, start_point, old_end_point, | ||
| 1191 | new_end_point); | ||
| 1192 | XTS_PARSER (lisp_parser)->need_reparse = true; | ||
| 978 | } | 1193 | } |
| 979 | } | 1194 | } |
| 980 | } | 1195 | } |
| 981 | 1196 | ||
| 1197 | /* Return the linecol of POS, calculated from CACHE. But if there's no | ||
| 1198 | parser in the current buffer, skip calculation and return an empty | ||
| 1199 | linecol instead. */ | ||
| 1200 | struct ts_linecol | ||
| 1201 | treesit_linecol_maybe (ptrdiff_t pos, ptrdiff_t pos_byte, | ||
| 1202 | struct ts_linecol cache) | ||
| 1203 | { | ||
| 1204 | if (NILP (BVAR (current_buffer, ts_parser_list))) | ||
| 1205 | return TREESIT_EMPTY_LINECOL; | ||
| 1206 | |||
| 1207 | return treesit_linecol_of_pos (pos, pos_byte, cache); | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | /* Update each parser's tree after the user made an edit. This function | ||
| 1211 | does not parse the buffer and only updates the tree, so it should be | ||
| 1212 | very fast. | ||
| 1213 | |||
| 1214 | This is a wrapper over treesit_record_change that does a bit more | ||
| 1215 | boilerplate work: it (optionally) calculates linecol for new_end, | ||
| 1216 | pass all the positions into treesit_record_change_1 which does the | ||
| 1217 | real work, and finally (optionally) sets buffer's linecol cache to | ||
| 1218 | new_end's linecol. | ||
| 1219 | |||
| 1220 | If NEW_END is next to NEW_END_BYTE in the arglist, caller might | ||
| 1221 | accidentally swap them, so I placed NEW_END at the end of the | ||
| 1222 | arglist. */ | ||
| 1223 | void | ||
| 1224 | treesit_record_change (ptrdiff_t start_byte, ptrdiff_t old_end_byte, | ||
| 1225 | ptrdiff_t new_end_byte, | ||
| 1226 | struct ts_linecol start_linecol, | ||
| 1227 | struct ts_linecol old_end_linecol, | ||
| 1228 | ptrdiff_t new_end) | ||
| 1229 | { | ||
| 1230 | struct ts_linecol new_end_linecol | ||
| 1231 | = treesit_linecol_maybe (new_end, new_end_byte, start_linecol); | ||
| 1232 | |||
| 1233 | treesit_record_change_1 (start_byte, old_end_byte, new_end_byte, | ||
| 1234 | start_linecol, old_end_linecol, new_end_linecol); | ||
| 1235 | |||
| 1236 | treesit_print_linecol (new_end_linecol); | ||
| 1237 | if (new_end_linecol.pos != 0) | ||
| 1238 | current_buffer->ts_linecol_cache = new_end_linecol; | ||
| 1239 | } | ||
| 1240 | |||
| 982 | static TSRange *treesit_make_ts_ranges (Lisp_Object, Lisp_Object, | 1241 | static TSRange *treesit_make_ts_ranges (Lisp_Object, Lisp_Object, |
| 983 | uint32_t *); | 1242 | uint32_t *); |
| 984 | 1243 | ||
| @@ -1046,6 +1305,7 @@ treesit_sync_visible_region (Lisp_Object parser) | |||
| 1046 | 1305 | ||
| 1047 | ptrdiff_t visible_beg = XTS_PARSER (parser)->visible_beg; | 1306 | ptrdiff_t visible_beg = XTS_PARSER (parser)->visible_beg; |
| 1048 | ptrdiff_t visible_end = XTS_PARSER (parser)->visible_end; | 1307 | ptrdiff_t visible_end = XTS_PARSER (parser)->visible_end; |
| 1308 | |||
| 1049 | eassert (0 <= visible_beg); | 1309 | eassert (0 <= visible_beg); |
| 1050 | eassert (visible_beg <= visible_end); | 1310 | eassert (visible_beg <= visible_end); |
| 1051 | 1311 | ||
| @@ -1066,39 +1326,72 @@ treesit_sync_visible_region (Lisp_Object parser) | |||
| 1066 | from ________|xxxx|__ | 1326 | from ________|xxxx|__ |
| 1067 | to |xxxx|__________ */ | 1327 | to |xxxx|__________ */ |
| 1068 | 1328 | ||
| 1329 | struct ts_linecol buffer_linecol_cache = buffer->ts_linecol_cache; | ||
| 1330 | struct ts_linecol visi_beg_linecol = XTS_PARSER (parser)->visi_beg_linecol; | ||
| 1331 | struct ts_linecol visi_end_linecol = XTS_PARSER (parser)->visi_end_linecol; | ||
| 1332 | struct ts_linecol buffer_begv_linecol | ||
| 1333 | = treesit_linecol_of_pos (BUF_BEGV (buffer), BUF_BEGV_BYTE (buffer), | ||
| 1334 | visi_beg_linecol); | ||
| 1335 | struct ts_linecol buffer_zv_linecol | ||
| 1336 | = treesit_linecol_of_pos (BUF_ZV (buffer), BUF_ZV_BYTE (buffer), | ||
| 1337 | buffer_linecol_cache); | ||
| 1338 | eassert (visi_beg_linecol.byte_pos == visible_beg); | ||
| 1339 | |||
| 1069 | /* 1. Make sure visible_beg <= BUF_BEGV_BYTE. */ | 1340 | /* 1. Make sure visible_beg <= BUF_BEGV_BYTE. */ |
| 1070 | if (visible_beg > BUF_BEGV_BYTE (buffer)) | 1341 | if (visible_beg > BUF_BEGV_BYTE (buffer)) |
| 1071 | { | 1342 | { |
| 1343 | TSPoint new_end = treesit_make_ts_point (buffer_begv_linecol, | ||
| 1344 | visi_beg_linecol); | ||
| 1072 | /* Tree-sitter sees: insert at the beginning. */ | 1345 | /* Tree-sitter sees: insert at the beginning. */ |
| 1073 | treesit_tree_edit_1 (tree, 0, 0, visible_beg - BUF_BEGV_BYTE (buffer)); | 1346 | treesit_tree_edit_1 (tree, 0, 0, visible_beg - BUF_BEGV_BYTE (buffer), |
| 1347 | TREESIT_TS_POINT_1_0, TREESIT_TS_POINT_1_0, | ||
| 1348 | new_end); | ||
| 1074 | visible_beg = BUF_BEGV_BYTE (buffer); | 1349 | visible_beg = BUF_BEGV_BYTE (buffer); |
| 1350 | visi_beg_linecol = buffer_begv_linecol; | ||
| 1075 | eassert (visible_beg <= visible_end); | 1351 | eassert (visible_beg <= visible_end); |
| 1076 | } | 1352 | } |
| 1077 | /* 2. Make sure visible_end = BUF_ZV_BYTE. */ | 1353 | /* 2. Make sure visible_end = BUF_ZV_BYTE. */ |
| 1078 | if (visible_end < BUF_ZV_BYTE (buffer)) | 1354 | if (visible_end < BUF_ZV_BYTE (buffer)) |
| 1079 | { | 1355 | { |
| 1356 | TSPoint start = treesit_make_ts_point (visi_beg_linecol, | ||
| 1357 | visi_end_linecol); | ||
| 1358 | TSPoint new_end = treesit_make_ts_point (visi_beg_linecol, | ||
| 1359 | buffer_zv_linecol); | ||
| 1080 | /* Tree-sitter sees: insert at the end. */ | 1360 | /* Tree-sitter sees: insert at the end. */ |
| 1081 | treesit_tree_edit_1 (tree, visible_end - visible_beg, | 1361 | treesit_tree_edit_1 (tree, visible_end - visible_beg, |
| 1082 | visible_end - visible_beg, | 1362 | visible_end - visible_beg, |
| 1083 | BUF_ZV_BYTE (buffer) - visible_beg); | 1363 | BUF_ZV_BYTE (buffer) - visible_beg, |
| 1364 | start, start, new_end); | ||
| 1084 | visible_end = BUF_ZV_BYTE (buffer); | 1365 | visible_end = BUF_ZV_BYTE (buffer); |
| 1366 | visi_end_linecol = buffer_zv_linecol; | ||
| 1085 | eassert (visible_beg <= visible_end); | 1367 | eassert (visible_beg <= visible_end); |
| 1086 | } | 1368 | } |
| 1087 | else if (visible_end > BUF_ZV_BYTE (buffer)) | 1369 | else if (visible_end > BUF_ZV_BYTE (buffer)) |
| 1088 | { | 1370 | { |
| 1371 | TSPoint start = treesit_make_ts_point (visi_beg_linecol, | ||
| 1372 | buffer_zv_linecol); | ||
| 1373 | TSPoint old_end = treesit_make_ts_point (visi_beg_linecol, | ||
| 1374 | visi_end_linecol); | ||
| 1089 | /* Tree-sitter sees: delete at the end. */ | 1375 | /* Tree-sitter sees: delete at the end. */ |
| 1090 | treesit_tree_edit_1 (tree, BUF_ZV_BYTE (buffer) - visible_beg, | 1376 | treesit_tree_edit_1 (tree, BUF_ZV_BYTE (buffer) - visible_beg, |
| 1091 | visible_end - visible_beg, | 1377 | visible_end - visible_beg, |
| 1092 | BUF_ZV_BYTE (buffer) - visible_beg); | 1378 | BUF_ZV_BYTE (buffer) - visible_beg, |
| 1379 | start, old_end, start); | ||
| 1093 | visible_end = BUF_ZV_BYTE (buffer); | 1380 | visible_end = BUF_ZV_BYTE (buffer); |
| 1381 | visi_end_linecol = buffer_zv_linecol; | ||
| 1094 | eassert (visible_beg <= visible_end); | 1382 | eassert (visible_beg <= visible_end); |
| 1095 | } | 1383 | } |
| 1096 | /* 3. Make sure visible_beg = BUF_BEGV_BYTE. */ | 1384 | /* 3. Make sure visible_beg = BUF_BEGV_BYTE. */ |
| 1097 | if (visible_beg < BUF_BEGV_BYTE (buffer)) | 1385 | if (visible_beg < BUF_BEGV_BYTE (buffer)) |
| 1098 | { | 1386 | { |
| 1387 | TSPoint old_end = treesit_make_ts_point (visi_beg_linecol, | ||
| 1388 | buffer_begv_linecol); | ||
| 1099 | /* Tree-sitter sees: delete at the beginning. */ | 1389 | /* Tree-sitter sees: delete at the beginning. */ |
| 1100 | treesit_tree_edit_1 (tree, 0, BUF_BEGV_BYTE (buffer) - visible_beg, 0); | 1390 | treesit_tree_edit_1 (tree, 0, BUF_BEGV_BYTE (buffer) - visible_beg, 0, |
| 1391 | TREESIT_TS_POINT_1_0, old_end, | ||
| 1392 | TREESIT_TS_POINT_1_0); | ||
| 1101 | visible_beg = BUF_BEGV_BYTE (buffer); | 1393 | visible_beg = BUF_BEGV_BYTE (buffer); |
| 1394 | visi_beg_linecol = buffer_begv_linecol; | ||
| 1102 | eassert (visible_beg <= visible_end); | 1395 | eassert (visible_beg <= visible_end); |
| 1103 | } | 1396 | } |
| 1104 | eassert (0 <= visible_beg); | 1397 | eassert (0 <= visible_beg); |
| @@ -1108,6 +1401,8 @@ treesit_sync_visible_region (Lisp_Object parser) | |||
| 1108 | 1401 | ||
| 1109 | XTS_PARSER (parser)->visible_beg = visible_beg; | 1402 | XTS_PARSER (parser)->visible_beg = visible_beg; |
| 1110 | XTS_PARSER (parser)->visible_end = visible_end; | 1403 | XTS_PARSER (parser)->visible_end = visible_end; |
| 1404 | XTS_PARSER (parser)->visi_beg_linecol = visi_beg_linecol; | ||
| 1405 | XTS_PARSER (parser)->visi_end_linecol = visi_end_linecol; | ||
| 1111 | 1406 | ||
| 1112 | /* Fix ranges so that the ranges stays with in visible_end. Here we | 1407 | /* Fix ranges so that the ranges stays with in visible_end. Here we |
| 1113 | try to do minimal work so that the ranges is minimally correct and | 1408 | try to do minimal work so that the ranges is minimally correct and |
| @@ -1381,6 +1676,19 @@ make_treesit_parser (Lisp_Object buffer, TSParser *parser, | |||
| 1381 | lisp_parser->need_to_gc_buffer = false; | 1676 | lisp_parser->need_to_gc_buffer = false; |
| 1382 | lisp_parser->within_reparse = false; | 1677 | lisp_parser->within_reparse = false; |
| 1383 | eassert (lisp_parser->visible_beg <= lisp_parser->visible_end); | 1678 | eassert (lisp_parser->visible_beg <= lisp_parser->visible_end); |
| 1679 | |||
| 1680 | struct buffer *old_buf = current_buffer; | ||
| 1681 | set_buffer_internal (XBUFFER (buffer)); | ||
| 1682 | |||
| 1683 | /* treesit_linecol_of_pos doesn't signal, so no need to | ||
| 1684 | unwind-protect. */ | ||
| 1685 | lisp_parser->visi_beg_linecol = treesit_linecol_of_pos (BEGV, BEGV_BYTE, | ||
| 1686 | TREESIT_BOB_LINECOL); | ||
| 1687 | lisp_parser->visi_end_linecol | ||
| 1688 | = treesit_linecol_of_pos (ZV, ZV_BYTE, lisp_parser->visi_beg_linecol); | ||
| 1689 | |||
| 1690 | set_buffer_internal (old_buf); | ||
| 1691 | |||
| 1384 | return make_lisp_ptr (lisp_parser, Lisp_Vectorlike); | 1692 | return make_lisp_ptr (lisp_parser, Lisp_Vectorlike); |
| 1385 | } | 1693 | } |
| 1386 | 1694 | ||
| @@ -4376,6 +4684,66 @@ nodes in the subtree, including NODE. */) | |||
| 4376 | } | 4684 | } |
| 4377 | } | 4685 | } |
| 4378 | 4686 | ||
| 4687 | DEFUN ("treesit--linecol-at", Ftreesit__linecol_at, | ||
| 4688 | Streesit__linecol_at, 1, 1, 0, | ||
| 4689 | doc: /* Test buffer-local linecol cache. | ||
| 4690 | |||
| 4691 | Calculate the line and column at POS using the buffer-local cache, | ||
| 4692 | return the line and column in the form of | ||
| 4693 | |||
| 4694 | (LINE . COL) | ||
| 4695 | |||
| 4696 | This is used for testing and debugging only. */) | ||
| 4697 | (Lisp_Object pos) | ||
| 4698 | { | ||
| 4699 | CHECK_NUMBER (pos); | ||
| 4700 | struct ts_linecol pos_linecol | ||
| 4701 | = treesit_linecol_of_pos (XFIXNUM (pos), CHAR_TO_BYTE (XFIXNUM (pos)), | ||
| 4702 | current_buffer->ts_linecol_cache); | ||
| 4703 | return Fcons (make_fixnum (pos_linecol.line), make_fixnum (pos_linecol.col)); | ||
| 4704 | } | ||
| 4705 | |||
| 4706 | DEFUN ("treesit--linecol-cache-set", Ftreesit__linecol_cache_set, | ||
| 4707 | Streesit__linecol_cache_set, 4, 4, 0, | ||
| 4708 | doc: /* Set the linecol cache for the current buffer. | ||
| 4709 | |||
| 4710 | This is used for testing and debugging only. */) | ||
| 4711 | (Lisp_Object line, Lisp_Object col, Lisp_Object pos, Lisp_Object bytepos) | ||
| 4712 | { | ||
| 4713 | CHECK_FIXNUM (line); | ||
| 4714 | CHECK_FIXNUM (col); | ||
| 4715 | CHECK_FIXNUM (pos); | ||
| 4716 | CHECK_FIXNUM (bytepos); | ||
| 4717 | |||
| 4718 | current_buffer->ts_linecol_cache.line = XFIXNUM (line); | ||
| 4719 | current_buffer->ts_linecol_cache.col = XFIXNUM (col); | ||
| 4720 | current_buffer->ts_linecol_cache.pos = XFIXNUM (pos); | ||
| 4721 | current_buffer->ts_linecol_cache.byte_pos = XFIXNUM (bytepos); | ||
| 4722 | |||
| 4723 | return Qnil; | ||
| 4724 | } | ||
| 4725 | |||
| 4726 | DEFUN ("treesit--linecol-cache", Ftreesit__linecol_cache, | ||
| 4727 | Streesit__linecol_cache, 0, 0, 0, | ||
| 4728 | doc: /* Return the buffer-local linecol cache for debugging. | ||
| 4729 | |||
| 4730 | Return a plist (:line LINE :col COL :pos POS :bytepos BYTEPOS). This is | ||
| 4731 | used for testing and debugging only. */) | ||
| 4732 | (void) | ||
| 4733 | { | ||
| 4734 | struct ts_linecol cache = current_buffer->ts_linecol_cache; | ||
| 4735 | |||
| 4736 | Lisp_Object plist = (list4 (QCpos, make_fixnum (cache.pos), | ||
| 4737 | QCbytepos, make_fixnum (cache.byte_pos))); | ||
| 4738 | plist = Fcons (make_fixnum (cache.col), plist); | ||
| 4739 | plist = Fcons (QCcol, plist); | ||
| 4740 | plist = Fcons (make_fixnum (cache.line), plist); | ||
| 4741 | plist = Fcons (QCline, plist); | ||
| 4742 | |||
| 4743 | return plist; | ||
| 4744 | } | ||
| 4745 | |||
| 4746 | |||
| 4379 | #endif /* HAVE_TREE_SITTER */ | 4747 | #endif /* HAVE_TREE_SITTER */ |
| 4380 | 4748 | ||
| 4381 | DEFUN ("treesit-available-p", Ftreesit_available_p, | 4749 | DEFUN ("treesit-available-p", Ftreesit_available_p, |
| @@ -4418,6 +4786,11 @@ syms_of_treesit (void) | |||
| 4418 | DEFSYM (QCequal, ":equal"); | 4786 | DEFSYM (QCequal, ":equal"); |
| 4419 | DEFSYM (QCmatch, ":match"); | 4787 | DEFSYM (QCmatch, ":match"); |
| 4420 | DEFSYM (QCpred, ":pred"); | 4788 | DEFSYM (QCpred, ":pred"); |
| 4789 | DEFSYM (QCline, ":line"); | ||
| 4790 | DEFSYM (QCcol, ":col"); | ||
| 4791 | DEFSYM (QCpos, ":pos"); | ||
| 4792 | DEFSYM (QCbytepos, ":bytepos"); | ||
| 4793 | |||
| 4421 | 4794 | ||
| 4422 | DEFSYM (Qnot_found, "not-found"); | 4795 | DEFSYM (Qnot_found, "not-found"); |
| 4423 | DEFSYM (Qsymbol_error, "symbol-error"); | 4796 | DEFSYM (Qsymbol_error, "symbol-error"); |
| @@ -4649,6 +5022,10 @@ applies to LANGUAGE-A will be redirected to LANGUAGE-B instead. */); | |||
| 4649 | defsubr (&Streesit_induce_sparse_tree); | 5022 | defsubr (&Streesit_induce_sparse_tree); |
| 4650 | defsubr (&Streesit_node_match_p); | 5023 | defsubr (&Streesit_node_match_p); |
| 4651 | defsubr (&Streesit_subtree_stat); | 5024 | defsubr (&Streesit_subtree_stat); |
| 5025 | |||
| 5026 | defsubr (&Streesit__linecol_at); | ||
| 5027 | defsubr (&Streesit__linecol_cache); | ||
| 5028 | defsubr (&Streesit__linecol_cache_set); | ||
| 4652 | #endif /* HAVE_TREE_SITTER */ | 5029 | #endif /* HAVE_TREE_SITTER */ |
| 4653 | defsubr (&Streesit_available_p); | 5030 | defsubr (&Streesit_available_p); |
| 4654 | #ifdef WINDOWSNT | 5031 | #ifdef WINDOWSNT |