diff options
-rw-r--r-- | lisp/emacs-lisp/subr-x.el | 27 | ||||
-rw-r--r-- | lisp/json.el | 8 | ||||
-rw-r--r-- | lisp/subr.el | 26 | ||||
-rw-r--r-- | src/editfns.c | 314 |
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); |