aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard M. Stallman1994-04-29 23:22:51 +0000
committerRichard M. Stallman1994-04-29 23:22:51 +0000
commitb229b8d187a65116800e56f7ebd35edbecbcf026 (patch)
treed13e876b6b75a4ecd1db6f03616c5388bf613285
parentc15c5d408d696928862ca2848a359231e373556c (diff)
downloademacs-b229b8d187a65116800e56f7ebd35edbecbcf026.tar.gz
emacs-b229b8d187a65116800e56f7ebd35edbecbcf026.zip
(Ftranspose_regions): New function.
(transpose_markers): Helper func for above. (syms_of_frame): Call defsubr for Stranspose_regions.
-rw-r--r--src/editfns.c301
1 files changed, 301 insertions, 0 deletions
diff --git a/src/editfns.c b/src/editfns.c
index fee9d9e687f..5464c3ac717 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -1609,6 +1609,306 @@ Case is ignored if `case-fold-search' is non-nil in the current buffer.")
1609 return Qt; 1609 return Qt;
1610 return Qnil; 1610 return Qnil;
1611} 1611}
1612
1613/* Transpose the markers in two regions of the current buffer, and
1614 adjust the ones between them if necessary (i.e.: if the regions
1615 differ in size).
1616
1617 Traverses the entire marker list of the buffer to do so, adding an
1618 appropriate amount to some, subtracting from some, and leaving the
1619 rest untouched. Most of this is copied from adjust_markers in insdel.c.
1620
1621 It's caller's job to see that (start1 <= end1 <= start2 <= end2),
1622 and that the buffer gap will not conflict with the markers. This
1623 last requirement is odd and maybe should be taken out, but it works
1624 for now because Ftranspose_regions does in fact guarantee that, in
1625 addition to providing universal health-care coverage. */
1626
1627void
1628transpose_markers (start1, end1, start2, end2)
1629 register int start1, end1, start2, end2;
1630{
1631 register int amt1, amt2, diff, mpos;
1632 register Lisp_Object marker;
1633 register struct Lisp_Marker *m;
1634
1635 /* Internally, marker positions take the gap into account, so if the
1636 * gap is before one or both of the regions, the region's limits
1637 * must be adjusted to compensate. The caller guaranteed that the
1638 * gap is not inside any of the regions, however, so this is fairly
1639 * simple.
1640 */
1641 if (GPT < start1)
1642 {
1643 register int gs = GAP_SIZE;
1644 start1 += gs; end1 += gs;
1645 start2 += gs; end2 += gs;
1646 }
1647 else if (GPT < start2)
1648 {
1649 /* If the regions are of equal size, the gap could, in theory,
1650 * be somewhere between them. */
1651 register int gs = GAP_SIZE;
1652 start2 += gs; end2 += gs;
1653 }
1654
1655 /* The difference between the region's lengths */
1656 diff = (end2 - start2) - (end1 - start1);
1657
1658 /* For shifting each marker in a region by the length of the other
1659 * region plus the distance between the regions.
1660 */
1661 amt1 = (end2 - start2) + (start2 - end1);
1662 amt2 = (end1 - start1) + (start2 - end1);
1663
1664 marker = current_buffer->markers;
1665
1666 while (!NILP (marker))
1667 {
1668 m = XMARKER (marker);
1669 mpos = m->bufpos;
1670 if (mpos >= start1 && mpos < end1) /* in region 1 */
1671 {
1672 m->bufpos += amt1;
1673 }
1674 else if (mpos >= start2 && mpos < end2) /* in region 2 */
1675 {
1676 m->bufpos -= amt2;
1677 }
1678 else if (mpos >= end1 && mpos < start2) /* between the regions */
1679 {
1680 m->bufpos += diff;
1681 }
1682 marker = m->chain;
1683 }
1684}
1685
1686DEFUN ("transpose-regions", Ftranspose_regions, Stranspose_regions, 4, 5, 0,
1687 "Transpose region START1 to END1 with START2 to END2.\n\
1688The regions may not be overlapping, because the size of the buffer is\n\
1689never changed in a transposition.\n\
1690\n\
1691Optional fifth arg LEAVE_MARKERS, if non-nil, means don't transpose\n\
1692any markers that happen to be located in the regions.\n\
1693\n\
1694Transposing beyond buffer boundaries is an error.")
1695 (startr1, endr1, startr2, endr2, leave_markers)
1696 Lisp_Object startr1, endr1, startr2, endr2, leave_markers;
1697{
1698 register int start1, end1, start2, end2,
1699 gap, len1, len_mid, len2;
1700 char *start1_addr, *start2_addr, *temp;
1701
1702#ifdef USE_TEXT_PROPERTIES
1703 INTERVAL cur_intv, tmp_interval1, tmp_interval_mid, tmp_interval2;
1704 cur_intv = current_buffer->intervals;
1705#endif /* USE_TEXT_PROPERTIES */
1706
1707 validate_region (&startr1, &endr1);
1708 validate_region (&startr2, &endr2);
1709
1710 start1 = XFASTINT (startr1);
1711 end1 = XFASTINT (endr1);
1712 start2 = XFASTINT (startr2);
1713 end2 = XFASTINT (endr2);
1714 gap = GPT;
1715
1716 /* Swap the regions if they're reversed. */
1717 if (start2 < end1)
1718 {
1719 register int glumph = start1;
1720 start1 = start2;
1721 start2 = glumph;
1722 glumph = end1;
1723 end1 = end2;
1724 end2 = glumph;
1725 }
1726
1727 start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1);
1728 start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2);
1729 len1 = end1 - start1;
1730 len2 = end2 - start2;
1731
1732 if (start2 < end1)
1733 error ("transposed regions not properly ordered");
1734 else if (start1 == end1 || start2 == end2)
1735 error ("transposed region may not be of length 0");
1736
1737 /* The possibilities are:
1738 1. Adjacent (contiguous) regions, or separate but equal regions
1739 (no, really equal, in this case!), or
1740 2. Separate regions of unequal size.
1741
1742 The worst case is usually No. 2. It means that (aside from
1743 potential need for getting the gap out of the way), there also
1744 needs to be a shifting of the text between the two regions. So
1745 if they are spread far apart, we are that much slower... sigh. */
1746
1747 /* It must be pointed out that the really studly thing to do would
1748 be not to move the gap at all, but to leave it in place and work
1749 around it if necessary. This would be extremely efficient,
1750 especially considering that people are likely to do
1751 transpositions near where they are working interactively, which
1752 is exactly where the gap would be found. However, such code
1753 would be much harder to write and to read. So, if you are
1754 reading this comment and are feeling squirrely, by all means have
1755 a go! I just didn't feel like doing it, so I will simply move
1756 the gap the minimum distance to get it out of the way, and then
1757 deal with an unbroken array. */
1758
1759 /* Hmmm... how about checking to see if the gap is large
1760 enough to use as the temporary storage? That would avoid an
1761 allocation... interesting. Later, don't fool with it now. */
1762
1763 /* Working without memmove, for portability (sigh), so must be
1764 careful of overlapping subsections of the array... */
1765
1766 if (end1 == start2) /* adjacent regions */
1767 {
1768 if ((start1 < gap) && (gap <= end2))
1769 {
1770 if ((gap - start1) < (end2 - gap) || (end2 == Z))
1771 move_gap (start1);
1772 else
1773 move_gap (end2 + 1);
1774 }
1775 modify_region (current_buffer, start1, end2);
1776 record_change (start1, len1 + len2);
1777
1778#ifdef USE_TEXT_PROPERTIES
1779 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
1780 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
1781 Fset_text_properties (start1, end2, Qnil, Qnil);
1782#endif /* USE_TEXT_PROPERTIES */
1783
1784 /* First region smaller than second. */
1785 if (len1 < len2)
1786 {
1787 temp = alloca (len2);
1788 bcopy (start2_addr, temp, len2);
1789 bcopy (start1_addr, start1_addr + len2, len1);
1790 bcopy (temp, start1_addr, len2);
1791 }
1792 else
1793 /* First region not smaller than second. */
1794 {
1795 temp = alloca (len1);
1796 bcopy (start1_addr, temp, len1);
1797 bcopy (start2_addr, start1_addr, len2);
1798 bcopy (temp, start1_addr + len2, len1);
1799 }
1800#ifdef USE_TEXT_PROPERTIES
1801 graft_intervals_into_buffer (tmp_interval1, start1 + len2,
1802 len1, current_buffer, 0);
1803 graft_intervals_into_buffer (tmp_interval2, start1,
1804 len2, current_buffer, 0);
1805#endif /* USE_TEXT_PROPERTIES */
1806 }
1807 /* Non-adjacent regions, because end1 != start2, bleagh... */
1808 else
1809 {
1810 if (((start1 < gap) && (gap <= end1)) || (end2 == Z))
1811 move_gap (start1);
1812 else if ((start2 < gap) && (gap <= end2))
1813 move_gap (end2 + 1);
1814
1815 if (len1 == len2)
1816 /* Regions are same size, though, how nice. */
1817 {
1818 modify_region (current_buffer, start1, end1);
1819 modify_region (current_buffer, start2, end2);
1820 record_change (start1, len1);
1821 record_change (start2, len2);
1822#ifdef USE_TEXT_PROPERTIES
1823 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
1824 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
1825 Fset_text_properties (start1, end1, Qnil, Qnil);
1826 Fset_text_properties (start2, end2, Qnil, Qnil);
1827#endif /* USE_TEXT_PROPERTIES */
1828
1829 temp = alloca (len1);
1830 bcopy (start1_addr, temp, len1);
1831 bcopy (start2_addr, start1_addr, len2);
1832 bcopy (temp, start2_addr, len1);
1833#ifdef USE_TEXT_PROPERTIES
1834 graft_intervals_into_buffer (tmp_interval1, start2,
1835 len1, current_buffer, 0);
1836 graft_intervals_into_buffer (tmp_interval2, start1,
1837 len2, current_buffer, 0);
1838#endif /* USE_TEXT_PROPERTIES */
1839 }
1840
1841 else if (len1 < len2) /* Second region larger than first */
1842 /* Non-adjacent & unequal size, area between must also be shifted. */
1843 {
1844 len_mid = start2 - end1;
1845 modify_region (current_buffer, start1, end2);
1846 record_change (start1, (end2 - start1));
1847#ifdef USE_TEXT_PROPERTIES
1848 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
1849 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
1850 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
1851 Fset_text_properties (start1, end2, Qnil, Qnil);
1852#endif /* USE_TEXT_PROPERTIES */
1853
1854 temp = alloca (len_mid + len2); /* holds mid area & region 2 */
1855 bcopy (start1_addr + len1, temp, len_mid);
1856 bcopy (start2_addr, temp + len_mid, len2);
1857 bcopy (start1_addr, start1_addr + len_mid + len2, len1);
1858 bcopy (temp + len_mid, start1_addr, len2);
1859 bcopy (temp, start1_addr + len2, len_mid);
1860#ifdef USE_TEXT_PROPERTIES
1861 graft_intervals_into_buffer (tmp_interval1, end2 - len1,
1862 len1, current_buffer, 0);
1863 graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
1864 len_mid, current_buffer, 0);
1865 graft_intervals_into_buffer (tmp_interval2, start1,
1866 len2, current_buffer, 0);
1867#endif /* USE_TEXT_PROPERTIES */
1868 }
1869 else
1870 /* Second region smaller than first. */
1871 {
1872 len_mid = start2 - end1;
1873 record_change (start1, (end2 - start1));
1874 modify_region (current_buffer, start1, end2);
1875
1876#ifdef USE_TEXT_PROPERTIES
1877 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
1878 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
1879 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
1880 Fset_text_properties (start1, end2, Qnil, Qnil);
1881#endif /* USE_TEXT_PROPERTIES */
1882
1883 temp = alloca (len_mid + len1); /* holds mid area & region 1 */
1884 bcopy (start1_addr + len1, temp, len_mid);
1885 bcopy (start1_addr, temp + len_mid, len1);
1886 bcopy (start2_addr, start1_addr, len2);
1887 bcopy (temp + len_mid, start1_addr + len2 + len_mid, len1);
1888 bcopy (temp, start1_addr + len2, len_mid);
1889#ifdef USE_TEXT_PROPERTIES
1890 graft_intervals_into_buffer (tmp_interval1, end2 - len1,
1891 len1, current_buffer, 0);
1892 graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
1893 len_mid, current_buffer, 0);
1894 graft_intervals_into_buffer (tmp_interval2, start1,
1895 len2, current_buffer, 0);
1896#endif /* USE_TEXT_PROPERTIES */
1897 }
1898 }
1899
1900 /* todo: this will be slow, because for every transposition, we
1901 traverse the whole friggin marker list. Possible solutions:
1902 somehow get a list of *all* the markers across multiple
1903 transpositions and do it all in one swell phoop. Or maybe modify
1904 Emacs' marker code to keep an ordered list or tree. This might
1905 be nicer, and more beneficial in the long run, but would be a
1906 bunch of work. Plus the way they're arranged now is nice. */
1907 if (NILP (leave_markers))
1908 transpose_markers (start1, end1, start2, end2);
1909
1910 return Qnil;
1911}
1612 1912
1613 1913
1614void 1914void
@@ -1675,4 +1975,5 @@ syms_of_editfns ()
1675 defsubr (&Swiden); 1975 defsubr (&Swiden);
1676 defsubr (&Snarrow_to_region); 1976 defsubr (&Snarrow_to_region);
1677 defsubr (&Ssave_restriction); 1977 defsubr (&Ssave_restriction);
1978 defsubr (&Stranspose_regions);
1678} 1979}