aboutsummaryrefslogtreecommitdiffstats
path: root/src/treesit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/treesit.c')
-rw-r--r--src/treesit.c433
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
871static void
872treesit_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
877static void
878treesit_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. */
903static struct ts_linecol
904treesit_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. */
1017static TSPoint
1018treesit_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
869static void 1039static void
@@ -879,28 +1049,34 @@ treesit_check_parser (Lisp_Object obj)
879 larger than UINT32_MAX. */ 1049 larger than UINT32_MAX. */
880static inline void 1050static inline void
881treesit_tree_edit_1 (TSTree *tree, ptrdiff_t start_byte, 1051treesit_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
901void 1072 buffer, they can pass empty linecol for
902treesit_record_change (ptrdiff_t start_byte, ptrdiff_t old_end_byte, 1073 START/OLD_END/NEW_END_linecol. */
903 ptrdiff_t new_end_byte) 1074static void
1075treesit_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. */
1200struct ts_linecol
1201treesit_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. */
1223void
1224treesit_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
982static TSRange *treesit_make_ts_ranges (Lisp_Object, Lisp_Object, 1241static 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
4687DEFUN ("treesit--linecol-at", Ftreesit__linecol_at,
4688 Streesit__linecol_at, 1, 1, 0,
4689 doc: /* Test buffer-local linecol cache.
4690
4691Calculate the line and column at POS using the buffer-local cache,
4692return the line and column in the form of
4693
4694 (LINE . COL)
4695
4696This 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
4706DEFUN ("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
4710This 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
4726DEFUN ("treesit--linecol-cache", Ftreesit__linecol_cache,
4727 Streesit__linecol_cache, 0, 0, 0,
4728 doc: /* Return the buffer-local linecol cache for debugging.
4729
4730Return a plist (:line LINE :col COL :pos POS :bytepos BYTEPOS). This is
4731used 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
4381DEFUN ("treesit-available-p", Ftreesit_available_p, 4749DEFUN ("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