summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lisp/emacs-lisp/subr-x.el27
-rw-r--r--lisp/json.el8
-rw-r--r--lisp/subr.el26
-rw-r--r--src/editfns.c314
4 files changed, 220 insertions, 155 deletions
diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 7d9f0bba4c7..5020772ddee 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -250,6 +250,33 @@ TRIM-LEFT and TRIM-RIGHT default to \"[ \\t\\n\\r]+\"."
(substring string 0 (- (length string) (length suffix)))
string))
+(defun replace-region-contents (beg end replace-fn &optional max-costs)
+ "Replace the region between BEG and END using REPLACE-FN.
+REPLACE-FN runs on the current buffer narrowed to the region. It
+should return either a string or a buffer replacing the region.
+
+The replacement is performed using `replace-buffer-contents'
+which also describes the MAX-COSTS argument.
+
+Note: If the replacement is a string, it'll be placed in a
+temporary buffer so that `replace-buffer-contents' can operate on
+it. Therefore, if you already have the replacement in a buffer,
+it makes no sense to convert it to a string using
+`buffer-substring' or similar."
+ (save-excursion
+ (save-restriction
+ (narrow-to-region beg end)
+ (goto-char (point-min))
+ (let ((repl (funcall replace-fn)))
+ (if (bufferp repl)
+ (replace-buffer-contents repl max-costs)
+ (let ((source-buffer (current-buffer)))
+ (with-temp-buffer
+ (insert repl)
+ (let ((tmp-buffer (current-buffer)))
+ (set-buffer source-buffer)
+ (replace-buffer-contents tmp-buffer max-costs)))))))))
+
(provide 'subr-x)
;;; subr-x.el ends here
diff --git a/lisp/json.el b/lisp/json.el
index 19b8f09dcda..cc0a6fdfd4f 100644
--- a/lisp/json.el
+++ b/lisp/json.el
@@ -49,10 +49,13 @@
;; 2008-02-21 - Installed in GNU Emacs.
;; 2011-10-17 - Patch `json-alist-p' and `json-plist-p' to avoid recursion -tzz
;; 2012-10-25 - Added pretty-printed reformatting -Ryan Crum (ryan@ryancrum.org)
+;; 2019-02-02 - Pretty-printing now uses replace-region-contents and support for
+;; minimization -tsdh
;;; Code:
(require 'map)
+(require 'subr-x)
;; Parameters
@@ -749,7 +752,10 @@ With prefix argument MINIMIZE, minimize it instead."
(json-object-type 'alist))
(replace-region-contents
begin end
- (lambda () (json-encode (json-read))))))
+ (lambda () (json-encode (json-read)))
+ ;; FIXME: What's a good value here? Can we use something better,
+ ;; e.g., by deriving a value from the size of the region?
+ 64)))
(defun json-pretty-print-buffer-ordered (&optional minimize)
"Pretty-print current buffer with object keys ordered.
diff --git a/lisp/subr.el b/lisp/subr.el
index 44a1c608949..122a0d8da4c 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -5476,30 +5476,4 @@ returned list are in the same order as in TREE.
;; for discoverability:
(defalias 'flatten-list 'flatten-tree)
-(defun replace-region-contents (beg end replace-fn)
- "Replace the region between BEG and END using REPLACE-FN.
-REPLACE-FN runs on the current buffer narrowed to the region. It
-should return either a string or a buffer replacing the region.
-
-The replacement is performed using `replace-buffer-contents'.
-
-Note: If the replacement is a string, it'll be placed in a
-temporary buffer so that `replace-buffer-contents' can operate on
-it. Therefore, if you already have the replacement in a buffer,
-it makes no sense to convert it to a string using
-`buffer-substring' or similar."
- (save-excursion
- (save-restriction
- (narrow-to-region beg end)
- (goto-char (point-min))
- (let ((repl (funcall replace-fn)))
- (if (bufferp repl)
- (replace-buffer-contents repl)
- (let ((source-buffer (current-buffer)))
- (with-temp-buffer
- (insert repl)
- (let ((tmp-buffer (current-buffer)))
- (set-buffer source-buffer)
- (replace-buffer-contents tmp-buffer)))))))))
-
;;; subr.el ends here
diff --git a/src/editfns.c b/src/editfns.c
index 7a600bacf18..057641a9823 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -20,6 +20,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <config.h>
#include <sys/types.h>
+#include <sys/time.h>
#include <stdio.h>
#ifdef HAVE_PWD_H
@@ -438,7 +439,7 @@ find_field (Lisp_Object pos, Lisp_Object merge_at_boundary,
? get_char_property_and_overlay (make_fixnum (XFIXNUM (pos) - 1),
Qfield, Qnil, NULL)
/* Using nil here would be a more obvious choice, but it would
- fail when the buffer starts with a non-sticky field. */
+ fail when the buffer starts with a non-sticky field. */
: after_field);
/* See if we need to handle the case where MERGE_AT_BOUNDARY is nil
@@ -646,24 +647,24 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil. */)
if (NILP (Vinhibit_field_text_motion)
&& !EQ (new_pos, old_pos)
&& (!NILP (Fget_char_property (new_pos, Qfield, Qnil))
- || !NILP (Fget_char_property (old_pos, Qfield, Qnil))
- /* To recognize field boundaries, we must also look at the
- previous positions; we could use `Fget_pos_property'
- instead, but in itself that would fail inside non-sticky
- fields (like comint prompts). */
- || (XFIXNAT (new_pos) > BEGV
- && !NILP (Fget_char_property (prev_new, Qfield, Qnil)))
- || (XFIXNAT (old_pos) > BEGV
- && !NILP (Fget_char_property (prev_old, Qfield, Qnil))))
+ || !NILP (Fget_char_property (old_pos, Qfield, Qnil))
+ /* To recognize field boundaries, we must also look at the
+ previous positions; we could use `Fget_pos_property'
+ instead, but in itself that would fail inside non-sticky
+ fields (like comint prompts). */
+ || (XFIXNAT (new_pos) > BEGV
+ && !NILP (Fget_char_property (prev_new, Qfield, Qnil)))
+ || (XFIXNAT (old_pos) > BEGV
+ && !NILP (Fget_char_property (prev_old, Qfield, Qnil))))
&& (NILP (inhibit_capture_property)
- /* Field boundaries are again a problem; but now we must
- decide the case exactly, so we need to call
- `get_pos_property' as well. */
- || (NILP (Fget_pos_property (old_pos, inhibit_capture_property, Qnil))
- && (XFIXNAT (old_pos) <= BEGV
- || NILP (Fget_char_property
+ /* Field boundaries are again a problem; but now we must
+ decide the case exactly, so we need to call
+ `get_pos_property' as well. */
+ || (NILP (Fget_pos_property (old_pos, inhibit_capture_property, Qnil))
+ && (XFIXNAT (old_pos) <= BEGV
+ || NILP (Fget_char_property
(old_pos, inhibit_capture_property, Qnil))
- || NILP (Fget_char_property
+ || NILP (Fget_char_property
(prev_old, inhibit_capture_property, Qnil))))))
/* It is possible that NEW_POS is not within the same field as
OLD_POS; try to move NEW_POS so that it is. */
@@ -677,9 +678,9 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil. */)
field_bound = Ffield_beginning (old_pos, escape_from_edge, new_pos);
if (/* See if ESCAPE_FROM_EDGE caused FIELD_BOUND to jump to the
- other side of NEW_POS, which would mean that NEW_POS is
- already acceptable, and it's not necessary to constrain it
- to FIELD_BOUND. */
+ other side of NEW_POS, which would mean that NEW_POS is
+ already acceptable, and it's not necessary to constrain it
+ to FIELD_BOUND. */
((XFIXNAT (field_bound) < XFIXNAT (new_pos)) ? fwd : !fwd)
/* NEW_POS should be constrained, but only if either
ONLY_IN_LINE is nil (in which case any constraint is OK),
@@ -1049,7 +1050,7 @@ If POS is out of range, the value is nil. */)
{
pos_byte = PT_BYTE;
if (pos_byte < BEGV_BYTE || pos_byte >= ZV_BYTE)
- return Qnil;
+ return Qnil;
}
else if (MARKERP (pos))
{
@@ -1433,8 +1434,8 @@ usage: (insert-before-markers-and-inherit &rest ARGS) */)
DEFUN ("insert-char", Finsert_char, Sinsert_char, 1, 3,
"(list (read-char-by-name \"Insert character (Unicode name or hex): \")\
- (prefix-numeric-value current-prefix-arg)\
- t))",
+ (prefix-numeric-value current-prefix-arg)\
+ t))",
doc: /* Insert COUNT copies of CHARACTER.
Interactively, prompt for CHARACTER. You can specify CHARACTER in one
of these ways:
@@ -1802,7 +1803,7 @@ determines whether case is significant or ignored. */)
if (!(BUF_BEGV (bp1) <= begp1
&& begp1 <= endp1
- && endp1 <= BUF_ZV (bp1)))
+ && endp1 <= BUF_ZV (bp1)))
args_out_of_range (start1, end1);
/* Likewise for second substring. */
@@ -1840,7 +1841,7 @@ determines whether case is significant or ignored. */)
if (!(BUF_BEGV (bp2) <= begp2
&& begp2 <= endp2
- && endp2 <= BUF_ZV (bp2)))
+ && endp2 <= BUF_ZV (bp2)))
args_out_of_range (start2, end2);
i1 = begp1;
@@ -1912,10 +1913,6 @@ determines whether case is significant or ignored. */)
#undef EQUAL
#define USE_HEURISTIC
-#ifdef USE_HEURISTIC
-#define DIFFSEQ_HEURISTIC
-#endif
-
/* Counter used to rarely_quit in replace-buffer-contents. */
static unsigned short rbc_quitcounter;
@@ -1935,32 +1932,46 @@ static unsigned short rbc_quitcounter;
bool a_unibyte; \
bool b_unibyte; \
/* Bit vectors recording for each character whether it was deleted
- or inserted. */ \
- unsigned char *deletions; \
- unsigned char *insertions;
+ or inserted. */ \
+ unsigned char *deletions; \
+ unsigned char *insertions; \
+ struct timeval start; \
+ double max_secs; \
+ unsigned int early_abort_tests;
#define NOTE_DELETE(ctx, xoff) set_bit ((ctx)->deletions, (xoff))
#define NOTE_INSERT(ctx, yoff) set_bit ((ctx)->insertions, (yoff))
+#define EARLY_ABORT(ctx) compareseq_early_abort (ctx)
struct context;
static void set_bit (unsigned char *, OFFSET);
static bool bit_is_set (const unsigned char *, OFFSET);
static bool buffer_chars_equal (struct context *, OFFSET, OFFSET);
+static bool compareseq_early_abort (struct context *);
#include "minmax.h"
#include "diffseq.h"
DEFUN ("replace-buffer-contents", Freplace_buffer_contents,
- Sreplace_buffer_contents, 1, 1, "bSource buffer: ",
+ Sreplace_buffer_contents, 1, 2, "bSource buffer: ",
doc: /* Replace accessible portion of current buffer with that of SOURCE.
SOURCE can be a buffer or a string that names a buffer.
Interactively, prompt for SOURCE.
+
+The optional argument MAX-COSTS defines the maximum costs of the
+difference computation. If the costs are too high, heuristics are
+used to provide a faster but suboptimal solution.
+
As far as possible the replacement is non-destructive, i.e. existing
buffer contents, markers, properties, and overlays in the current
buffer stay intact.
-Warning: this function can be slow if there's a large number of small
-differences between the two buffers. */)
- (Lisp_Object source)
+
+Because this function can be very slow if there's a large number of
+differences between the two buffers, it falls back to a plain delete
+and insert if comparing the buffers takes longer than
+`replace-buffer-contents-max-secs'. In this case, it returns t.
+Otherwise it returns nil. */)
+ (Lisp_Object source, Lisp_Object max_costs)
{
struct buffer *a = current_buffer;
Lisp_Object source_buffer = Fget_buffer (source);
@@ -2007,6 +2018,19 @@ differences between the two buffers. */)
ptrdiff_t *buffer;
USE_SAFE_ALLOCA;
SAFE_NALLOCA (buffer, 2, diags);
+
+ if (NILP (max_costs))
+ XSETFASTINT (max_costs, 1000000);
+ else
+ CHECK_FIXNUM (max_costs);
+
+ double max_secs = -1.0;
+ if (FLOATP (Vreplace_buffer_contents_max_secs))
+ max_secs = XFLOAT_DATA (Vreplace_buffer_contents_max_secs);
+
+ struct timeval tv_cmpseq_start, tv_cmpseq_end, tv_cmpseq_duration;
+ gettimeofday(&tv_cmpseq_start, NULL);
+
/* Micro-optimization: Casting to size_t generates much better
code. */
ptrdiff_t del_bytes = (size_t) size_a / CHAR_BIT + 1;
@@ -2022,20 +2046,34 @@ differences between the two buffers. */)
.insertions = SAFE_ALLOCA (ins_bytes),
.fdiag = buffer + size_b + 1,
.bdiag = buffer + diags + size_b + 1,
-#ifdef DIFFSEQ_HEURISTIC
.heuristic = true,
-#endif
/* FIXME: Find a good number for .too_expensive. */
- .too_expensive = 64,
+ .too_expensive = XFIXNUM (max_costs),
+ .max_secs = max_secs,
+ .early_abort_tests = 0
};
memclear (ctx.deletions, del_bytes);
memclear (ctx.insertions, ins_bytes);
+
/* compareseq requires indices to be zero-based. We add BEGV back
later. */
+ gettimeofday (&ctx.start, NULL);
bool early_abort = compareseq (0, size_a, 0, size_b, false, &ctx);
- /* Since we didn’t define EARLY_ABORT, we should never abort
- early. */
- eassert (! early_abort);
+
+ gettimeofday (&tv_cmpseq_end, NULL);
+ timersub (&tv_cmpseq_end, &tv_cmpseq_start, &tv_cmpseq_duration);
+ message ("compareseq returned %s after %d.%d secs and %d early_abort_tests.",
+ early_abort ? "early" : "normally",
+ tv_cmpseq_duration.tv_sec, tv_cmpseq_duration.tv_usec,
+ ctx.early_abort_tests);
+
+ if (early_abort)
+ {
+ del_range (min_a, ZV);
+ Finsert_buffer_substring (source, Qnil,Qnil);
+ SAFE_FREE_UNBIND_TO (count, Qnil);
+ return Qt;
+ }
rbc_quitcounter = 0;
@@ -2066,37 +2104,38 @@ differences between the two buffers. */)
rarely_quit (++rbc_quitcounter);
/* Check whether there is a change (insertion or deletion)
- before the current position. */
+ before the current position. */
if ((i > 0 && bit_is_set (ctx.deletions, i - 1)) ||
- (j > 0 && bit_is_set (ctx.insertions, j - 1)))
+ (j > 0 && bit_is_set (ctx.insertions, j - 1)))
{
- ptrdiff_t end_a = min_a + i;
- ptrdiff_t end_b = min_b + j;
- /* Find the beginning of the current change run. */
+ ptrdiff_t end_a = min_a + i;
+ ptrdiff_t end_b = min_b + j;
+ /* Find the beginning of the current change run. */
while (i > 0 && bit_is_set (ctx.deletions, i - 1))
- --i;
+ --i;
while (j > 0 && bit_is_set (ctx.insertions, j - 1))
- --j;
+ --j;
rarely_quit (rbc_quitcounter++);
- ptrdiff_t beg_a = min_a + i;
- ptrdiff_t beg_b = min_b + j;
- eassert (beg_a <= end_a);
- eassert (beg_b <= end_b);
- eassert (beg_a < end_a || beg_b < end_b);
- 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));
- }
+ ptrdiff_t beg_a = min_a + i;
+ ptrdiff_t beg_b = min_b + j;
+ eassert (beg_a <= end_a);
+ eassert (beg_b <= end_b);
+ eassert (beg_a < end_a || beg_b < end_b);
+ 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));
+ }
}
--i;
--j;
}
+
SAFE_FREE_UNBIND_TO (count, Qnil);
rbc_quitcounter = 0;
@@ -2143,7 +2182,7 @@ bit_is_set (const unsigned char *a, ptrdiff_t i)
static bool
buffer_chars_equal (struct context *ctx,
- ptrdiff_t pos_a, ptrdiff_t pos_b)
+ ptrdiff_t pos_a, ptrdiff_t pos_b)
{
pos_a += ctx->beg_a;
pos_b += ctx->beg_b;
@@ -2173,6 +2212,19 @@ buffer_chars_equal (struct context *ctx,
== BUF_FETCH_MULTIBYTE_CHAR (ctx->buffer_b, bpos_b);
}
+static bool
+compareseq_early_abort (struct context *ctx)
+{
+ ctx->early_abort_tests++;
+ if (ctx->max_secs < 0.0)
+ return false;
+
+ struct timeval now, diff;
+ gettimeofday (&now, NULL);
+ timersub (&now, &ctx->start, &diff);
+ return diff.tv_sec + diff.tv_usec / 1000000.0 > ctx->max_secs;
+}
+
static void
subst_char_in_region_unwind (Lisp_Object arg)
@@ -3137,7 +3189,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
while (format != end)
{
/* The values of N, ISPEC, and FORMAT when the loop body is
- entered. */
+ entered. */
ptrdiff_t n0 = n;
ptrdiff_t ispec0 = ispec;
char *format0 = format;
@@ -3161,7 +3213,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
where
- field-number ::= [0-9]+ '$'
+ field-number ::= [0-9]+ '$'
flags ::= [-+0# ]+
field-width ::= [0-9]+
precision ::= '.' [0-9]*
@@ -3684,7 +3736,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
if (incr != sprintf_bytes)
{
/* Move data to make room to insert spaces and '0's.
- As this may entail overlapping moves, process
+ As this may entail overlapping moves, process
the output right-to-left and use memmove.
With any luck this code is rarely executed. */
char *src = p + sprintf_bytes;
@@ -3916,7 +3968,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
len = make_fixnum (SCHARS (info[i].argument));
Lisp_Object new_len = make_fixnum (info[i].end - info[i].start);
props = text_property_list (info[i].argument,
- make_fixnum (0), len, Qnil);
+ make_fixnum (0), len, Qnil);
props = extend_property_ranges (props, len, new_len);
/* If successive arguments have properties, be sure that
the value of `composition' property be the copy. */
@@ -4210,7 +4262,7 @@ ring. */)
/* First region smaller than second. */
if (len1_byte < len2_byte)
- {
+ {
temp = SAFE_ALLOCA (len2_byte);
/* Don't precompute these addresses. We have to compute them
@@ -4219,26 +4271,26 @@ ring. */)
start1_addr = BYTE_POS_ADDR (start1_byte);
start2_addr = BYTE_POS_ADDR (start2_byte);
- memcpy (temp, start2_addr, len2_byte);
- memcpy (start1_addr + len2_byte, start1_addr, len1_byte);
- memcpy (start1_addr, temp, len2_byte);
- }
+ memcpy (temp, start2_addr, len2_byte);
+ memcpy (start1_addr + len2_byte, start1_addr, len1_byte);
+ memcpy (start1_addr, temp, len2_byte);
+ }
else
/* First region not smaller than second. */
- {
+ {
temp = SAFE_ALLOCA (len1_byte);
start1_addr = BYTE_POS_ADDR (start1_byte);
start2_addr = BYTE_POS_ADDR (start2_byte);
- memcpy (temp, start1_addr, len1_byte);
- memcpy (start1_addr, start2_addr, len2_byte);
- memcpy (start1_addr + len2_byte, temp, len1_byte);
- }
+ memcpy (temp, start1_addr, len1_byte);
+ memcpy (start1_addr, start2_addr, len2_byte);
+ memcpy (start1_addr + len2_byte, temp, len1_byte);
+ }
SAFE_FREE ();
graft_intervals_into_buffer (tmp_interval1, start1 + len2,
- len1, current_buffer, 0);
+ len1, current_buffer, 0);
graft_intervals_into_buffer (tmp_interval2, start1,
- len2, current_buffer, 0);
+ len2, current_buffer, 0);
update_compositions (start1, start1 + len2, CHECK_BORDER);
update_compositions (start1 + len2, end2, CHECK_TAIL);
}
@@ -4249,14 +4301,14 @@ ring. */)
if (len1_byte == len2_byte)
/* Regions are same size, though, how nice. */
- {
+ {
USE_SAFE_ALLOCA;
- modify_text (start1, end2);
- record_change (start1, len1);
- record_change (start2, len2);
- tmp_interval1 = copy_intervals (cur_intv, start1, len1);
- tmp_interval2 = copy_intervals (cur_intv, start2, len2);
+ modify_text (start1, end2);
+ record_change (start1, len1);
+ record_change (start2, len2);
+ tmp_interval1 = copy_intervals (cur_intv, start1, len1);
+ tmp_interval2 = copy_intervals (cur_intv, start2, len2);
tmp_interval3 = validate_interval_range (buf, &startr1, &endr1, 0);
if (tmp_interval3)
@@ -4269,27 +4321,27 @@ ring. */)
temp = SAFE_ALLOCA (len1_byte);
start1_addr = BYTE_POS_ADDR (start1_byte);
start2_addr = BYTE_POS_ADDR (start2_byte);
- memcpy (temp, start1_addr, len1_byte);
- memcpy (start1_addr, start2_addr, len2_byte);
- memcpy (start2_addr, temp, len1_byte);
+ memcpy (temp, start1_addr, len1_byte);
+ memcpy (start1_addr, start2_addr, len2_byte);
+ memcpy (start2_addr, temp, len1_byte);
SAFE_FREE ();
- graft_intervals_into_buffer (tmp_interval1, start2,
- len1, current_buffer, 0);
- graft_intervals_into_buffer (tmp_interval2, start1,
- len2, current_buffer, 0);
- }
+ graft_intervals_into_buffer (tmp_interval1, start2,
+ len1, current_buffer, 0);
+ graft_intervals_into_buffer (tmp_interval2, start1,
+ len2, current_buffer, 0);
+ }
else if (len1_byte < len2_byte) /* Second region larger than first */
- /* Non-adjacent & unequal size, area between must also be shifted. */
- {
+ /* Non-adjacent & unequal size, area between must also be shifted. */
+ {
USE_SAFE_ALLOCA;
- modify_text (start1, end2);
- record_change (start1, (end2 - start1));
- tmp_interval1 = copy_intervals (cur_intv, start1, len1);
- tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
- tmp_interval2 = copy_intervals (cur_intv, start2, len2);
+ modify_text (start1, end2);
+ record_change (start1, (end2 - start1));
+ tmp_interval1 = copy_intervals (cur_intv, start1, len1);
+ tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
+ tmp_interval2 = copy_intervals (cur_intv, start2, len2);
tmp_interval3 = validate_interval_range (buf, &startr1, &endr2, 0);
if (tmp_interval3)
@@ -4299,30 +4351,30 @@ ring. */)
temp = SAFE_ALLOCA (len2_byte);
start1_addr = BYTE_POS_ADDR (start1_byte);
start2_addr = BYTE_POS_ADDR (start2_byte);
- memcpy (temp, start2_addr, len2_byte);
- memcpy (start1_addr + len_mid + len2_byte, start1_addr, len1_byte);
- memmove (start1_addr + len2_byte, start1_addr + len1_byte, len_mid);
- memcpy (start1_addr, temp, len2_byte);
+ memcpy (temp, start2_addr, len2_byte);
+ memcpy (start1_addr + len_mid + len2_byte, start1_addr, len1_byte);
+ memmove (start1_addr + len2_byte, start1_addr + len1_byte, len_mid);
+ memcpy (start1_addr, temp, len2_byte);
SAFE_FREE ();
- graft_intervals_into_buffer (tmp_interval1, end2 - len1,
- len1, current_buffer, 0);
- graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
- len_mid, current_buffer, 0);
- graft_intervals_into_buffer (tmp_interval2, start1,
- len2, current_buffer, 0);
- }
+ graft_intervals_into_buffer (tmp_interval1, end2 - len1,
+ len1, current_buffer, 0);
+ graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
+ len_mid, current_buffer, 0);
+ graft_intervals_into_buffer (tmp_interval2, start1,
+ len2, current_buffer, 0);
+ }
else
/* Second region smaller than first. */
- {
+ {
USE_SAFE_ALLOCA;
- record_change (start1, (end2 - start1));
- modify_text (start1, end2);
+ record_change (start1, (end2 - start1));
+ modify_text (start1, end2);
- tmp_interval1 = copy_intervals (cur_intv, start1, len1);
- tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
- tmp_interval2 = copy_intervals (cur_intv, start2, len2);
+ tmp_interval1 = copy_intervals (cur_intv, start1, len1);
+ tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
+ tmp_interval2 = copy_intervals (cur_intv, start2, len2);
tmp_interval3 = validate_interval_range (buf, &startr1, &endr2, 0);
if (tmp_interval3)
@@ -4332,19 +4384,19 @@ ring. */)
temp = SAFE_ALLOCA (len1_byte);
start1_addr = BYTE_POS_ADDR (start1_byte);
start2_addr = BYTE_POS_ADDR (start2_byte);
- memcpy (temp, start1_addr, len1_byte);
- memcpy (start1_addr, start2_addr, len2_byte);
- memmove (start1_addr + len2_byte, start1_addr + len1_byte, len_mid);
- memcpy (start1_addr + len2_byte + len_mid, temp, len1_byte);
+ memcpy (temp, start1_addr, len1_byte);
+ memcpy (start1_addr, start2_addr, len2_byte);
+ memmove (start1_addr + len2_byte, start1_addr + len1_byte, len_mid);
+ memcpy (start1_addr + len2_byte + len_mid, temp, len1_byte);
SAFE_FREE ();
- graft_intervals_into_buffer (tmp_interval1, end2 - len1,
- len1, current_buffer, 0);
- graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
- len_mid, current_buffer, 0);
- graft_intervals_into_buffer (tmp_interval2, start1,
- len2, current_buffer, 0);
- }
+ graft_intervals_into_buffer (tmp_interval1, end2 - len1,
+ len1, current_buffer, 0);
+ graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
+ len_mid, current_buffer, 0);
+ graft_intervals_into_buffer (tmp_interval2, start1,
+ len2, current_buffer, 0);
+ }
update_compositions (start1, start1 + len2, CHECK_BORDER);
update_compositions (end2 - len1, end2, CHECK_BORDER);
@@ -4441,6 +4493,12 @@ it to be non-nil. */);
binary_as_unsigned = true;
#endif
+ DEFVAR_LISP ("replace-buffer-contents-max-secs",
+ Vreplace_buffer_contents_max_secs,
+ doc: /* If differencing the two buffers takes longer than this,
+`replace-buffer-contents' falls back to a plain delete and insert. */);
+ Vreplace_buffer_contents_max_secs = Qnil;
+
defsubr (&Spropertize);
defsubr (&Schar_equal);
defsubr (&Sgoto_char);