(Freplace_buffer_contents): Preserve markers more carefully
Use `replace_range` rather than `delete+insert`. * src/insdel.c (replace_range): Allow NEW to specify a chunk of buffer text. * src/editfns.c (Freplace_buffer_contents): Use it. * test/src/editfns-tests.el (replace-buffer-contents-1): Remove incorrect check which happened to succeed because point was not preserved carefully enough. Make the replacement text share a bit more content to make the test a bit more strict. (editfns-tests--replace-region): Doesn't fail any more.
This commit is contained in:
parent
e1ceee716d
commit
40d8650d51
3 changed files with 82 additions and 29 deletions
|
@ -2050,9 +2050,10 @@ nil. */)
|
|||
|
||||
if (early_abort)
|
||||
{
|
||||
/* FIXME: Use 'replace_range'! */
|
||||
del_range (min_a, ZV);
|
||||
Finsert_buffer_substring (source, Qnil,Qnil);
|
||||
Lisp_Object src = CALLN (Fvector, source_buffer,
|
||||
make_fixnum (BUF_BEGV (b)),
|
||||
make_fixnum (BUF_ZV (b)));
|
||||
replace_range (BEGV, ZV, src, true, false, false);
|
||||
SAFE_FREE_UNBIND_TO (count, Qnil);
|
||||
return Qnil;
|
||||
}
|
||||
|
@ -2075,6 +2076,7 @@ nil. */)
|
|||
|
||||
ptrdiff_t i = size_a;
|
||||
ptrdiff_t j = size_b;
|
||||
Lisp_Object src = CALLN (Fvector, source_buffer, Qnil, Qnil);
|
||||
/* Walk backwards through the lists of changes. This was also
|
||||
cargo-culted from src/analyze.c in GNU Diffutils. Because we
|
||||
walk backwards, we don’t have to keep the positions in sync. */
|
||||
|
@ -2101,14 +2103,9 @@ nil. */)
|
|||
eassert (beg_b <= end_b);
|
||||
eassert (beg_a < end_a || beg_b < end_b);
|
||||
/* FIXME: Use 'replace_range'! */
|
||||
if (beg_a < end_a)
|
||||
del_range (beg_a, end_a);
|
||||
if (beg_b < end_b)
|
||||
{
|
||||
SET_PT (beg_a);
|
||||
Finsert_buffer_substring (source, make_fixed_natnum (beg_b),
|
||||
make_fixed_natnum (end_b));
|
||||
}
|
||||
ASET (src, 1, make_fixed_natnum (beg_b));
|
||||
ASET (src, 2, make_fixed_natnum (end_b));
|
||||
replace_range (beg_a, end_a, src, true, false, false);
|
||||
}
|
||||
--i;
|
||||
--j;
|
||||
|
|
76
src/insdel.c
76
src/insdel.c
|
@ -1428,12 +1428,29 @@ replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
|
|||
bool run_mod_hooks, bool inherit,
|
||||
bool adjust_match_data)
|
||||
{
|
||||
ptrdiff_t inschars = SCHARS (new);
|
||||
ptrdiff_t insbytes = SBYTES (new);
|
||||
ptrdiff_t inschars;
|
||||
ptrdiff_t insbeg;
|
||||
struct buffer *insbuf;
|
||||
if (STRINGP (new))
|
||||
{
|
||||
insbuf = NULL;
|
||||
insbeg = 0;
|
||||
inschars = SCHARS (new);
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_VECTOR (new);
|
||||
/* Let `Faref' signal an error if it's too small. */
|
||||
Lisp_Object insend = Faref (new, make_fixnum (2));
|
||||
CHECK_BUFFER (AREF (new, 0));
|
||||
CHECK_FIXNUM (AREF (new, 1));
|
||||
CHECK_FIXNUM (insend);
|
||||
insbuf = XBUFFER (AREF (new, 0));
|
||||
insbeg = XFIXNUM (AREF (new, 1));
|
||||
inschars = XFIXNUM (insend) - insbeg;
|
||||
}
|
||||
ptrdiff_t from_byte, to_byte;
|
||||
ptrdiff_t nbytes_del, nchars_del;
|
||||
INTERVAL intervals;
|
||||
ptrdiff_t outgoing_insbytes = insbytes;
|
||||
Lisp_Object deletion;
|
||||
|
||||
check_markers ();
|
||||
|
@ -1459,17 +1476,51 @@ replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
|
|||
nchars_del = to - from;
|
||||
nbytes_del = to_byte - from_byte;
|
||||
|
||||
if (nbytes_del <= 0 && insbytes == 0)
|
||||
if (nbytes_del <= 0 && inschars == 0)
|
||||
return;
|
||||
|
||||
ptrdiff_t insbeg_bytes, insend_bytes;
|
||||
ptrdiff_t insbytes;
|
||||
unsigned char *insbeg_ptr;
|
||||
bool new_is_multibyte;
|
||||
if (!insbuf)
|
||||
{
|
||||
new_is_multibyte = STRING_MULTIBYTE (new);
|
||||
insbytes = SBYTES (new);
|
||||
insbeg_ptr = SDATA (new);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_is_multibyte = !NILP (BVAR (insbuf, enable_multibyte_characters));
|
||||
ptrdiff_t insend = insbeg + inschars;
|
||||
if (new_is_multibyte)
|
||||
{
|
||||
insbeg_bytes = buf_charpos_to_bytepos (insbuf, insbeg);
|
||||
insend_bytes = buf_charpos_to_bytepos (insbuf, insend);
|
||||
}
|
||||
else
|
||||
{
|
||||
insbeg_bytes = insbeg;
|
||||
insend_bytes = insend;
|
||||
}
|
||||
insbytes = insend_bytes - insbeg_bytes;
|
||||
if (insbuf->text->gpt_byte > insbeg_bytes
|
||||
&& insbuf->text->gpt_byte < insend_bytes)
|
||||
move_gap_both (insbeg, insbeg_bytes);
|
||||
insbeg_ptr = BUF_BYTE_ADDRESS (insbuf, insbeg_bytes);
|
||||
eassert (insbuf->text->gpt_byte <= insbeg_bytes
|
||||
|| insbuf->text->gpt_byte >= insend_bytes);
|
||||
}
|
||||
ptrdiff_t outgoing_insbytes = insbytes;
|
||||
|
||||
/* Make OUTGOING_INSBYTES describe the text
|
||||
as it will be inserted in this buffer. */
|
||||
|
||||
if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
|
||||
outgoing_insbytes = inschars;
|
||||
else if (! STRING_MULTIBYTE (new))
|
||||
else if (! new_is_multibyte)
|
||||
outgoing_insbytes
|
||||
= count_size_as_multibyte (SDATA (new), insbytes);
|
||||
= count_size_as_multibyte (insbeg_ptr, insbytes);
|
||||
|
||||
/* Make sure the gap is somewhere in or next to what we are deleting. */
|
||||
if (from > GPT)
|
||||
|
@ -1504,8 +1555,8 @@ replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
|
|||
|
||||
/* Copy the string text into the buffer, perhaps converting
|
||||
between single-byte and multibyte. */
|
||||
copy_text (SDATA (new), GPT_ADDR, insbytes,
|
||||
STRING_MULTIBYTE (new),
|
||||
copy_text (insbeg_ptr, GPT_ADDR, insbytes,
|
||||
new_is_multibyte,
|
||||
! NILP (BVAR (current_buffer, enable_multibyte_characters)));
|
||||
|
||||
#ifdef BYTE_COMBINING_DEBUG
|
||||
|
@ -1548,7 +1599,10 @@ replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
|
|||
|
||||
/* Get the intervals for the part of the string we are inserting--
|
||||
not including the combined-before bytes. */
|
||||
intervals = string_intervals (new);
|
||||
INTERVAL intervals
|
||||
= (!insbuf ? string_intervals (new)
|
||||
: copy_intervals (buffer_intervals (insbuf), insbeg, inschars));
|
||||
|
||||
/* Insert those intervals. */
|
||||
graft_intervals_into_buffer (intervals, from, inschars,
|
||||
current_buffer, inherit);
|
||||
|
@ -1571,7 +1625,7 @@ replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
|
|||
CHARS_MODIFF = MODIFF;
|
||||
|
||||
if (adjust_match_data)
|
||||
update_search_regs (from, to, from + SCHARS (new));
|
||||
update_search_regs (from, to, from + inschars);
|
||||
|
||||
if (run_mod_hooks)
|
||||
{
|
||||
|
|
|
@ -280,23 +280,25 @@
|
|||
|
||||
(ert-deftest replace-buffer-contents-1 ()
|
||||
(with-temp-buffer
|
||||
(insert #("source" 2 4 (prop 7)))
|
||||
(insert #("source " 2 4 (prop 7)))
|
||||
(let ((source (current-buffer)))
|
||||
(with-temp-buffer
|
||||
(insert "before dest after")
|
||||
(let ((marker (set-marker (make-marker) 14)))
|
||||
(save-restriction
|
||||
(narrow-to-region 8 12)
|
||||
(replace-buffer-contents source))
|
||||
(narrow-to-region 8 13)
|
||||
(goto-char 12)
|
||||
(should (looking-at " \\'"))
|
||||
(replace-buffer-contents source)
|
||||
(should (looking-at " \\'")))
|
||||
(should (equal (marker-buffer marker) (current-buffer)))
|
||||
(should (equal (marker-position marker) 16)))
|
||||
(should (equal-including-properties
|
||||
(buffer-string)
|
||||
#("before source after" 9 11 (prop 7))))
|
||||
(should (equal (point) 9))))
|
||||
#("before source after" 9 11 (prop 7))))))
|
||||
(should (equal-including-properties
|
||||
(buffer-string)
|
||||
#("source" 2 4 (prop 7))))))
|
||||
#("source " 2 4 (prop 7))))))
|
||||
|
||||
(ert-deftest replace-buffer-contents-2 ()
|
||||
(with-temp-buffer
|
||||
|
@ -332,7 +334,7 @@
|
|||
(replace-buffer-contents str-buf))))))))
|
||||
|
||||
(ert-deftest editfns-tests--replace-region ()
|
||||
:expected-result :failed
|
||||
;; :expected-result :failed
|
||||
(with-temp-buffer
|
||||
(insert "here is some text")
|
||||
(let ((m5n (copy-marker (+ (point-min) 5)))
|
||||
|
|
Loading…
Add table
Reference in a new issue