emacs, The GNU Emacs Manual}) runs these two hooks just as a keyboard
command does.
+ Note that, when the buffer text includes very long lines, these two
+hooks are called as if they were in a @code{with-narrowing} form (see
+@ref{Narrowing}), with a
+@code{long-line-optimizations-in-command-hooks} label and with the
+buffer narrowed to a portion around point.
+
@node Defining Commands
@section Defining Commands
@cindex defining commands
For efficiency, we recommend writing these functions so that they
usually assign faces to around 400 to 600 characters at each call.
-When the buffer text includes very long lines, these functions are
-called with the buffer narrowed to a relatively small region around
-@var{pos}, and with narrowing locked, so the functions cannot use
-@code{widen} to gain access to the rest of the buffer.
-@xref{Narrowing}.
+Note that, when the buffer text includes very long lines, these
+functions are called as if they were in a @code{with-narrowing} form
+(see @ref{Narrowing}), with a
+@code{long-line-optimizations-in-fontification-functions} label and
+with the buffer narrowed to a portion around @var{pos}.
@end defvar
@node Basic Faces
In an interactive call, @var{start} and @var{end} are set to the bounds
of the current region (point and the mark, with the smallest first).
-Note that, in rare circumstances, Emacs may decide to leave, for
-performance reasons, the accessible portion of the buffer unchanged
-after a call to @code{narrow-to-region}. This can happen when a Lisp
-program is called via low-level hooks, such as
-@code{jit-lock-functions}, @code{post-command-hook}, etc.
+However, when the narrowing has been set by @code{with-narrowing} with
+a label argument (see below), @code{narrow-to-region} can be used only
+within the limits of that narrowing. If @var{start} or @var{end} are
+outside these limits, the corresponding limit set by
+@code{with-narrowing} is used instead. To gain access to other
+portions of the buffer, use @code{without-narrowing} with the same
+label.
@end deffn
@deffn Command narrow-to-page &optional move-count
@example
(narrow-to-region 1 (1+ (buffer-size)))
@end example
-@end deffn
-Note that, in rare circumstances, Emacs may decide to leave, for
-performance reasons, the accessible portion of the buffer unchanged
-after a call to @code{widen}. This can happen when a Lisp program is
-called via low-level hooks, such as @code{jit-lock-functions},
-@code{post-command-hook}, etc.
+However, when a narrowing has been set by @code{with-narrowing} with a
+label argument (see below), the limits set by @code{with-narrowing}
+are restored, instead of canceling the narrowing. To gain access to
+other portions of the buffer, use @code{without-narrowing} with the
+same label.
+@end deffn
@defun buffer-narrowed-p
This function returns non-@code{nil} if the buffer is narrowed, and
abnormal exit via @code{throw} or error (@pxref{Nonlocal Exits}).
Therefore, this construct is a clean way to narrow a buffer temporarily.
+This construct also saves and restores the narrowings that were set by
+@code{with-narrowing} with a label argument (see below).
+
The value returned by @code{save-restriction} is that returned by the
last form in @var{body}, or @code{nil} if no body forms were given.
@end group
@end example
@end defspec
+
+@defspec with-narrowing start end [:label label] body
+This special form saves the current bounds of the accessible portion
+of the buffer, sets the accessible portion to start at @var{start} and
+end at @var{end}, evaluates the @var{body} forms, and restores the
+saved bounds. In that case it is equivalent to
+
+@example
+(save-restriction
+ (narrow-to-region start end)
+ body)
+@end example
+
+When the optional @var{label} symbol argument is present however, the
+narrowing is labeled. A labeled narrowing differs from a non-labeled
+one in several ways:
+
+@itemize @bullet
+@item
+During the evaluation of the @var{body} form, @code{narrow-to-region}
+and @code{widen} can be used only within the @var{start} and @var{end}
+limits.
+
+@item
+To lift the restriction introduced by @code{with-narrowing} and gain
+access to other portions of the buffer, use @code{without-narrowing}
+with the same @var{label} argument. (Another way to gain access to
+other portions of the buffer is to use an indirect buffer
+(@pxref{Indirect Buffers}).)
+
+@item
+Labeled narrowings can be nested.
+
+@item
+Labeled narrowings can only be used in Lisp programs: they are never
+visible on display, and never interfere with narrowings set by the
+user.
+@end itemize
+@end defspec
+
+@defspec without-narrowing [:label label] body
+This special form saves the current bounds of the accessible portion
+of the buffer, widens the buffer, evaluates the @var{body} forms, and
+restores the saved bounds. In that case it is equivalent to
+
+@example
+(save-restriction
+ (widen)
+ body)
+@end example
+
+When the optional @var{label} argument is present however, the
+narrowing set by @code{with-narrowing} with the same @var{label}
+argument are lifted.
+@end defspec
and the major mode with 'M-x so-long-mode', or visit the file with
'M-x find-file-literally' instead of the usual 'C-x C-f'.
-Note that the display optimizations in these cases may cause the
-buffer to be occasionally mis-fontified.
+In buffers in which these display optimizations are in effect, the
+'fontification-functions', 'pre-command-hook' and 'post-command-hook'
+hooks are executed on a narrowed portion of the buffer, whose size is
+controlled by the options 'long-line-optimizations-region-size' and
+'long-line-optimizations-bol-search-limit'. This may, in particular,
+cause occasional mis-fontifications in these buffers.
The new function 'long-line-optimizations-p' returns non-nil when
these optimizations are in effect in the current buffer.
The default timeout value can be defined by the new variable
'set-transient-map-timeout'.
++++
+** New forms 'with-narrowing' and 'without-narrowing'.
+These forms can be used as enhanced alternatives to the
+'save-restriction' form combined with, respectively,
+'narrow-to-region' and 'widen'. They also accept an optional label
+argument, with which labeled narrowings can be created and lifted.
+See the "(elisp) Narrowing" node for details.
+
** Connection Local Variables
+++
The current restrictions, if any, are restored upon return.
-With the optional :locked TAG argument, inside BODY,
-`narrow-to-region' and `widen' can be used only within the START
-and END limits, unless the restrictions are unlocked by calling
-`narrowing-unlock' with TAG. See `narrowing-lock' for a more
-detailed description.
+When the optional :label LABEL argument is present, in which
+LABEL is a symbol, inside BODY, `narrow-to-region' and `widen'
+can be used only within the START and END limits. To gain access
+to other portions of the buffer, use `without-narrowing' with the
+same LABEL argument.
\(fn START END [:label LABEL] BODY)"
(if (eq (car rest) :label)
The current restrictions, if any, are restored upon return.
+When the optional :label LABEL argument is present, the
+restrictions set by `with-narrowing' with the same LABEL argument
+are lifted.
+
\(fn [:label LABEL] BODY)"
(if (eq (car rest) :label)
`(internal--without-narrowing (lambda () ,@(cddr rest))
DEFVAR_INT ("long-line-optimizations-region-size",
long_line_optimizations_region_size,
- doc: /* Region size for locked narrowing in buffers with long lines.
+ doc: /* Region size for narrowing in buffers with long lines.
-This variable has effect only in buffers which contain one or more
-lines whose length is above `long-line-threshold', which see. For
-performance reasons, in such buffers, low-level hooks such as
-`fontification-functions' or `post-command-hook' are executed on a
-narrowed buffer, with a narrowing locked with `narrowing-lock'. This
-variable specifies the size of the narrowed region around point.
+This variable has effect only in buffers in which
+`long-line-optimizations-p' is non-nil. For performance reasons, in
+such buffers, the `fontification-functions', `pre-command-hook' and
+`post-command-hook' hooks are executed on a narrowed buffer around
+point, as if they were called in a `with-narrowing' form with a label.
+This variable specifies the size of the narrowed region around point.
To disable that narrowing, set this variable to 0.
-See also `long-line-locked-narrowing-bol-search-limit'.
+See also `long-line-optimizations-bol-search-limit'.
There is no reason to change that value except for debugging purposes. */);
long_line_optimizations_region_size = 500000;
long_line_optimizations_bol_search_limit,
doc: /* Limit for beginning of line search in buffers with long lines.
-This variable has effect only in buffers which contain one or more
-lines whose length is above `long-line-threshold', which see. For
-performance reasons, in such buffers, low-level hooks such as
-`fontification-functions' or `post-command-hook' are executed on a
-narrowed buffer, with a narrowing locked with `narrowing-lock'. The
-variable `long-line-locked-narrowing-region-size' specifies the size
-of the narrowed region around point. This variable, which should be a
-small integer, specifies the number of characters by which that region
-can be extended backwards to make it start at the beginning of a line.
+This variable has effect only in buffers in which
+`long-line-optimizations-p' is non-nil. For performance reasons, in
+such buffers, the `fontification-functions', `pre-command-hook' and
+`post-command-hook' hooks are executed on a narrowed buffer around
+point, as if they were called in a `with-narrowing' form with a label.
+The variable `long-line-optimizations-region-size' specifies the
+size of the narrowed region around point. This variable, which should
+be a small integer, specifies the number of characters by which that
+region can be extended backwards to make it start at the beginning of
+a line.
There is no reason to change that value except for debugging purposes. */);
long_line_optimizations_bol_search_limit = 128;
the (uninterned) Qoutermost_narrowing tag and records the narrowing
bounds that were set by the user and that are visible on display.
This alist is used internally by narrow-to-region, widen,
- narrowing-lock, narrowing-unlock and save-restriction. */
+ internal--lock-narrowing, internal--unlock-narrowing and
+ save-restriction. For efficiency reasons, an alist is used instead
+ of a buffer-local variable: otherwise reset_outermost_narrowings,
+ which is called during each redisplay cycle, would have to loop
+ through all live buffers. */
static Lisp_Object narrowing_locks;
/* Add BUF with its LOCKS in the narrowing_locks alist. */
In particular, this function is called when redisplay starts, so
that if a Lisp function executed during redisplay calls (redisplay)
while a locked narrowing is in effect, the locked narrowing will
- not be visible on display. */
+ not be visible on display.
+ See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=57207#140 and
+ https://debbugs.gnu.org/cgi/bugreport.cgi?bug=57207#254 for example
+ recipes that demonstrate why this is necessary. */
void
reset_outermost_narrowings (void)
{
DEFUN ("widen", Fwiden, Swiden, 0, 0, "",
doc: /* Remove restrictions (narrowing) from current buffer.
-This allows the buffer's full text to be seen and edited, unless
-restrictions have been locked with `narrowing-lock', which see, in
-which case the narrowing that was current when `narrowing-lock' was
-called is restored. */)
+This allows the buffer's full text to be seen and edited.
+
+However, when restrictions have been set by `with-narrowing' with a
+label, `widen' restores the narrowing limits set by `with-narrowing'.
+To gain access to other portions of the buffer, use
+`without-narrowing' with the same label. */)
(void)
{
Fset (Qoutermost_narrowing, Qnil);
positions (integers or markers) bounding the text that should
remain visible.
-When restrictions have been locked with `narrowing-lock', which see,
-`narrow-to-region' can be used only within the limits of the
-restrictions that were current when `narrowing-lock' was called. If
-the START or END arguments are outside these limits, the corresponding
-limit of the locked restriction is used instead of the argument. */)
+However, when restrictions have been set by `with-narrowing' with a
+label, `narrow-to-region' can be used only within the limits of these
+restrictions. If the START or END arguments are outside these limits,
+the corresponding limit set by `with-narrowing' is used instead of the
+argument. To gain access to other portions of the buffer, use
+`without-narrowing' with the same label. */)
(Lisp_Object start, Lisp_Object end)
{
EMACS_INT s = fix_position (start), e = fix_position (end);
/* Record the accessible range of the buffer when narrow-to-region
is called, that is, before applying the narrowing. It is used
- only by narrowing-lock. */
+ only by internal--lock-narrowing. */
Fset (Qoutermost_narrowing, list3 (Qoutermost_narrowing,
Fpoint_min_marker (),
Fpoint_max_marker ()));
DEFUN ("internal--lock-narrowing", Finternal__lock_narrowing,
Sinternal__lock_narrowing, 1, 1, 0,
- doc: /* Lock the current narrowing with TAG.
-
-When restrictions are locked, `narrow-to-region' and `widen' can be
-used only within the limits of the restrictions that were current when
-`narrowing-lock' was called, unless the lock is removed by calling
-`narrowing-unlock' with TAG.
-
-Locking restrictions should be used sparingly, after carefully
-considering the potential adverse effects on the code that will be
-executed within locked restrictions. It is typically meant to be used
-around portions of code that would become too slow, and make Emacs
-unresponsive, if they were executed in a large buffer. For example,
-restrictions are locked by Emacs around low-level hooks such as
-`fontification-functions' or `post-command-hook'.
-
-Locked restrictions are never visible on display, and can therefore
-not be used as a stronger variant of normal restrictions. */)
+ doc: /* Lock the current narrowing with LABEL.
+
+This is an internal function used by `with-narrowing'. */)
(Lisp_Object tag)
{
Lisp_Object buf = Fcurrent_buffer ();
Lisp_Object outermost_narrowing
= buffer_local_value (Qoutermost_narrowing, buf);
- /* If narrowing-lock is called without being preceded by
- narrow-to-region, do nothing. */
+ /* If internal--lock-narrowing is ever called without being preceded
+ by narrow-to-region, do nothing. */
if (NILP (outermost_narrowing))
return Qnil;
if (NILP (narrowing_lock_peek_tag (buf)))
DEFUN ("internal--unlock-narrowing", Finternal__unlock_narrowing,
Sinternal__unlock_narrowing, 1, 1, 0,
- doc: /* Unlock a narrowing locked with (narrowing-lock TAG).
-
-Unlocking restrictions locked with `narrowing-lock' should be used
-sparingly, after carefully considering the reasons why restrictions
-were locked. Restrictions are typically locked around portions of
-code that would become too slow, and make Emacs unresponsive, if they
-were executed in a large buffer. For example, restrictions are locked
-by Emacs around low-level hooks such as `fontification-functions' or
-`post-command-hook'. */)
+ doc: /* Unlock a narrowing locked with LABEL.
+
+This is an internal function used by `without-narrowing'. */)
(Lisp_Object tag)
{
Lisp_Object buf = Fcurrent_buffer ();
The buffer's restrictions make parts of the beginning and end invisible.
\(They are set up with `narrow-to-region' and eliminated with `widen'.)
This special form, `save-restriction', saves the current buffer's
-restrictions, as well as their locks if they have been locked with
-`narrowing-lock', when it is entered, and restores them when it is exited.
+restrictions, including those that were set by `with-narrowing' with a
+label argument, when it is entered, and restores them when it is exited.
So any `narrow-to-region' within BODY lasts only until the end of the form.
The old restrictions settings are restored even in case of abnormal exit
\(throw or error).
which the error occurred is unconditionally removed, since otherwise
the error might happen repeatedly and make Emacs nonfunctional.
-Note that, when the current buffer contains one or more lines whose
-length is above `long-line-threshold', these hook functions are called
-with the buffer narrowed to a small portion around point (whose size
-is specified by `long-line-locked-narrowing-region-size'), and the
-narrowing is locked (see `narrowing-lock'), so that these hook
-functions cannot use `widen' to gain access to other portions of
-buffer text.
+Note that, when `long-line-optimizations-p' is non-nil in the buffer,
+these functions are called as if they were in a `with-narrowing' form,
+with a `long-line-optimizations-in-command-hooks' label and with the
+buffer narrowed to a portion around point whose size is specified by
+`long-line-optimizations-region-size'.
See also `post-command-hook'. */);
Vpre_command_hook = Qnil;
unavoidable, wrap your code in `(while-no-input (redisplay) CODE)' to
avoid making Emacs unresponsive while the user types.
-Note that, when the current buffer contains one or more lines whose
-length is above `long-line-threshold', these hook functions are called
-with the buffer narrowed to a small portion around point (whose size
-is specified by `long-line-locked-narrowing-region-size'), and the
-narrowing is locked (see `narrowing-lock'), so that these hook
-functions cannot use `widen' to gain access to other portions of
-buffer text.
+Note that, when `long-line-optimizations-p' is non-nil in the buffer,
+these functions are called as if they were in a `with-narrowing' form,
+with a `long-line-optimizations-in-command-hooks' label and with the
+buffer narrowed to a portion around point whose size is specified by
+`long-line-optimizations-region-size'.
See also `pre-command-hook'. */);
Vpost_command_hook = Qnil;
fontify a region starting at POS in the current buffer, and give
fontified regions the property `fontified' with a non-nil value.
-Note that, when the buffer contains one or more lines whose length is
-above `long-line-threshold', these functions are called with the
-buffer narrowed to a small portion around POS (whose size is specified
-by `long-line-locked-narrowing-region-size'), and the narrowing is
-locked (see `narrowing-lock'), so that these functions cannot use
-`widen' to gain access to other portions of buffer text. */);
+Note that, when `long-line-optimizations-p' is non-nil in the buffer,
+these functions are called as if they were in a `with-narrowing' form,
+with a `long-line-optimizations-in-fontification-functions' label and
+with the buffer narrowed to a portion around POS whose size is
+specified by `long-line-optimizations-region-size'. */);
Vfontification_functions = Qnil;
Fmake_variable_buffer_local (Qfontification_functions);