From c10e9ece08ab58bf0d49fd1554879c379f810748 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Wed, 1 Jan 2014 19:44:48 +0200 Subject: [PATCH] Fix bug #16265 with buffer caches when modifying text in indirect buffers. src/search.c (newline_cache_on_off, find_newline): In indirect buffers, use the newline cache of the base buffer. src/insdel.c (invalidate_buffer_caches): If BUF is an indirect buffer, invalidate the caches of its base buffer. src/indent.c (width_run_cache_on_off, compute_motion): In indirect buffers, use the width-run cache of the base buffer. src/xdisp.c (redisplay_window): When the window displays an indirect buffer, and the character widths in the display table have changed, invalidate the width-run cache of the corresponding base buffer. src/fileio.c (Finsert_file_contents): When invalidating the newline cache, consider the case of inserting into indirect buffer. src/bidi.c (bidi_paragraph_cache_on_off, bidi_find_paragraph_start): In indirect buffers, use the paragraph cache of the base buffer. --- src/ChangeLog | 22 +++++++++++++++++ src/bidi.c | 44 +++++++++++++++++++++++++++------ src/fileio.c | 6 ++++- src/indent.c | 68 ++++++++++++++++++++++++++++++++++----------------- src/insdel.c | 4 +++ src/search.c | 60 +++++++++++++++++++++++++++++++++------------ src/xdisp.c | 12 ++++++--- 7 files changed, 164 insertions(+), 52 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 6ed13a11fe5..e41ccd168c6 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,25 @@ +2014-01-01 Eli Zaretskii + + * search.c (newline_cache_on_off, find_newline): In indirect + buffers, use the newline cache of the base buffer. + + * insdel.c (invalidate_buffer_caches): If BUF is an indirect + buffer, invalidate the caches of its base buffer. (Bug#16265) + + * indent.c (width_run_cache_on_off, compute_motion): In indirect + buffers, use the width-run cache of the base buffer. + + * xdisp.c (redisplay_window): When the window displays an indirect + buffer, and the character widths in the display table have + changed, invalidate the width-run cache of the corresponding base + buffer. + + * fileio.c (Finsert_file_contents): When invalidating the newline + cache, consider the case of inserting into indirect buffer. + + * bidi.c (bidi_paragraph_cache_on_off, bidi_find_paragraph_start): + In indirect buffers, use the paragraph cache of the base buffer. + 2013-12-31 Martin Rudalics * window.c (grow_mini_window): Fix last change. diff --git a/src/bidi.c b/src/bidi.c index 18bbd030785..b96cc24bbd1 100644 --- a/src/bidi.c +++ b/src/bidi.c @@ -1100,20 +1100,44 @@ bidi_at_paragraph_end (ptrdiff_t charpos, ptrdiff_t bytepos) static struct region_cache * bidi_paragraph_cache_on_off (void) { + struct buffer *cache_buffer = current_buffer; + bool indirect_p = false; + + /* For indirect buffers, make sure to use the cache of their base + buffer. */ + if (cache_buffer->base_buffer) + { + cache_buffer = cache_buffer->base_buffer; + indirect_p = true; + } + + /* Don't turn on or off the cache in the base buffer, if the value + of cache-long-scans of the base buffer is inconsistent with that. + This is because doing so will just make the cache pure overhead, + since if we turn it on via indirect buffer, it will be + immediately turned off by its base buffer. */ if (NILP (BVAR (current_buffer, cache_long_scans))) { - if (current_buffer->bidi_paragraph_cache) + if (!indirect_p + || NILP (BVAR (cache_buffer, cache_long_scans))) { - free_region_cache (current_buffer->bidi_paragraph_cache); - current_buffer->bidi_paragraph_cache = 0; + if (cache_buffer->bidi_paragraph_cache) + { + free_region_cache (cache_buffer->bidi_paragraph_cache); + cache_buffer->bidi_paragraph_cache = 0; + } } return NULL; } else { - if (!current_buffer->bidi_paragraph_cache) - current_buffer->bidi_paragraph_cache = new_region_cache (); - return current_buffer->bidi_paragraph_cache; + if (!indirect_p + || !NILP (BVAR (cache_buffer, cache_long_scans))) + { + if (!cache_buffer->bidi_paragraph_cache) + cache_buffer->bidi_paragraph_cache = new_region_cache (); + } + return cache_buffer->bidi_paragraph_cache; } } @@ -1134,6 +1158,10 @@ bidi_find_paragraph_start (ptrdiff_t pos, ptrdiff_t pos_byte) ptrdiff_t limit = ZV, limit_byte = ZV_BYTE; struct region_cache *bpc = bidi_paragraph_cache_on_off (); ptrdiff_t n = 0, oldpos = pos, next; + struct buffer *cache_buffer = current_buffer; + + if (cache_buffer->base_buffer) + cache_buffer = cache_buffer->base_buffer; while (pos_byte > BEGV_BYTE && n++ < MAX_PARAGRAPH_SEARCH @@ -1144,7 +1172,7 @@ bidi_find_paragraph_start (ptrdiff_t pos, ptrdiff_t pos_byte) of the text over which we scan back includes paragraph_start_re? */ DEC_BOTH (pos, pos_byte); - if (bpc && region_cache_backward (current_buffer, bpc, pos, &next)) + if (bpc && region_cache_backward (cache_buffer, bpc, pos, &next)) { pos = next, pos_byte = CHAR_TO_BYTE (pos); break; @@ -1155,7 +1183,7 @@ bidi_find_paragraph_start (ptrdiff_t pos, ptrdiff_t pos_byte) if (n >= MAX_PARAGRAPH_SEARCH) pos = BEGV, pos_byte = BEGV_BYTE; if (bpc) - know_region_cache (current_buffer, bpc, pos, oldpos); + know_region_cache (cache_buffer, bpc, pos, oldpos); /* Positions returned by the region cache are not limited to BEGV..ZV range, so we limit them here. */ pos_byte = clip_to_bounds (BEGV_BYTE, pos_byte, ZV_BYTE); diff --git a/src/fileio.c b/src/fileio.c index 904a8d24dd8..5d8f3cb64f5 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -4496,7 +4496,11 @@ by calling `format-decode', which see. */) /* We made a lot of deletions and insertions above, so invalidate the newline cache for the entire region of the inserted characters. */ - if (current_buffer->newline_cache) + if (current_buffer->base_buffer && current_buffer->base_buffer->newline_cache) + invalidate_region_cache (current_buffer->base_buffer, + current_buffer->base_buffer->newline_cache, + PT - BEG, Z - PT - inserted); + else if (current_buffer->newline_cache) invalidate_region_cache (current_buffer, current_buffer->newline_cache, PT - BEG, Z - PT - inserted); diff --git a/src/indent.c b/src/indent.c index 0c345d6c670..e86add54142 100644 --- a/src/indent.c +++ b/src/indent.c @@ -144,30 +144,51 @@ recompute_width_table (struct buffer *buf, struct Lisp_Char_Table *disptab) /* Allocate or free the width run cache, as requested by the current state of current_buffer's cache_long_scans variable. */ -static void +static struct region_cache * width_run_cache_on_off (void) { + struct buffer *cache_buffer = current_buffer; + bool indirect_p = false; + + if (cache_buffer->base_buffer) + { + cache_buffer = cache_buffer->base_buffer; + indirect_p = true; + } + if (NILP (BVAR (current_buffer, cache_long_scans)) /* And, for the moment, this feature doesn't work on multibyte characters. */ || !NILP (BVAR (current_buffer, enable_multibyte_characters))) { - /* It should be off. */ - if (current_buffer->width_run_cache) - { - free_region_cache (current_buffer->width_run_cache); - current_buffer->width_run_cache = 0; - bset_width_table (current_buffer, Qnil); + if (!indirect_p + || NILP (BVAR (cache_buffer, cache_long_scans)) + || !NILP (BVAR (cache_buffer, enable_multibyte_characters))) + { + /* It should be off. */ + if (cache_buffer->width_run_cache) + { + free_region_cache (cache_buffer->width_run_cache); + cache_buffer->width_run_cache = 0; + bset_width_table (current_buffer, Qnil); + } } + return NULL; } else { - /* It should be on. */ - if (current_buffer->width_run_cache == 0) - { - current_buffer->width_run_cache = new_region_cache (); - recompute_width_table (current_buffer, buffer_display_table ()); - } + if (!indirect_p + || (!NILP (BVAR (cache_buffer, cache_long_scans)) + && NILP (BVAR (cache_buffer, enable_multibyte_characters)))) + { + /* It should be on. */ + if (cache_buffer->width_run_cache == 0) + { + cache_buffer->width_run_cache = new_region_cache (); + recompute_width_table (current_buffer, buffer_display_table ()); + } + } + return cache_buffer->width_run_cache; } } @@ -1128,12 +1149,16 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos, EMACS_INT contin_hpos; /* HPOS of last column of continued line. */ int prev_tab_offset; /* Previous tab offset. */ int continuation_glyph_width; + struct buffer *cache_buffer = current_buffer; + struct region_cache *width_cache; struct composition_it cmp_it; XSETWINDOW (window, win); - width_run_cache_on_off (); + if (cache_buffer->base_buffer) + cache_buffer = cache_buffer->base_buffer; + width_cache = width_run_cache_on_off (); if (dp == buffer_display_table ()) width_table = (VECTORP (BVAR (current_buffer, width_table)) ? XVECTOR (BVAR (current_buffer, width_table))->contents @@ -1404,13 +1429,11 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos, /* Consult the width run cache to see if we can avoid inspecting the text character-by-character. */ - if (current_buffer->width_run_cache && pos >= next_width_run) + if (width_cache && pos >= next_width_run) { ptrdiff_t run_end; int common_width - = region_cache_forward (current_buffer, - current_buffer->width_run_cache, - pos, &run_end); + = region_cache_forward (cache_buffer, width_cache, pos, &run_end); /* A width of zero means the character's width varies (like a tab), is meaningless (like a newline), or we just don't @@ -1486,7 +1509,7 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos, pos++, pos_byte++; /* Perhaps add some info to the width_run_cache. */ - if (current_buffer->width_run_cache) + if (width_cache) { /* Is this character part of the current run? If so, extend the run. */ @@ -1502,8 +1525,7 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos, (Currently, we only cache runs of width == 1). */ if (width_run_start < width_run_end && width_run_width == 1) - know_region_cache (current_buffer, - current_buffer->width_run_cache, + know_region_cache (cache_buffer, width_cache, width_run_start, width_run_end); /* Start recording a new width run. */ @@ -1639,10 +1661,10 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos, after_loop: /* Remember any final width run in the cache. */ - if (current_buffer->width_run_cache + if (width_cache && width_run_width == 1 && width_run_start < width_run_end) - know_region_cache (current_buffer, current_buffer->width_run_cache, + know_region_cache (cache_buffer, width_cache, width_run_start, width_run_end); val_compute_motion.bufpos = pos; diff --git a/src/insdel.c b/src/insdel.c index dec8e074ec2..1c9bafd6004 100644 --- a/src/insdel.c +++ b/src/insdel.c @@ -1878,6 +1878,10 @@ prepare_to_modify_buffer (ptrdiff_t start, ptrdiff_t end, void invalidate_buffer_caches (struct buffer *buf, ptrdiff_t start, ptrdiff_t end) { + /* Indirect buffers usually have their caches set to NULL, but we + need to consider the caches of their base buffer. */ + if (buf->base_buffer) + buf = buf->base_buffer; if (buf->newline_cache) invalidate_region_cache (buf, buf->newline_cache, diff --git a/src/search.c b/src/search.c index aaaa31f24f3..40ab5db495a 100644 --- a/src/search.c +++ b/src/search.c @@ -602,23 +602,47 @@ fast_looking_at (Lisp_Object regexp, ptrdiff_t pos, ptrdiff_t pos_byte, Otherwise, make sure it's off. This is our cheezy way of associating an action with the change of state of a buffer-local variable. */ -static void +static struct region_cache * newline_cache_on_off (struct buffer *buf) { + struct buffer *base_buf = buf; + bool indirect_p = false; + + if (buf->base_buffer) + { + base_buf = buf->base_buffer; + indirect_p = true; + } + + /* Don't turn on or off the cache in the base buffer, if the value + of cache-long-scans of the base buffer is inconsistent with that. + This is because doing so will just make the cache pure overhead, + since if we turn it on via indirect buffer, it will be + immediately turned off by its base buffer. */ if (NILP (BVAR (buf, cache_long_scans))) { - /* It should be off. */ - if (buf->newline_cache) - { - free_region_cache (buf->newline_cache); - buf->newline_cache = 0; - } + if (!indirect_p + || NILP (BVAR (base_buf, cache_long_scans))) + { + /* It should be off. */ + if (base_buf->newline_cache) + { + free_region_cache (base_buf->newline_cache); + base_buf->newline_cache = 0; + } + } + return NULL; } else { - /* It should be on. */ - if (buf->newline_cache == 0) - buf->newline_cache = new_region_cache (); + if (!indirect_p + || !NILP (BVAR (base_buf, cache_long_scans))) + { + /* It should be on. */ + if (base_buf->newline_cache == 0) + base_buf->newline_cache = new_region_cache (); + } + return base_buf->newline_cache; } } @@ -653,6 +677,7 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, { struct region_cache *newline_cache; int direction; + struct buffer *cache_buffer; if (count > 0) { @@ -669,8 +694,11 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, if (end_byte == -1) end_byte = CHAR_TO_BYTE (end); - newline_cache_on_off (current_buffer); - newline_cache = current_buffer->newline_cache; + newline_cache = newline_cache_on_off (current_buffer); + if (current_buffer->base_buffer) + cache_buffer = current_buffer->base_buffer; + else + cache_buffer = current_buffer; if (shortage != 0) *shortage = 0; @@ -694,7 +722,7 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, ptrdiff_t next_change; immediate_quit = 0; while (region_cache_forward - (current_buffer, newline_cache, start, &next_change)) + (cache_buffer, newline_cache, start, &next_change)) start = next_change; immediate_quit = allow_quit; @@ -738,7 +766,7 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, this line's region is free of them. */ if (newline_cache) { - know_region_cache (current_buffer, newline_cache, + know_region_cache (cache_buffer, newline_cache, BYTE_TO_CHAR (lim_byte + cursor), BYTE_TO_CHAR (lim_byte + next)); /* know_region_cache can relocate buffer text. */ @@ -774,7 +802,7 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, ptrdiff_t next_change; immediate_quit = 0; while (region_cache_backward - (current_buffer, newline_cache, start, &next_change)) + (cache_buffer, newline_cache, start, &next_change)) start = next_change; immediate_quit = allow_quit; @@ -814,7 +842,7 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, this line's region is free of them. */ if (newline_cache) { - know_region_cache (current_buffer, newline_cache, + know_region_cache (cache_buffer, newline_cache, BYTE_TO_CHAR (ceiling_byte + prev + 1), BYTE_TO_CHAR (ceiling_byte + cursor)); /* know_region_cache can relocate buffer text. */ diff --git a/src/xdisp.c b/src/xdisp.c index 8e2ac437ca3..035edc0ff55 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -15767,16 +15767,20 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) this may be a bit late to catch such changes, but the rest of redisplay goes (non-fatally) haywire when the display table is changed, so why should we worry about doing any better? */ - if (current_buffer->width_run_cache) + if (current_buffer->width_run_cache + || (current_buffer->base_buffer + && current_buffer->base_buffer->width_run_cache)) { struct Lisp_Char_Table *disptab = buffer_display_table (); if (! disptab_matches_widthtab (disptab, XVECTOR (BVAR (current_buffer, width_table)))) { - invalidate_region_cache (current_buffer, - current_buffer->width_run_cache, - BEG, Z); + struct buffer *buf = current_buffer; + + if (buf->base_buffer) + buf = buf->base_buffer; + invalidate_region_cache (buf, buf->width_run_cache, BEG, Z); recompute_width_table (current_buffer, disptab); } } -- 2.39.2