diff options
| author | Eli Zaretskii | 2016-07-19 18:59:41 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2016-07-19 18:59:41 +0300 |
| commit | 00b6647651e4276ac5c47aa33e0fec6726469bc7 (patch) | |
| tree | 8e03635aac3f32b806b85e1a7bf976741d85cc30 /src | |
| parent | 439f3c3e567692b6823923d569a06ac206d1c3be (diff) | |
| download | emacs-00b6647651e4276ac5c47aa33e0fec6726469bc7.tar.gz emacs-00b6647651e4276ac5c47aa33e0fec6726469bc7.zip | |
Fix 'transpose-regions' when LEAVE-MARKERS arg is non-nil
* src/insdel.c (adjust_markers_bytepos): New function.
* src/lisp.h (adjust_markers_bytepos): Add prototype.
* src/insdel.c (replace_range, replace_range_2):
* src/editfns.c (Ftranspose_regions): Call
adjust_markers_bytepos. (Bug#5131)
* test/src/editfns-tests.el (transpose-test-reverse-word)
(transpose-test-get-byte-positions): New functions.
(transpose-ascii-regions-test)
(transpose-nonascii-regions-test-1)
(transpose-nonascii-regions-test-2): New tests.
Diffstat (limited to 'src')
| -rw-r--r-- | src/editfns.c | 8 | ||||
| -rw-r--r-- | src/insdel.c | 102 | ||||
| -rw-r--r-- | src/lisp.h | 2 |
3 files changed, 108 insertions, 4 deletions
diff --git a/src/editfns.c b/src/editfns.c index 4c8336b8c82..aed884ebe1c 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -5058,6 +5058,14 @@ Transposing beyond buffer boundaries is an error. */) | |||
| 5058 | start2_byte, start2_byte + len2_byte); | 5058 | start2_byte, start2_byte + len2_byte); |
| 5059 | fix_start_end_in_overlays (start1, end2); | 5059 | fix_start_end_in_overlays (start1, end2); |
| 5060 | } | 5060 | } |
| 5061 | else | ||
| 5062 | { | ||
| 5063 | /* The character positions of the markers remain intact, but we | ||
| 5064 | still need to update their byte positions, because the | ||
| 5065 | transposed regions might include multibyte sequences which | ||
| 5066 | make some original byte positions of the markers invalid. */ | ||
| 5067 | adjust_markers_bytepos (start1, start1_byte, end2, end2_byte, 0); | ||
| 5068 | } | ||
| 5061 | 5069 | ||
| 5062 | signal_after_change (start1, end2 - start1, end2 - start1); | 5070 | signal_after_change (start1, end2 - start1, end2 - start1); |
| 5063 | return Qnil; | 5071 | return Qnil; |
diff --git a/src/insdel.c b/src/insdel.c index 4ad1074f5f7..ec7bbb3e715 100644 --- a/src/insdel.c +++ b/src/insdel.c | |||
| @@ -364,6 +364,78 @@ adjust_markers_for_replace (ptrdiff_t from, ptrdiff_t from_byte, | |||
| 364 | check_markers (); | 364 | check_markers (); |
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | /* Starting at POS (BYTEPOS), find the byte position corresponding to | ||
| 368 | ENDPOS, which could be either before or after POS. */ | ||
| 369 | static ptrdiff_t | ||
| 370 | count_bytes (ptrdiff_t pos, ptrdiff_t bytepos, ptrdiff_t endpos) | ||
| 371 | { | ||
| 372 | eassert (BEG_BYTE <= bytepos && bytepos <= Z_BYTE | ||
| 373 | && BEG <= endpos && endpos <= Z); | ||
| 374 | |||
| 375 | if (pos <= endpos) | ||
| 376 | for ( ; pos < endpos; pos++) | ||
| 377 | INC_POS (bytepos); | ||
| 378 | else | ||
| 379 | for ( ; pos > endpos; pos--) | ||
| 380 | DEC_POS (bytepos); | ||
| 381 | |||
| 382 | return bytepos; | ||
| 383 | } | ||
| 384 | |||
| 385 | /* Adjust byte positions of markers when their character positions | ||
| 386 | didn't change. This is used in several places that replace text, | ||
| 387 | but keep the character positions of the markers unchanged -- the | ||
| 388 | byte positions could still change due to different numbers of bytes | ||
| 389 | in the new text. | ||
| 390 | |||
| 391 | FROM (FROM_BYTE) and TO (TO_BYTE) specify the region of text where | ||
| 392 | changes have been done. TO_Z, if non-zero, means all the markers | ||
| 393 | whose positions are after TO should also be adjusted. */ | ||
| 394 | void | ||
| 395 | adjust_markers_bytepos (ptrdiff_t from, ptrdiff_t from_byte, | ||
| 396 | ptrdiff_t to, ptrdiff_t to_byte, int to_z) | ||
| 397 | { | ||
| 398 | register struct Lisp_Marker *m; | ||
| 399 | ptrdiff_t beg = from, begbyte = from_byte; | ||
| 400 | |||
| 401 | adjust_suspend_auto_hscroll (from, to); | ||
| 402 | |||
| 403 | if (Z == Z_BYTE || (!to_z && to == to_byte)) | ||
| 404 | { | ||
| 405 | /* Make sure each affected marker's bytepos is equal to | ||
| 406 | its charpos. */ | ||
| 407 | for (m = BUF_MARKERS (current_buffer); m; m = m->next) | ||
| 408 | { | ||
| 409 | if (m->bytepos > from_byte | ||
| 410 | && (to_z || m->bytepos <= to_byte)) | ||
| 411 | m->bytepos = m->charpos; | ||
| 412 | } | ||
| 413 | } | ||
| 414 | else | ||
| 415 | { | ||
| 416 | for (m = BUF_MARKERS (current_buffer); m; m = m->next) | ||
| 417 | { | ||
| 418 | /* Recompute each affected marker's bytepos. */ | ||
| 419 | if (m->bytepos > from_byte | ||
| 420 | && (to_z || m->bytepos <= to_byte)) | ||
| 421 | { | ||
| 422 | if (m->charpos < beg | ||
| 423 | && beg - m->charpos > m->charpos - from) | ||
| 424 | { | ||
| 425 | beg = from; | ||
| 426 | begbyte = from_byte; | ||
| 427 | } | ||
| 428 | m->bytepos = count_bytes (beg, begbyte, m->charpos); | ||
| 429 | beg = m->charpos; | ||
| 430 | begbyte = m->bytepos; | ||
| 431 | } | ||
| 432 | } | ||
| 433 | } | ||
| 434 | |||
| 435 | /* Make sure cached charpos/bytepos is invalid. */ | ||
| 436 | clear_charpos_cache (current_buffer); | ||
| 437 | } | ||
| 438 | |||
| 367 | 439 | ||
| 368 | void | 440 | void |
| 369 | buffer_overflow (void) | 441 | buffer_overflow (void) |
| @@ -1397,6 +1469,16 @@ replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new, | |||
| 1397 | if (markers) | 1469 | if (markers) |
| 1398 | adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del, | 1470 | adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del, |
| 1399 | inschars, outgoing_insbytes); | 1471 | inschars, outgoing_insbytes); |
| 1472 | else | ||
| 1473 | { | ||
| 1474 | /* The character positions of the markers remain intact, but we | ||
| 1475 | still need to update their byte positions, because the | ||
| 1476 | deleted and the inserted text might have multibyte sequences | ||
| 1477 | which make the original byte positions of the markers | ||
| 1478 | invalid. */ | ||
| 1479 | adjust_markers_bytepos (from, from_byte, from + inschars, | ||
| 1480 | from_byte + outgoing_insbytes, 1); | ||
| 1481 | } | ||
| 1400 | 1482 | ||
| 1401 | /* Adjust the overlay center as needed. This must be done after | 1483 | /* Adjust the overlay center as needed. This must be done after |
| 1402 | adjusting the markers that bound the overlays. */ | 1484 | adjusting the markers that bound the overlays. */ |
| @@ -1509,10 +1591,22 @@ replace_range_2 (ptrdiff_t from, ptrdiff_t from_byte, | |||
| 1509 | eassert (GPT <= GPT_BYTE); | 1591 | eassert (GPT <= GPT_BYTE); |
| 1510 | 1592 | ||
| 1511 | /* Adjust markers for the deletion and the insertion. */ | 1593 | /* Adjust markers for the deletion and the insertion. */ |
| 1512 | if (markers | 1594 | if (! (nchars_del == 1 && inschars == 1 && nbytes_del == insbytes)) |
| 1513 | && ! (nchars_del == 1 && inschars == 1 && nbytes_del == insbytes)) | 1595 | { |
| 1514 | adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del, | 1596 | if (markers) |
| 1515 | inschars, insbytes); | 1597 | adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del, |
| 1598 | inschars, insbytes); | ||
| 1599 | else | ||
| 1600 | { | ||
| 1601 | /* The character positions of the markers remain intact, but | ||
| 1602 | we still need to update their byte positions, because the | ||
| 1603 | deleted and the inserted text might have multibyte | ||
| 1604 | sequences which make the original byte positions of the | ||
| 1605 | markers invalid. */ | ||
| 1606 | adjust_markers_bytepos (from, from_byte, from + inschars, | ||
| 1607 | from_byte + insbytes, 1); | ||
| 1608 | } | ||
| 1609 | } | ||
| 1516 | 1610 | ||
| 1517 | /* Adjust the overlay center as needed. This must be done after | 1611 | /* Adjust the overlay center as needed. This must be done after |
| 1518 | adjusting the markers that bound the overlays. */ | 1612 | adjusting the markers that bound the overlays. */ |
diff --git a/src/lisp.h b/src/lisp.h index e0eb52a84ea..48c27281643 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3528,6 +3528,8 @@ extern void adjust_after_insert (ptrdiff_t, ptrdiff_t, ptrdiff_t, | |||
| 3528 | ptrdiff_t, ptrdiff_t); | 3528 | ptrdiff_t, ptrdiff_t); |
| 3529 | extern void adjust_markers_for_delete (ptrdiff_t, ptrdiff_t, | 3529 | extern void adjust_markers_for_delete (ptrdiff_t, ptrdiff_t, |
| 3530 | ptrdiff_t, ptrdiff_t); | 3530 | ptrdiff_t, ptrdiff_t); |
| 3531 | extern void adjust_markers_bytepos (ptrdiff_t, ptrdiff_t, | ||
| 3532 | ptrdiff_t, ptrdiff_t, int); | ||
| 3531 | extern void replace_range (ptrdiff_t, ptrdiff_t, Lisp_Object, bool, bool, bool); | 3533 | extern void replace_range (ptrdiff_t, ptrdiff_t, Lisp_Object, bool, bool, bool); |
| 3532 | extern void replace_range_2 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, | 3534 | extern void replace_range_2 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, |
| 3533 | const char *, ptrdiff_t, ptrdiff_t, bool); | 3535 | const char *, ptrdiff_t, ptrdiff_t, bool); |