aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2016-07-19 18:59:41 +0300
committerEli Zaretskii2016-07-19 18:59:41 +0300
commit00b6647651e4276ac5c47aa33e0fec6726469bc7 (patch)
tree8e03635aac3f32b806b85e1a7bf976741d85cc30 /src
parent439f3c3e567692b6823923d569a06ac206d1c3be (diff)
downloademacs-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.c8
-rw-r--r--src/insdel.c102
-rw-r--r--src/lisp.h2
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. */
369static ptrdiff_t
370count_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. */
394void
395adjust_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
368void 440void
369buffer_overflow (void) 441buffer_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);
3529extern void adjust_markers_for_delete (ptrdiff_t, ptrdiff_t, 3529extern void adjust_markers_for_delete (ptrdiff_t, ptrdiff_t,
3530 ptrdiff_t, ptrdiff_t); 3530 ptrdiff_t, ptrdiff_t);
3531extern void adjust_markers_bytepos (ptrdiff_t, ptrdiff_t,
3532 ptrdiff_t, ptrdiff_t, int);
3531extern void replace_range (ptrdiff_t, ptrdiff_t, Lisp_Object, bool, bool, bool); 3533extern void replace_range (ptrdiff_t, ptrdiff_t, Lisp_Object, bool, bool, bool);
3532extern void replace_range_2 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, 3534extern 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);