mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-05-02 03:00:56 -07:00
Reworked locked narrowing.
* src/editfns.c: (narrowing_locks): New alist to hold the narrowing locks and their buffers. (narrowing_lock_get_bound, narrowing_lock_peek_tag) (narrowing_lock_push, narrowing_lock_pop): New functions to access and update 'narrowing_locks'. (reset_outermost_narrowings, unwind_reset_outermost_narrowing): Functions moved from src/xdisp.c, and rewritten with the above functions. (Fwiden): Use the above functions. Update docstring. (Fnarrow_to_region, Fnarrowing_lock, Fnarrowing_unlock): Use the above functions. (syms_of_editfns): Remove the 'narrowing-locks' variable. * src/lisp.h: Make 'reset_outermost_narrowings' externally visible. * src/xdisp.c (reset_outermost_narrowings) unwind_reset_outermost_narrowing): Functions moved to src/editfns.c. * lisp/subr.el (with-locked-narrowing): Improved macro, with a helper function.
This commit is contained in:
parent
ba9315b164
commit
9dee6df39c
4 changed files with 179 additions and 87 deletions
19
lisp/subr.el
19
lisp/subr.el
|
|
@ -3943,14 +3943,17 @@ 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. The current
|
||||
restrictions, if any, are restored upon return."
|
||||
`(save-restriction
|
||||
(unwind-protect
|
||||
(progn
|
||||
(narrow-to-region ,start ,end)
|
||||
(narrowing-lock ,tag)
|
||||
,@body)
|
||||
(narrowing-unlock ,tag)
|
||||
(widen))))
|
||||
`(with-locked-narrowing-1 ,start ,end ,tag (lambda () ,@body)))
|
||||
|
||||
(defun with-locked-narrowing-1 (start end tag body)
|
||||
"Helper function for `with-locked-narrowing', which see."
|
||||
(save-restriction
|
||||
(unwind-protect
|
||||
(progn
|
||||
(narrow-to-region start end)
|
||||
(narrowing-lock tag)
|
||||
(funcall body))
|
||||
(narrowing-unlock tag))))
|
||||
|
||||
(defun find-tag-default-bounds ()
|
||||
"Determine the boundaries of the default tag, based on text at point.
|
||||
|
|
|
|||
212
src/editfns.c
212
src/editfns.c
|
|
@ -2653,18 +2653,144 @@ DEFUN ("delete-and-extract-region", Fdelete_and_extract_region,
|
|||
return del_range_1 (XFIXNUM (start), XFIXNUM (end), 1, 1);
|
||||
}
|
||||
|
||||
/* Alist of buffers in which locked narrowing is used. The car of
|
||||
each list element is a buffer, the cdr is a list of triplets (tag
|
||||
begv-marker zv-marker). The last element of that list always uses
|
||||
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 and narrowing-unlock. */
|
||||
static Lisp_Object narrowing_locks;
|
||||
|
||||
/* Retrieve one of the BEGV/ZV bounds of a narrowing in BUF from the
|
||||
narrowing_locks alist. When OUTERMOST is true, the bounds that
|
||||
were set by the user and that are visible on display are returned.
|
||||
Otherwise the innermost locked narrowing bounds are returned. */
|
||||
static ptrdiff_t
|
||||
narrowing_lock_get_bound (Lisp_Object buf, bool begv, bool outermost)
|
||||
{
|
||||
if (NILP (Fbuffer_live_p (buf)))
|
||||
return 0;
|
||||
Lisp_Object buffer_locks = assq_no_quit (buf, narrowing_locks);
|
||||
if (NILP (buffer_locks))
|
||||
return 0;
|
||||
buffer_locks = Fcar (Fcdr (buffer_locks));
|
||||
Lisp_Object bounds
|
||||
= outermost
|
||||
? Fcdr (assq_no_quit (Qoutermost_narrowing, buffer_locks))
|
||||
: Fcdr (Fcar (buffer_locks));
|
||||
eassert (! NILP (bounds));
|
||||
Lisp_Object marker = begv ? Fcar (bounds) : Fcar (Fcdr (bounds));
|
||||
eassert (MARKERP (marker));
|
||||
Lisp_Object pos = Fmarker_position (marker);
|
||||
eassert (! NILP (pos));
|
||||
return XFIXNUM (pos);
|
||||
}
|
||||
|
||||
/* Retrieve the tag of the innermost narrowing in BUF. */
|
||||
static Lisp_Object
|
||||
narrowing_lock_peek_tag (Lisp_Object buf)
|
||||
{
|
||||
if (NILP (Fbuffer_live_p (buf)))
|
||||
return Qnil;
|
||||
Lisp_Object buffer_locks = assq_no_quit (buf, narrowing_locks);
|
||||
if (NILP (buffer_locks))
|
||||
return Qnil;
|
||||
Lisp_Object tag = Fcar (Fcar (Fcar (Fcdr (buffer_locks))));
|
||||
eassert (! NILP (tag));
|
||||
return tag;
|
||||
}
|
||||
|
||||
/* Add a LOCK in BUF in the narrowing_locks alist. */
|
||||
static void
|
||||
narrowing_lock_push (Lisp_Object buf, Lisp_Object lock)
|
||||
{
|
||||
Lisp_Object buffer_locks = assq_no_quit (buf, narrowing_locks);
|
||||
if (NILP (buffer_locks))
|
||||
narrowing_locks = nconc2 (list1 (list2 (buf, list1 (lock))),
|
||||
narrowing_locks);
|
||||
else
|
||||
Fsetcdr (buffer_locks, list1 (nconc2 (list1 (lock),
|
||||
Fcar (Fcdr (buffer_locks)))));
|
||||
}
|
||||
|
||||
/* Remove the innermost lock in BUF from the narrowing_lock alist. */
|
||||
static void
|
||||
narrowing_lock_pop (Lisp_Object buf)
|
||||
{
|
||||
Lisp_Object buffer_locks = assq_no_quit (buf, narrowing_locks);
|
||||
eassert (! NILP (buffer_locks));
|
||||
if (EQ (narrowing_lock_peek_tag (buf), Qoutermost_narrowing))
|
||||
narrowing_locks = Fdelq (Fassoc (buf, narrowing_locks, Qnil),
|
||||
narrowing_locks);
|
||||
else
|
||||
Fsetcdr (buffer_locks, list1 (Fcdr (Fcar (Fcdr (buffer_locks)))));
|
||||
}
|
||||
|
||||
static void
|
||||
unwind_reset_outermost_narrowing (Lisp_Object buf)
|
||||
{
|
||||
ptrdiff_t begv, zv;
|
||||
begv = narrowing_lock_get_bound (buf, true, false);
|
||||
zv = narrowing_lock_get_bound (buf, false, false);
|
||||
if (begv && zv)
|
||||
{
|
||||
SET_BUF_BEGV (XBUFFER (buf), begv);
|
||||
SET_BUF_ZV (XBUFFER (buf), zv);
|
||||
}
|
||||
}
|
||||
|
||||
/* When redisplay is called in a function executed while a locked
|
||||
narrowing is in effect, restore the narrowing bounds that were set
|
||||
by the user, and restore the bounds of the locked narrowing when
|
||||
returning from redisplay. */
|
||||
void
|
||||
reset_outermost_narrowings (void)
|
||||
{
|
||||
Lisp_Object val, buf;
|
||||
for (val = narrowing_locks; CONSP (val); val = XCDR (val))
|
||||
{
|
||||
buf = Fcar (Fcar (val));
|
||||
eassert (BUFFERP (buf));
|
||||
ptrdiff_t begv = narrowing_lock_get_bound (buf, true, true);
|
||||
ptrdiff_t zv = narrowing_lock_get_bound (buf, false, true);
|
||||
SET_BUF_BEGV (XBUFFER (buf), begv);
|
||||
SET_BUF_ZV (XBUFFER (buf), zv);
|
||||
record_unwind_protect (unwind_reset_outermost_narrowing, buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unwind_narrow_to_region_locked (Lisp_Object tag)
|
||||
{
|
||||
Fnarrowing_unlock (tag);
|
||||
Fwiden ();
|
||||
}
|
||||
|
||||
/* Narrow current_buffer to BEGV-ZV with a locked narrowing */
|
||||
void
|
||||
narrow_to_region_locked (Lisp_Object begv, Lisp_Object zv, Lisp_Object tag)
|
||||
{
|
||||
Fnarrow_to_region (begv, zv);
|
||||
Fnarrowing_lock (tag);
|
||||
record_unwind_protect (restore_point_unwind, Fpoint_marker ());
|
||||
record_unwind_protect (unwind_narrow_to_region_locked, tag);
|
||||
}
|
||||
|
||||
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 restrictions that were current when `narrowing-lock'
|
||||
was called are restored. */)
|
||||
which case the narrowing that was current when `narrowing-lock' was
|
||||
called is restored. */)
|
||||
(void)
|
||||
{
|
||||
Fset (Qoutermost_narrowing, Qnil);
|
||||
Lisp_Object buf = Fcurrent_buffer ();
|
||||
Lisp_Object tag = narrowing_lock_peek_tag (buf);
|
||||
|
||||
if (NILP (Vnarrowing_locks))
|
||||
if (NILP (tag))
|
||||
{
|
||||
if (BEG != BEGV || Z != ZV)
|
||||
current_buffer->clip_changed = 1;
|
||||
|
|
@ -2674,14 +2800,18 @@ was called are restored. */)
|
|||
}
|
||||
else
|
||||
{
|
||||
ptrdiff_t begv = XFIXNUM (Fcar (Fcdr (Fcar (Vnarrowing_locks))));
|
||||
ptrdiff_t zv = XFIXNUM (Fcdr (Fcdr (Fcar (Vnarrowing_locks))));
|
||||
ptrdiff_t begv = narrowing_lock_get_bound (buf, true, false);
|
||||
ptrdiff_t zv = narrowing_lock_get_bound (buf, false, false);
|
||||
if (begv != BEGV || zv != ZV)
|
||||
current_buffer->clip_changed = 1;
|
||||
SET_BUF_BEGV (current_buffer, begv);
|
||||
SET_BUF_ZV (current_buffer, zv);
|
||||
if (EQ (Fcar (Fcar (Vnarrowing_locks)), Qoutermost_narrowing))
|
||||
Fset (Qnarrowing_locks, Qnil);
|
||||
/* If the only remaining bounds in narrowing_locks for
|
||||
current_buffer are the bounds that were set by the user, no
|
||||
locked narrowing is in effect in current_buffer anymore:
|
||||
remove it from the narrowing_locks alist. */
|
||||
if (EQ (tag, Qoutermost_narrowing))
|
||||
narrowing_lock_pop (buf);
|
||||
}
|
||||
/* Changing the buffer bounds invalidates any recorded current column. */
|
||||
invalidate_current_column ();
|
||||
|
|
@ -2716,20 +2846,25 @@ limit of the locked restriction is used instead of the argument. */)
|
|||
if (!(BEG <= s && s <= e && e <= Z))
|
||||
args_out_of_range (start, end);
|
||||
|
||||
if (! NILP (Vnarrowing_locks))
|
||||
Lisp_Object buf = Fcurrent_buffer ();
|
||||
if (! NILP (narrowing_lock_peek_tag (buf)))
|
||||
{
|
||||
ptrdiff_t begv = XFIXNUM (Fcar (Fcdr (Fcar (Vnarrowing_locks))));
|
||||
ptrdiff_t zv = XFIXNUM (Fcdr (Fcdr (Fcar (Vnarrowing_locks))));
|
||||
ptrdiff_t begv = narrowing_lock_get_bound (buf, true, false);
|
||||
ptrdiff_t zv = narrowing_lock_get_bound (buf, false, false);
|
||||
/* Limit the start and end positions to those of the locked
|
||||
narrowing. */
|
||||
if (s < begv) s = begv;
|
||||
if (s > zv) s = zv;
|
||||
if (e < begv) e = begv;
|
||||
if (e > zv) e = zv;
|
||||
}
|
||||
|
||||
Fset (Qoutermost_narrowing,
|
||||
Fcons (Fcons (Qoutermost_narrowing,
|
||||
Fcons (make_fixnum (BEGV), make_fixnum (ZV))),
|
||||
Qnil));
|
||||
/* 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. */
|
||||
Fset (Qoutermost_narrowing, list3 (Qoutermost_narrowing,
|
||||
Fpoint_min_marker (),
|
||||
Fpoint_max_marker ()));
|
||||
|
||||
if (BEGV != s || ZV != e)
|
||||
current_buffer->clip_changed = 1;
|
||||
|
|
@ -2766,11 +2901,18 @@ Locked restrictions are never visible on display, and can therefore
|
|||
not be used as a stronger variant of normal restrictions. */)
|
||||
(Lisp_Object tag)
|
||||
{
|
||||
if (NILP (Vnarrowing_locks))
|
||||
Fset (Qnarrowing_locks, Voutermost_narrowing);
|
||||
Fset (Qnarrowing_locks,
|
||||
Fcons (Fcons (tag, Fcons (make_fixnum (BEGV), make_fixnum (ZV))),
|
||||
Vnarrowing_locks));
|
||||
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 (NILP (outermost_narrowing))
|
||||
return Qnil;
|
||||
if (NILP (narrowing_lock_peek_tag (buf)))
|
||||
narrowing_lock_push (buf, outermost_narrowing);
|
||||
narrowing_lock_push (buf, list3 (tag,
|
||||
Fpoint_min_marker (),
|
||||
Fpoint_max_marker ()));
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
|
|
@ -2786,27 +2928,12 @@ by Emacs around low-level hooks such as `fontification-functions' or
|
|||
`post-command-hook'. */)
|
||||
(Lisp_Object tag)
|
||||
{
|
||||
if (EQ (Fcar (Fcar (Vnarrowing_locks)), tag))
|
||||
Fset (Qnarrowing_locks, Fcdr (Vnarrowing_locks));
|
||||
Lisp_Object buf = Fcurrent_buffer ();
|
||||
if (EQ (narrowing_lock_peek_tag (buf), tag))
|
||||
narrowing_lock_pop (buf);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static void
|
||||
unwind_narrow_to_region_locked (Lisp_Object tag)
|
||||
{
|
||||
Fnarrowing_unlock (tag);
|
||||
Fwiden ();
|
||||
}
|
||||
|
||||
void
|
||||
narrow_to_region_locked (Lisp_Object begv, Lisp_Object zv, Lisp_Object tag)
|
||||
{
|
||||
Fnarrow_to_region (begv, zv);
|
||||
Fnarrowing_lock (tag);
|
||||
record_unwind_protect (restore_point_unwind, Fpoint_marker ());
|
||||
record_unwind_protect (unwind_narrow_to_region_locked, tag);
|
||||
}
|
||||
|
||||
Lisp_Object
|
||||
save_restriction_save (void)
|
||||
{
|
||||
|
|
@ -4564,6 +4691,8 @@ syms_of_editfns (void)
|
|||
DEFSYM (Qwall, "wall");
|
||||
DEFSYM (Qpropertize, "propertize");
|
||||
|
||||
staticpro (&narrowing_locks);
|
||||
|
||||
DEFVAR_LISP ("inhibit-field-text-motion", Vinhibit_field_text_motion,
|
||||
doc: /* Non-nil means text motion commands don't notice fields. */);
|
||||
Vinhibit_field_text_motion = Qnil;
|
||||
|
|
@ -4623,18 +4752,11 @@ This variable is experimental; email 32252@debbugs.gnu.org if you need
|
|||
it to be non-nil. */);
|
||||
binary_as_unsigned = false;
|
||||
|
||||
DEFSYM (Qnarrowing_locks, "narrowing-locks");
|
||||
DEFVAR_LISP ("narrowing-locks", Vnarrowing_locks,
|
||||
doc: /* List of narrowing locks in the current buffer. Internal use only. */);
|
||||
Vnarrowing_locks = Qnil;
|
||||
Fmake_variable_buffer_local (Qnarrowing_locks);
|
||||
Funintern (Qnarrowing_locks, Qnil);
|
||||
|
||||
DEFSYM (Qoutermost_narrowing, "outermost-narrowing");
|
||||
DEFVAR_LISP ("outermost-narrowing", Voutermost_narrowing,
|
||||
doc: /* Outermost narrowing bounds, if any. Internal use only. */);
|
||||
Voutermost_narrowing = Qnil;
|
||||
Fmake_variable_buffer_local (Qoutermost_narrowing);
|
||||
DEFSYM (Qoutermost_narrowing, "outermost-narrowing");
|
||||
Funintern (Qoutermost_narrowing, Qnil);
|
||||
|
||||
defsubr (&Spropertize);
|
||||
|
|
|
|||
|
|
@ -4683,6 +4683,7 @@ extern Lisp_Object make_buffer_string (ptrdiff_t, ptrdiff_t, bool);
|
|||
extern Lisp_Object make_buffer_string_both (ptrdiff_t, ptrdiff_t, ptrdiff_t,
|
||||
ptrdiff_t, bool);
|
||||
extern void narrow_to_region_locked (Lisp_Object, Lisp_Object, Lisp_Object);
|
||||
extern void reset_outermost_narrowings (void);
|
||||
extern void init_editfns (void);
|
||||
extern void syms_of_editfns (void);
|
||||
|
||||
|
|
|
|||
34
src/xdisp.c
34
src/xdisp.c
|
|
@ -16266,40 +16266,6 @@ do { if (! polling_stopped_here) stop_polling (); \
|
|||
do { if (polling_stopped_here) start_polling (); \
|
||||
polling_stopped_here = false; } while (false)
|
||||
|
||||
static void
|
||||
unwind_reset_outermost_narrowing (Lisp_Object buf)
|
||||
{
|
||||
Lisp_Object innermost_narrowing =
|
||||
Fcar (buffer_local_value (Qnarrowing_locks, buf));
|
||||
if (! NILP (innermost_narrowing))
|
||||
{
|
||||
SET_BUF_BEGV (XBUFFER (buf),
|
||||
XFIXNUM (Fcar (Fcdr (innermost_narrowing))));
|
||||
SET_BUF_ZV (XBUFFER (buf),
|
||||
XFIXNUM (Fcdr (Fcdr (innermost_narrowing))));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
reset_outermost_narrowings (void)
|
||||
{
|
||||
Lisp_Object tail, buf, outermost_narrowing;
|
||||
FOR_EACH_LIVE_BUFFER (tail, buf)
|
||||
{
|
||||
outermost_narrowing =
|
||||
Fassq (Qoutermost_narrowing,
|
||||
buffer_local_value (Qnarrowing_locks, buf));
|
||||
if (!NILP (outermost_narrowing))
|
||||
{
|
||||
SET_BUF_BEGV (XBUFFER (buf),
|
||||
XFIXNUM (Fcar (Fcdr (outermost_narrowing))));
|
||||
SET_BUF_ZV (XBUFFER (buf),
|
||||
XFIXNUM (Fcdr (Fcdr (outermost_narrowing))));
|
||||
record_unwind_protect (unwind_reset_outermost_narrowing, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Perhaps in the future avoid recentering windows if it
|
||||
is not necessary; currently that causes some problems. */
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue