aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNoam Postavsky2016-07-20 20:15:14 -0400
committerNoam Postavsky2016-07-22 23:55:23 -0400
commit66f95e0dabf750e9d2eff59b2bb6e593618cd48a (patch)
treea8cd27828bfef2459b70e446cdf1de346327fc3e /src
parent52cf0d5d98c51c3591ca5d376fd4e85cd9b72d7f (diff)
downloademacs-66f95e0dabf750e9d2eff59b2bb6e593618cd48a.tar.gz
emacs-66f95e0dabf750e9d2eff59b2bb6e593618cd48a.zip
Adjust match data before calling after-change-funs
It's important to adjust the match data in between calling before-change-functions and after-change-functions, so that buffer change hooks will always see match-data consistent with buffer content. (Bug #23917) * src/insdel.c (replace_range): Add new parameter ADJUST_MATCH_DATA, if true call update_search_regs. Update all callers (except Freplace_match) to pass 0 for the new parameter. * src/search.c (update_search_regs): New function, extracted from Freplace_match. (Freplace_match): Remove match data adjustment code, pass 1 for ADJUST_MATCH_DATA to replace_range instead.
Diffstat (limited to 'src')
-rw-r--r--src/cmds.c2
-rw-r--r--src/editfns.c6
-rw-r--r--src/insdel.c10
-rw-r--r--src/lisp.h4
-rw-r--r--src/search.c56
5 files changed, 47 insertions, 31 deletions
diff --git a/src/cmds.c b/src/cmds.c
index 1e44dddfbf6..4003d8bfa47 100644
--- a/src/cmds.c
+++ b/src/cmds.c
@@ -447,7 +447,7 @@ internal_self_insert (int c, EMACS_INT n)
447 string = concat2 (string, tem); 447 string = concat2 (string, tem);
448 } 448 }
449 449
450 replace_range (PT, PT + chars_to_delete, string, 1, 1, 1); 450 replace_range (PT, PT + chars_to_delete, string, 1, 1, 1, 0);
451 Fforward_char (make_number (n)); 451 Fforward_char (make_number (n));
452 } 452 }
453 else if (n > 1) 453 else if (n > 1)
diff --git a/src/editfns.c b/src/editfns.c
index 412745d551d..32c8bec6db2 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -3192,7 +3192,7 @@ Both characters must have the same length of multi-byte form. */)
3192 /* replace_range is less efficient, because it moves the gap, 3192 /* replace_range is less efficient, because it moves the gap,
3193 but it handles combining correctly. */ 3193 but it handles combining correctly. */
3194 replace_range (pos, pos + 1, string, 3194 replace_range (pos, pos + 1, string,
3195 0, 0, 1); 3195 0, 0, 1, 0);
3196 pos_byte_next = CHAR_TO_BYTE (pos); 3196 pos_byte_next = CHAR_TO_BYTE (pos);
3197 if (pos_byte_next > pos_byte) 3197 if (pos_byte_next > pos_byte)
3198 /* Before combining happened. We should not increment 3198 /* Before combining happened. We should not increment
@@ -3405,7 +3405,7 @@ It returns the number of characters changed. */)
3405 /* This is less efficient, because it moves the gap, 3405 /* This is less efficient, because it moves the gap,
3406 but it should handle multibyte characters correctly. */ 3406 but it should handle multibyte characters correctly. */
3407 string = make_multibyte_string ((char *) str, 1, str_len); 3407 string = make_multibyte_string ((char *) str, 1, str_len);
3408 replace_range (pos, pos + 1, string, 1, 0, 1); 3408 replace_range (pos, pos + 1, string, 1, 0, 1, 0);
3409 len = str_len; 3409 len = str_len;
3410 } 3410 }
3411 else 3411 else
@@ -3446,7 +3446,7 @@ It returns the number of characters changed. */)
3446 { 3446 {
3447 string = Fmake_string (make_number (1), val); 3447 string = Fmake_string (make_number (1), val);
3448 } 3448 }
3449 replace_range (pos, pos + len, string, 1, 0, 1); 3449 replace_range (pos, pos + len, string, 1, 0, 1, 0);
3450 pos_byte += SBYTES (string); 3450 pos_byte += SBYTES (string);
3451 pos += SCHARS (string); 3451 pos += SCHARS (string);
3452 cnt += SCHARS (string); 3452 cnt += SCHARS (string);
diff --git a/src/insdel.c b/src/insdel.c
index 4ad1074f5f7..fc3f19fd581 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -1268,7 +1268,9 @@ adjust_after_insert (ptrdiff_t from, ptrdiff_t from_byte,
1268/* Replace the text from character positions FROM to TO with NEW, 1268/* Replace the text from character positions FROM to TO with NEW,
1269 If PREPARE, call prepare_to_modify_buffer. 1269 If PREPARE, call prepare_to_modify_buffer.
1270 If INHERIT, the newly inserted text should inherit text properties 1270 If INHERIT, the newly inserted text should inherit text properties
1271 from the surrounding non-deleted text. */ 1271 from the surrounding non-deleted text.
1272 If ADJUST_MATCH_DATA, then adjust the match data before calling
1273 signal_after_change. */
1272 1274
1273/* Note that this does not yet handle markers quite right. 1275/* Note that this does not yet handle markers quite right.
1274 Also it needs to record a single undo-entry that does a replacement 1276 Also it needs to record a single undo-entry that does a replacement
@@ -1279,7 +1281,8 @@ adjust_after_insert (ptrdiff_t from, ptrdiff_t from_byte,
1279 1281
1280void 1282void
1281replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new, 1283replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
1282 bool prepare, bool inherit, bool markers) 1284 bool prepare, bool inherit, bool markers,
1285 bool adjust_match_data)
1283{ 1286{
1284 ptrdiff_t inschars = SCHARS (new); 1287 ptrdiff_t inschars = SCHARS (new);
1285 ptrdiff_t insbytes = SBYTES (new); 1288 ptrdiff_t insbytes = SBYTES (new);
@@ -1426,6 +1429,9 @@ replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
1426 MODIFF++; 1429 MODIFF++;
1427 CHARS_MODIFF = MODIFF; 1430 CHARS_MODIFF = MODIFF;
1428 1431
1432 if (adjust_match_data)
1433 update_search_regs (from, to, from + SCHARS (new));
1434
1429 signal_after_change (from, nchars_del, GPT - from); 1435 signal_after_change (from, nchars_del, GPT - from);
1430 update_compositions (from, GPT, CHECK_BORDER); 1436 update_compositions (from, GPT, CHECK_BORDER);
1431} 1437}
diff --git a/src/lisp.h b/src/lisp.h
index 6a98adbda9c..25f811e06ef 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3516,7 +3516,7 @@ extern void adjust_after_insert (ptrdiff_t, ptrdiff_t, ptrdiff_t,
3516 ptrdiff_t, ptrdiff_t); 3516 ptrdiff_t, ptrdiff_t);
3517extern void adjust_markers_for_delete (ptrdiff_t, ptrdiff_t, 3517extern void adjust_markers_for_delete (ptrdiff_t, ptrdiff_t,
3518 ptrdiff_t, ptrdiff_t); 3518 ptrdiff_t, ptrdiff_t);
3519extern void replace_range (ptrdiff_t, ptrdiff_t, Lisp_Object, bool, bool, bool); 3519extern void replace_range (ptrdiff_t, ptrdiff_t, Lisp_Object, bool, bool, bool, bool);
3520extern void replace_range_2 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, 3520extern void replace_range_2 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
3521 const char *, ptrdiff_t, ptrdiff_t, bool); 3521 const char *, ptrdiff_t, ptrdiff_t, bool);
3522extern void syms_of_insdel (void); 3522extern void syms_of_insdel (void);
@@ -3994,6 +3994,8 @@ extern Lisp_Object make_temp_name (Lisp_Object, bool);
3994/* Defined in search.c. */ 3994/* Defined in search.c. */
3995extern void shrink_regexp_cache (void); 3995extern void shrink_regexp_cache (void);
3996extern void restore_search_regs (void); 3996extern void restore_search_regs (void);
3997extern void update_search_regs (ptrdiff_t oldstart,
3998 ptrdiff_t oldend, ptrdiff_t newend);
3997extern void record_unwind_save_match_data (void); 3999extern void record_unwind_save_match_data (void);
3998struct re_registers; 4000struct re_registers;
3999extern struct re_pattern_buffer *compile_pattern (Lisp_Object, 4001extern struct re_pattern_buffer *compile_pattern (Lisp_Object,
diff --git a/src/search.c b/src/search.c
index 5c949ad00a4..b70f02097b7 100644
--- a/src/search.c
+++ b/src/search.c
@@ -2719,16 +2719,23 @@ since only regular expressions have distinguished subexpressions. */)
2719 2719
2720 /* The functions below modify the buffer, so they could trigger 2720 /* The functions below modify the buffer, so they could trigger
2721 various modification hooks (see signal_before_change and 2721 various modification hooks (see signal_before_change and
2722 signal_after_change), which might clobber the match data we need 2722 signal_after_change). If these hooks clobber the match data we
2723 to adjust after the replacement. If that happens, we error out. */ 2723 error out since otherwise this will result in confusing bugs. */
2724 ptrdiff_t sub_start = search_regs.start[sub]; 2724 ptrdiff_t sub_start = search_regs.start[sub];
2725 ptrdiff_t sub_end = search_regs.end[sub]; 2725 ptrdiff_t sub_end = search_regs.end[sub];
2726 unsigned num_regs = search_regs.num_regs; 2726 unsigned num_regs = search_regs.num_regs;
2727 newpoint = search_regs.start[sub] + SCHARS (newtext);
2727 2728
2728 /* Replace the old text with the new in the cleanest possible way. */ 2729 /* Replace the old text with the new in the cleanest possible way. */
2729 replace_range (search_regs.start[sub], search_regs.end[sub], 2730 replace_range (search_regs.start[sub], search_regs.end[sub],
2730 newtext, 1, 0, 1); 2731 newtext, 1, 0, 1, 1);
2731 newpoint = search_regs.start[sub] + SCHARS (newtext); 2732 /* Update saved data to match adjustment made by replace_range. */
2733 {
2734 ptrdiff_t change = newpoint - sub_end;
2735 if (sub_start >= sub_end)
2736 sub_start += change;
2737 sub_end += change;
2738 }
2732 2739
2733 if (case_action == all_caps) 2740 if (case_action == all_caps)
2734 Fupcase_region (make_number (search_regs.start[sub]), 2741 Fupcase_region (make_number (search_regs.start[sub]),
@@ -2742,26 +2749,6 @@ since only regular expressions have distinguished subexpressions. */)
2742 || search_regs.num_regs != num_regs) 2749 || search_regs.num_regs != num_regs)
2743 error ("Match data clobbered by buffer modification hooks"); 2750 error ("Match data clobbered by buffer modification hooks");
2744 2751
2745 /* Adjust search data for this change. */
2746 {
2747 ptrdiff_t oldend = search_regs.end[sub];
2748 ptrdiff_t oldstart = search_regs.start[sub];
2749 ptrdiff_t change = newpoint - search_regs.end[sub];
2750 ptrdiff_t i;
2751
2752 for (i = 0; i < search_regs.num_regs; i++)
2753 {
2754 if (search_regs.start[i] >= oldend)
2755 search_regs.start[i] += change;
2756 else if (search_regs.start[i] > oldstart)
2757 search_regs.start[i] = oldstart;
2758 if (search_regs.end[i] >= oldend)
2759 search_regs.end[i] += change;
2760 else if (search_regs.end[i] > oldstart)
2761 search_regs.end[i] = oldstart;
2762 }
2763 }
2764
2765 /* Put point back where it was in the text. */ 2752 /* Put point back where it was in the text. */
2766 if (opoint <= 0) 2753 if (opoint <= 0)
2767 TEMP_SET_PT (opoint + ZV); 2754 TEMP_SET_PT (opoint + ZV);
@@ -3102,6 +3089,27 @@ restore_search_regs (void)
3102 } 3089 }
3103} 3090}
3104 3091
3092/* Called from replace-match via replace_range. */
3093void
3094update_search_regs (ptrdiff_t oldstart, ptrdiff_t oldend, ptrdiff_t newend)
3095{
3096 /* Adjust search data for this change. */
3097 ptrdiff_t change = newend - oldend;
3098 ptrdiff_t i;
3099
3100 for (i = 0; i < search_regs.num_regs; i++)
3101 {
3102 if (search_regs.start[i] >= oldend)
3103 search_regs.start[i] += change;
3104 else if (search_regs.start[i] > oldstart)
3105 search_regs.start[i] = oldstart;
3106 if (search_regs.end[i] >= oldend)
3107 search_regs.end[i] += change;
3108 else if (search_regs.end[i] > oldstart)
3109 search_regs.end[i] = oldstart;
3110 }
3111}
3112
3105static void 3113static void
3106unwind_set_match_data (Lisp_Object list) 3114unwind_set_match_data (Lisp_Object list)
3107{ 3115{