mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-23 07:19:15 +00:00
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.
This commit is contained in:
parent
6bc383b1a4
commit
c10e9ece08
@ -1,3 +1,25 @@
|
||||
2014-01-01 Eli Zaretskii <eliz@gnu.org>
|
||||
|
||||
* 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 <rudalics@gmx.at>
|
||||
|
||||
* window.c (grow_mini_window): Fix last change.
|
||||
|
44
src/bidi.c
44
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);
|
||||
|
@ -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);
|
||||
|
68
src/indent.c
68
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;
|
||||
|
@ -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,
|
||||
|
60
src/search.c
60
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. */
|
||||
|
12
src/xdisp.c
12
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user