summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/lispref/ChangeLog6
-rw-r--r--doc/lispref/display.texi4
-rw-r--r--doc/lispref/positions.texi2
-rw-r--r--src/ChangeLog19
-rw-r--r--src/bidi.c39
-rw-r--r--src/buffer.c30
-rw-r--r--src/buffer.h11
-rw-r--r--src/indent.c6
-rw-r--r--src/insdel.c4
-rw-r--r--src/search.c4
10 files changed, 102 insertions, 23 deletions
diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog
index 82bc279fa5b..0aac5235a29 100644
--- a/doc/lispref/ChangeLog
+++ b/doc/lispref/ChangeLog
@@ -1,3 +1,9 @@
+2013-08-06 Dmitry Antipov <dmantipov@yandex.ru>
+
+ * positions.texi (Motion by Screen Lines):
+ * display.texi (Truncation): Rename `cache-long-line-scans'
+ to `cache-long-scans'.
+
2013-08-05 Xue Fuqiao <xfq.free@gmail.com>
* windows.texi (Window Start and End): Add an index.
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index c5068425c66..59a6f5ce340 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -217,9 +217,9 @@ over the @code{line-prefix} variable. @xref{Special Properties}.
continuation to display them, computing the continuation lines can
make redisplay slow. The column computation and indentation functions
also become slow. Then you might find it advisable to set
-@code{cache-long-line-scans} to @code{t}.
+@code{cache-long-scans} to @code{t}.
-@defvar cache-long-line-scans
+@defvar cache-long-scans
If this variable is non-@code{nil}, various indentation and motion
functions, and Emacs redisplay, cache the results of scanning the
buffer, and consult the cache to avoid rescanning regions of the buffer
diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi
index e8b6166f63c..119ad98a53d 100644
--- a/doc/lispref/positions.texi
+++ b/doc/lispref/positions.texi
@@ -483,7 +483,7 @@ Display}.
These functions scan text to determine where screen lines break, and
thus take time proportional to the distance scanned. If you intend to
use them heavily, Emacs provides caches which may improve the
-performance of your code. @xref{Truncation, cache-long-line-scans}.
+performance of your code. @xref{Truncation, cache-long-scans}.
@defun vertical-motion count &optional window
This function moves point to the start of the screen line @var{count}
diff --git a/src/ChangeLog b/src/ChangeLog
index 7b7d9b56cb5..e8c09b3b4f3 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,24 @@
2013-08-06 Dmitry Antipov <dmantipov@yandex.ru>
+ Use region cache to speedup bidi_find_paragraph_start.
+ * buffer.h (struct buffer): New member bidi_paragraph_cache.
+ Rename cache_long_line_scans to cache_long_scans.
+ * buffer.c (bset_cache_long_line_scans): Rename to
+ bset_cache_long_scans.
+ (Fget_buffer_create, Fmake_indirect_buffer, Fkill_buffer)
+ (Fbuffer_swap_text, init_buffer_once): Take bidi_paragraph_cache
+ into account.
+ (syms_of_buffer): Rename cache-long-line-scans to
+ cache-long-scans. Adjust docstring.
+ * search.c (newline_cache_on_off):
+ * indent.c (width_run_cache_on_off): Adjust users.
+ * bidi.c (bidi_paragraph_cache_on_off): New function.
+ (bidi_find_paragraph_start): Use bidi_paragraph_cache if needed.
+ * insdel.c (prepare_to_modify_buffer): Invalidate
+ bidi_paragraph_cache if enabled.
+
+2013-08-06 Dmitry Antipov <dmantipov@yandex.ru>
+
Invalidate region caches only if buffer text is going to be changed.
* lisp.h (modify_region_1): Remove 3rd arg and rename to...
(modify_text): ...new prototype.
diff --git a/src/bidi.c b/src/bidi.c
index c31d208ecbc..7d082a94997 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -61,6 +61,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include "character.h"
#include "buffer.h"
#include "dispextern.h"
+#include "region-cache.h"
static bool bidi_initialized = 0;
@@ -1085,6 +1086,29 @@ bidi_at_paragraph_end (ptrdiff_t charpos, ptrdiff_t bytepos)
return val;
}
+/* If the user has requested the long scans caching, make sure that
+ BIDI cache is enabled. Otherwise, make sure it's disabled. */
+
+static struct region_cache *
+bidi_paragraph_cache_on_off (void)
+{
+ if (NILP (BVAR (current_buffer, cache_long_scans)))
+ {
+ if (current_buffer->bidi_paragraph_cache)
+ {
+ free_region_cache (current_buffer->bidi_paragraph_cache);
+ current_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;
+ }
+}
+
/* On my 2005-vintage machine, searching back for paragraph start
takes ~1 ms per line. And bidi_paragraph_init is called 4 times
when user types C-p. The number below limits each call to
@@ -1100,7 +1124,8 @@ bidi_find_paragraph_start (ptrdiff_t pos, ptrdiff_t pos_byte)
{
Lisp_Object re = paragraph_start_re;
ptrdiff_t limit = ZV, limit_byte = ZV_BYTE;
- ptrdiff_t n = 0;
+ struct region_cache *bpc = bidi_paragraph_cache_on_off ();
+ ptrdiff_t n = 0, oldpos = pos, next;
while (pos_byte > BEGV_BYTE
&& n++ < MAX_PARAGRAPH_SEARCH
@@ -1111,10 +1136,18 @@ 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);
- pos = find_newline_no_quit (pos, pos_byte, -1, &pos_byte);
+ if (bpc && region_cache_backward (current_buffer, bpc, pos, &next))
+ {
+ pos = next, pos_byte = CHAR_TO_BYTE (pos);
+ break;
+ }
+ else
+ pos = find_newline_no_quit (pos, pos_byte, -1, &pos_byte);
}
if (n >= MAX_PARAGRAPH_SEARCH)
- pos_byte = BEGV_BYTE;
+ pos = BEGV, pos_byte = BEGV_BYTE;
+ if (bpc)
+ know_region_cache (current_buffer, bpc, pos, oldpos);
return pos_byte;
}
diff --git a/src/buffer.c b/src/buffer.c
index f9154d42b03..339175d9078 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -203,9 +203,9 @@ bset_buffer_file_coding_system (struct buffer *b, Lisp_Object val)
b->INTERNAL_FIELD (buffer_file_coding_system) = val;
}
static void
-bset_cache_long_line_scans (struct buffer *b, Lisp_Object val)
+bset_cache_long_scans (struct buffer *b, Lisp_Object val)
{
- b->INTERNAL_FIELD (cache_long_line_scans) = val;
+ b->INTERNAL_FIELD (cache_long_scans) = val;
}
static void
bset_case_fold_search (struct buffer *b, Lisp_Object val)
@@ -583,6 +583,7 @@ even if it is dead. The return value is never nil. */)
b->newline_cache = 0;
b->width_run_cache = 0;
+ b->bidi_paragraph_cache = 0;
bset_width_table (b, Qnil);
b->prevent_redisplay_optimizations_p = 1;
@@ -806,6 +807,7 @@ CLONE nil means the indirect buffer's state is reset to default values. */)
b->newline_cache = 0;
b->width_run_cache = 0;
+ b->bidi_paragraph_cache = 0;
bset_width_table (b, Qnil);
name = Fcopy_sequence (name);
@@ -1945,6 +1947,11 @@ cleaning up all windows currently displaying the buffer to be killed. */)
free_region_cache (b->width_run_cache);
b->width_run_cache = 0;
}
+ if (b->bidi_paragraph_cache)
+ {
+ free_region_cache (b->bidi_paragraph_cache);
+ b->bidi_paragraph_cache = 0;
+ }
bset_width_table (b, Qnil);
unblock_input ();
bset_undo_list (b, Qnil);
@@ -2355,6 +2362,7 @@ DEFUN ("buffer-swap-text", Fbuffer_swap_text, Sbuffer_swap_text,
current_buffer->clip_changed = 1; other_buffer->clip_changed = 1;
swapfield (newline_cache, struct region_cache *);
swapfield (width_run_cache, struct region_cache *);
+ swapfield (bidi_paragraph_cache, struct region_cache *);
current_buffer->prevent_redisplay_optimizations_p = 1;
other_buffer->prevent_redisplay_optimizations_p = 1;
swapfield (overlays_before, struct Lisp_Overlay *);
@@ -5169,7 +5177,7 @@ init_buffer_once (void)
bset_buffer_file_coding_system (&buffer_defaults, Qnil);
XSETFASTINT (BVAR (&buffer_defaults, fill_column), 70);
XSETFASTINT (BVAR (&buffer_defaults, left_margin), 0);
- bset_cache_long_line_scans (&buffer_defaults, Qnil);
+ bset_cache_long_scans (&buffer_defaults, Qnil);
bset_file_truename (&buffer_defaults, Qnil);
XSETFASTINT (BVAR (&buffer_defaults, display_count), 0);
XSETFASTINT (BVAR (&buffer_defaults, left_margin_cols), 0);
@@ -5233,7 +5241,7 @@ init_buffer_once (void)
XSETFASTINT (BVAR (&buffer_local_flags, abbrev_table), idx); ++idx;
XSETFASTINT (BVAR (&buffer_local_flags, display_table), idx); ++idx;
XSETFASTINT (BVAR (&buffer_local_flags, syntax_table), idx); ++idx;
- XSETFASTINT (BVAR (&buffer_local_flags, cache_long_line_scans), idx); ++idx;
+ XSETFASTINT (BVAR (&buffer_local_flags, cache_long_scans), idx); ++idx;
XSETFASTINT (BVAR (&buffer_local_flags, category_table), idx); ++idx;
XSETFASTINT (BVAR (&buffer_local_flags, bidi_display_reordering), idx); ++idx;
XSETFASTINT (BVAR (&buffer_local_flags, bidi_paragraph_direction), idx); ++idx;
@@ -6120,8 +6128,8 @@ If the value of the variable is t, undo information is not recorded. */);
DEFVAR_PER_BUFFER ("mark-active", &BVAR (current_buffer, mark_active), Qnil,
doc: /* Non-nil means the mark and region are currently active in this buffer. */);
- DEFVAR_PER_BUFFER ("cache-long-line-scans", &BVAR (current_buffer, cache_long_line_scans), Qnil,
- doc: /* Non-nil means that Emacs should use caches to handle long lines more quickly.
+ DEFVAR_PER_BUFFER ("cache-long-scans", &BVAR (current_buffer, cache_long_scans), Qnil,
+ doc: /* Non-nil means that Emacs should use caches in attempt to speedup buffer scans.
Normally, the line-motion functions work by scanning the buffer for
newlines. Columnar operations (like `move-to-column' and
@@ -6131,18 +6139,24 @@ buffer's lines are very long (say, more than 500 characters), these
motion functions will take longer to execute. Emacs may also take
longer to update the display.
-If `cache-long-line-scans' is non-nil, these motion functions cache the
+If `cache-long-scans' is non-nil, these motion functions cache the
results of their scans, and consult the cache to avoid rescanning
regions of the buffer until the text is modified. The caches are most
beneficial when they prevent the most searching---that is, when the
buffer contains long lines and large regions of characters with the
same, fixed screen width.
-When `cache-long-line-scans' is non-nil, processing short lines will
+When `cache-long-scans' is non-nil, processing short lines will
become slightly slower (because of the overhead of consulting the
cache), and the caches will use memory roughly proportional to the
number of newlines and characters whose screen width varies.
+Bidirectional editing also requires buffer scans to find paragraph
+separators. If you have large paragraphs or no paragraph separators
+at all, these scans may be slow. If `cache-long-scans' is non-nil,
+results of these scans are cached. This doesn't help too much if
+paragraphs are of the reasonable (few thousands of characters) size.
+
The caches require no explicit maintenance; their accuracy is
maintained internally by the Emacs primitives. Enabling or disabling
the cache should not affect the behavior of any of the motion
diff --git a/src/buffer.h b/src/buffer.h
index 646f8f72232..221db39329a 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -632,9 +632,9 @@ struct buffer
/* List of symbols naming the file format used for auto-save file. */
Lisp_Object INTERNAL_FIELD (auto_save_file_format);
- /* True if the newline position cache and width run cache are
- enabled. See search.c and indent.c. */
- Lisp_Object INTERNAL_FIELD (cache_long_line_scans);
+ /* True if the newline position cache, width run cache and BIDI paragraph
+ cache are enabled. See search.c, indent.c and bidi.c for details. */
+ Lisp_Object INTERNAL_FIELD (cache_long_scans);
/* If the width run cache is enabled, this table contains the
character widths width_run_cache (see above) assumes. When we
@@ -839,9 +839,12 @@ struct buffer
the character's width; if it maps a character to zero, we don't
know what its width is. This allows compute_motion to process
such regions very quickly, using algebra instead of inspecting
- each character. See also width_table, below. */
+ each character. See also width_table, below.
+
+ The latter cache is used to speedup bidi_find_paragraph_start. */
struct region_cache *newline_cache;
struct region_cache *width_run_cache;
+ struct region_cache *bidi_paragraph_cache;
/* Non-zero means don't use redisplay optimizations for
displaying this buffer. */
diff --git a/src/indent.c b/src/indent.c
index 47358e17db8..6aaf86579d7 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -141,13 +141,13 @@ recompute_width_table (struct buffer *buf, struct Lisp_Char_Table *disptab)
XSETFASTINT (widthtab->contents[i], character_width (i, disptab));
}
-/* Allocate or free the width run cache, as requested by the current
- state of current_buffer's cache_long_line_scans variable. */
+/* Allocate or free the width run cache, as requested by the
+ current state of current_buffer's cache_long_scans variable. */
static void
width_run_cache_on_off (void)
{
- if (NILP (BVAR (current_buffer, cache_long_line_scans))
+ 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)))
diff --git a/src/insdel.c b/src/insdel.c
index ac64299a997..f746fd34330 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -1879,6 +1879,10 @@ prepare_to_modify_buffer (ptrdiff_t start, ptrdiff_t end,
invalidate_region_cache (current_buffer,
current_buffer->width_run_cache,
start - BEG, Z - end);
+ if (current_buffer->bidi_paragraph_cache)
+ invalidate_region_cache (current_buffer,
+ current_buffer->bidi_paragraph_cache,
+ start - BEG, Z - end);
}
/* These macros work with an argument named `preserve_ptr'
diff --git a/src/search.c b/src/search.c
index 0f4d41586a3..761c12a364a 100644
--- a/src/search.c
+++ b/src/search.c
@@ -598,14 +598,14 @@ fast_looking_at (Lisp_Object regexp, ptrdiff_t pos, ptrdiff_t pos_byte,
/* The newline cache: remembering which sections of text have no newlines. */
-/* If the user has requested newline caching, make sure it's on.
+/* If the user has requested the long scans caching, make sure it's on.
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
newline_cache_on_off (struct buffer *buf)
{
- if (NILP (BVAR (buf, cache_long_line_scans)))
+ if (NILP (BVAR (buf, cache_long_scans)))
{
/* It should be off. */
if (buf->newline_cache)