diff options
| author | Yuan Fu | 2022-06-15 21:53:15 -0700 |
|---|---|---|
| committer | Yuan Fu | 2022-06-16 11:52:04 -0700 |
| commit | 7cee82a91d287e42e6596960cbee17157cde4b29 (patch) | |
| tree | eb6ec90eaacdc78137d87fc63632a18226027735 /src | |
| parent | bd1b27b7c7bbd969cf76409499bb84a83600c42a (diff) | |
| download | emacs-7cee82a91d287e42e6596960cbee17157cde4b29.tar.gz emacs-7cee82a91d287e42e6596960cbee17157cde4b29.zip | |
Fix treesit function ts_record_change and friends
In ts_record_change, the way we calculate tree-sitter change was
wrong:
ptrdiff_t affected_start =
max (visible_beg, start_byte) - visible_beg;
ptrdiff_t affected_old_end =
min (visible_end, affected_start + bytes_del);
ptrdiff_t affected_new_end =
affected_start + bytes_ins;
I changed it to below (also renamed variables)
ptrdiff_t start_offset =
min (visible_end,
max (visible_beg, start_byte)) - visible_beg;
ptrdiff_t old_end_offset =
min (visible_end,
max (visible_beg, old_end_byte)) - visible_beg;
ptrdiff_t new_end_offset =
min (visible_end,
max (visible_beg, new_end_byte)) - visible_beg;
Also previously only visible_end is changed (in a wrong way)
XTS_PARSER (lisp_parser)->visible_end = affected_new_end;
Now we have a whole new bunch of code that makes the right change.
* src/treesit.c (ts_tree_edit_1): Add assertion.
(ts_record_change): See above.
(ts_ensure_position_synced): Add assertion.
(ts_ensure_parsed): Only free if non-NULL.
(make_ts_parser): Add assertion.
(Ftreesit_parser_set_included_ranges): Ensure parsed before setting ranges.
(Ftreesit_parser_included_ranges): Add assertion.
Diffstat (limited to 'src')
| -rw-r--r-- | src/treesit.c | 87 |
1 files changed, 68 insertions, 19 deletions
diff --git a/src/treesit.c b/src/treesit.c index 585683aa1ba..5a53b09675c 100644 --- a/src/treesit.c +++ b/src/treesit.c | |||
| @@ -324,6 +324,9 @@ static inline void | |||
| 324 | ts_tree_edit_1 (TSTree *tree, ptrdiff_t start_byte, | 324 | ts_tree_edit_1 (TSTree *tree, ptrdiff_t start_byte, |
| 325 | ptrdiff_t old_end_byte, ptrdiff_t new_end_byte) | 325 | ptrdiff_t old_end_byte, ptrdiff_t new_end_byte) |
| 326 | { | 326 | { |
| 327 | eassert (start_byte >= 0); | ||
| 328 | eassert (start_byte <= old_end_byte); | ||
| 329 | eassert (start_byte <= new_end_byte); | ||
| 327 | TSPoint dummy_point = {0, 0}; | 330 | TSPoint dummy_point = {0, 0}; |
| 328 | TSInputEdit edit = {(uint32_t) start_byte, | 331 | TSInputEdit edit = {(uint32_t) start_byte, |
| 329 | (uint32_t) old_end_byte, | 332 | (uint32_t) old_end_byte, |
| @@ -356,24 +359,56 @@ ts_record_change (ptrdiff_t start_byte, ptrdiff_t old_end_byte, | |||
| 356 | insert, and think of them as moving unchanged text back | 359 | insert, and think of them as moving unchanged text back |
| 357 | and forth. After all, the whole point of updating the | 360 | and forth. After all, the whole point of updating the |
| 358 | tree is to update the position of unchanged text. */ | 361 | tree is to update the position of unchanged text. */ |
| 359 | ptrdiff_t bytes_del = old_end_byte - start_byte; | ||
| 360 | ptrdiff_t bytes_ins = new_end_byte - start_byte; | ||
| 361 | |||
| 362 | ptrdiff_t visible_beg = XTS_PARSER (lisp_parser)->visible_beg; | 362 | ptrdiff_t visible_beg = XTS_PARSER (lisp_parser)->visible_beg; |
| 363 | ptrdiff_t visible_end = XTS_PARSER (lisp_parser)->visible_end; | 363 | ptrdiff_t visible_end = XTS_PARSER (lisp_parser)->visible_end; |
| 364 | 364 | eassert (visible_beg >= 0); | |
| 365 | ptrdiff_t affected_start = | 365 | eassert (visible_beg <= visible_end); |
| 366 | max (visible_beg, start_byte) - visible_beg; | 366 | |
| 367 | ptrdiff_t affected_old_end = | 367 | /* AFFECTED_START/OLD_END/NEW_END are (0-based) offsets from |
| 368 | min (visible_end, affected_start + bytes_del); | 368 | VISIBLE_BEG. min(visi_end, max(visi_beg, value)) clips |
| 369 | ptrdiff_t affected_new_end = | 369 | value into [visi_beg, visi_end], and subtracting visi_beg |
| 370 | affected_start + bytes_ins; | 370 | gives the offset from visi_beg. */ |
| 371 | 371 | ptrdiff_t start_offset = | |
| 372 | ts_tree_edit_1 (tree, affected_start, affected_old_end, | 372 | min (visible_end, |
| 373 | affected_new_end); | 373 | max (visible_beg, start_byte)) - visible_beg; |
| 374 | XTS_PARSER (lisp_parser)->visible_end = affected_new_end; | 374 | ptrdiff_t old_end_offset = |
| 375 | min (visible_end, | ||
| 376 | max (visible_beg, old_end_byte)) - visible_beg; | ||
| 377 | ptrdiff_t new_end_offset = | ||
| 378 | min (visible_end, | ||
| 379 | max (visible_beg, new_end_byte)) - visible_beg; | ||
| 380 | eassert (start_offset <= old_end_offset); | ||
| 381 | eassert (start_offset <= new_end_offset); | ||
| 382 | |||
| 383 | ts_tree_edit_1 (tree, start_offset, old_end_offset, | ||
| 384 | new_end_offset); | ||
| 375 | XTS_PARSER (lisp_parser)->need_reparse = true; | 385 | XTS_PARSER (lisp_parser)->need_reparse = true; |
| 376 | XTS_PARSER (lisp_parser)->timestamp++; | 386 | XTS_PARSER (lisp_parser)->timestamp++; |
| 387 | |||
| 388 | /* VISIBLE_BEG/END records tree-sitter's range of view in | ||
| 389 | the buffer. Ee need to adjust them when tree-sitter's | ||
| 390 | view changes. */ | ||
| 391 | ptrdiff_t visi_beg_delta; | ||
| 392 | if (old_end_byte > new_end_byte) | ||
| 393 | { | ||
| 394 | /* Move backward. */ | ||
| 395 | visi_beg_delta = min (visible_beg, new_end_byte) | ||
| 396 | - min (visible_beg, old_end_byte); | ||
| 397 | } | ||
| 398 | else | ||
| 399 | { | ||
| 400 | /* Move forward. */ | ||
| 401 | visi_beg_delta = old_end_byte < visible_beg | ||
| 402 | ? new_end_byte - old_end_byte : 0; | ||
| 403 | } | ||
| 404 | XTS_PARSER (lisp_parser)->visible_beg | ||
| 405 | = visible_beg + visi_beg_delta; | ||
| 406 | XTS_PARSER (lisp_parser)->visible_end | ||
| 407 | = visible_end + visi_beg_delta | ||
| 408 | + (new_end_offset - old_end_offset); | ||
| 409 | eassert (XTS_PARSER (lisp_parser)->visible_beg >= 0); | ||
| 410 | eassert (XTS_PARSER (lisp_parser)->visible_beg | ||
| 411 | <= XTS_PARSER (lisp_parser)->visible_end); | ||
| 377 | } | 412 | } |
| 378 | } | 413 | } |
| 379 | } | 414 | } |
| @@ -389,6 +424,9 @@ ts_ensure_position_synced (Lisp_Object parser) | |||
| 389 | struct buffer *buffer = XBUFFER (XTS_PARSER (parser)->buffer); | 424 | struct buffer *buffer = XBUFFER (XTS_PARSER (parser)->buffer); |
| 390 | ptrdiff_t visible_beg = XTS_PARSER (parser)->visible_beg; | 425 | ptrdiff_t visible_beg = XTS_PARSER (parser)->visible_beg; |
| 391 | ptrdiff_t visible_end = XTS_PARSER (parser)->visible_end; | 426 | ptrdiff_t visible_end = XTS_PARSER (parser)->visible_end; |
| 427 | eassert (0 <= visible_beg); | ||
| 428 | eassert (visible_beg <= visible_end); | ||
| 429 | |||
| 392 | /* Before we parse or set ranges, catch up with the narrowing | 430 | /* Before we parse or set ranges, catch up with the narrowing |
| 393 | situation. We change visible_beg and visible_end to match | 431 | situation. We change visible_beg and visible_end to match |
| 394 | BUF_BEGV_BYTE and BUF_ZV_BYTE, and inform tree-sitter of the | 432 | BUF_BEGV_BYTE and BUF_ZV_BYTE, and inform tree-sitter of the |
| @@ -403,6 +441,7 @@ ts_ensure_position_synced (Lisp_Object parser) | |||
| 403 | /* Tree-sitter sees: insert at the beginning. */ | 441 | /* Tree-sitter sees: insert at the beginning. */ |
| 404 | ts_tree_edit_1 (tree, 0, 0, visible_beg - BUF_BEGV_BYTE (buffer)); | 442 | ts_tree_edit_1 (tree, 0, 0, visible_beg - BUF_BEGV_BYTE (buffer)); |
| 405 | visible_beg = BUF_BEGV_BYTE (buffer); | 443 | visible_beg = BUF_BEGV_BYTE (buffer); |
| 444 | eassert (visible_beg <= visible_end); | ||
| 406 | } | 445 | } |
| 407 | /* 2. Make sure visible_end = BUF_ZV_BYTE. */ | 446 | /* 2. Make sure visible_end = BUF_ZV_BYTE. */ |
| 408 | if (visible_end < BUF_ZV_BYTE (buffer)) | 447 | if (visible_end < BUF_ZV_BYTE (buffer)) |
| @@ -412,6 +451,7 @@ ts_ensure_position_synced (Lisp_Object parser) | |||
| 412 | visible_end - visible_beg, | 451 | visible_end - visible_beg, |
| 413 | BUF_ZV_BYTE (buffer) - visible_beg); | 452 | BUF_ZV_BYTE (buffer) - visible_beg); |
| 414 | visible_end = BUF_ZV_BYTE (buffer); | 453 | visible_end = BUF_ZV_BYTE (buffer); |
| 454 | eassert (visible_beg <= visible_end); | ||
| 415 | } | 455 | } |
| 416 | else if (visible_end > BUF_ZV_BYTE (buffer)) | 456 | else if (visible_end > BUF_ZV_BYTE (buffer)) |
| 417 | { | 457 | { |
| @@ -420,6 +460,7 @@ ts_ensure_position_synced (Lisp_Object parser) | |||
| 420 | visible_end - visible_beg, | 460 | visible_end - visible_beg, |
| 421 | BUF_ZV_BYTE (buffer) - visible_beg); | 461 | BUF_ZV_BYTE (buffer) - visible_beg); |
| 422 | visible_end = BUF_ZV_BYTE (buffer); | 462 | visible_end = BUF_ZV_BYTE (buffer); |
| 463 | eassert (visible_beg <= visible_end); | ||
| 423 | } | 464 | } |
| 424 | /* 3. Make sure visible_beg = BUF_BEGV_BYTE. */ | 465 | /* 3. Make sure visible_beg = BUF_BEGV_BYTE. */ |
| 425 | if (visible_beg < BUF_BEGV_BYTE (buffer)) | 466 | if (visible_beg < BUF_BEGV_BYTE (buffer)) |
| @@ -427,6 +468,7 @@ ts_ensure_position_synced (Lisp_Object parser) | |||
| 427 | /* Tree-sitter sees: delete at the beginning. */ | 468 | /* Tree-sitter sees: delete at the beginning. */ |
| 428 | ts_tree_edit_1 (tree, 0, BUF_BEGV_BYTE (buffer) - visible_beg, 0); | 469 | ts_tree_edit_1 (tree, 0, BUF_BEGV_BYTE (buffer) - visible_beg, 0); |
| 429 | visible_beg = BUF_BEGV_BYTE (buffer); | 470 | visible_beg = BUF_BEGV_BYTE (buffer); |
| 471 | eassert (visible_beg <= visible_end); | ||
| 430 | } | 472 | } |
| 431 | eassert (0 <= visible_beg); | 473 | eassert (0 <= visible_beg); |
| 432 | eassert (visible_beg <= visible_end); | 474 | eassert (visible_beg <= visible_end); |
| @@ -477,7 +519,8 @@ ts_ensure_parsed (Lisp_Object parser) | |||
| 477 | xsignal1 (Qtreesit_parse_error, buf); | 519 | xsignal1 (Qtreesit_parse_error, buf); |
| 478 | } | 520 | } |
| 479 | 521 | ||
| 480 | ts_tree_delete (tree); | 522 | if (tree != NULL) |
| 523 | ts_tree_delete (tree); | ||
| 481 | XTS_PARSER (parser)->tree = new_tree; | 524 | XTS_PARSER (parser)->tree = new_tree; |
| 482 | XTS_PARSER (parser)->need_reparse = false; | 525 | XTS_PARSER (parser)->need_reparse = false; |
| 483 | } | 526 | } |
| @@ -551,6 +594,7 @@ make_ts_parser (Lisp_Object buffer, TSParser *parser, | |||
| 551 | lisp_parser->need_reparse = true; | 594 | lisp_parser->need_reparse = true; |
| 552 | lisp_parser->visible_beg = BUF_BEGV (XBUFFER (buffer)); | 595 | lisp_parser->visible_beg = BUF_BEGV (XBUFFER (buffer)); |
| 553 | lisp_parser->visible_end = BUF_ZV (XBUFFER (buffer)); | 596 | lisp_parser->visible_end = BUF_ZV (XBUFFER (buffer)); |
| 597 | eassert (lisp_parser->visible_beg <= lisp_parser->visible_end); | ||
| 554 | return make_lisp_ptr (lisp_parser, Lisp_Vectorlike); | 598 | return make_lisp_ptr (lisp_parser, Lisp_Vectorlike); |
| 555 | } | 599 | } |
| 556 | 600 | ||
| @@ -673,10 +717,7 @@ function provided by a tree-sitter language dynamic module, e.g., | |||
| 673 | ts_parser_set_language (parser, lang); | 717 | ts_parser_set_language (parser, lang); |
| 674 | 718 | ||
| 675 | Lisp_Object lisp_parser | 719 | Lisp_Object lisp_parser |
| 676 | = make_ts_parser (buffer, parser, NULL, language); | 720 | = make_ts_parser (Fcurrent_buffer (), parser, NULL, language); |
| 677 | |||
| 678 | struct buffer *old_buffer = current_buffer; | ||
| 679 | set_buffer_internal (XBUFFER (buffer)); | ||
| 680 | 721 | ||
| 681 | Fset (Qtreesit_parser_list, | 722 | Fset (Qtreesit_parser_list, |
| 682 | Fcons (lisp_parser, Fsymbol_value (Qtreesit_parser_list))); | 723 | Fcons (lisp_parser, Fsymbol_value (Qtreesit_parser_list))); |
| @@ -835,6 +876,11 @@ nil. */) | |||
| 835 | (XTS_PARSER (parser)->parser, &len); | 876 | (XTS_PARSER (parser)->parser, &len); |
| 836 | if (len == 0) | 877 | if (len == 0) |
| 837 | return Qnil; | 878 | return Qnil; |
| 879 | |||
| 880 | /* Our return value depends on the buffer state (BUF_BEGV_BYTE, | ||
| 881 | etc), so we need to sync up. */ | ||
| 882 | ts_ensure_position_synced (parser); | ||
| 883 | |||
| 838 | struct buffer *buffer = XBUFFER (XTS_PARSER (parser)->buffer); | 884 | struct buffer *buffer = XBUFFER (XTS_PARSER (parser)->buffer); |
| 839 | 885 | ||
| 840 | Lisp_Object list = Qnil; | 886 | Lisp_Object list = Qnil; |
| @@ -843,6 +889,9 @@ nil. */) | |||
| 843 | TSRange range = ranges[idx]; | 889 | TSRange range = ranges[idx]; |
| 844 | uint32_t beg_byte = range.start_byte + BUF_BEGV_BYTE (buffer); | 890 | uint32_t beg_byte = range.start_byte + BUF_BEGV_BYTE (buffer); |
| 845 | uint32_t end_byte = range.end_byte + BUF_BEGV_BYTE (buffer); | 891 | uint32_t end_byte = range.end_byte + BUF_BEGV_BYTE (buffer); |
| 892 | eassert (BUF_BEGV_BYTE (buffer) <= beg_byte); | ||
| 893 | eassert (beg_byte <= end_byte); | ||
| 894 | eassert (end_byte <= BUF_ZV_BYTE (buffer)); | ||
| 846 | 895 | ||
| 847 | Lisp_Object lisp_range = | 896 | Lisp_Object lisp_range = |
| 848 | Fcons (make_fixnum (buf_bytepos_to_charpos (buffer, beg_byte)) , | 897 | Fcons (make_fixnum (buf_bytepos_to_charpos (buffer, beg_byte)) , |