Commit c10e9ece authored by Eli Zaretskii's avatar Eli Zaretskii
Browse files

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.
parent 6bc383b1
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.
......
......@@ -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);
......
......@@ -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,
......
......@@ -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. */
......
......@@ -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);
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment