aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGregory Heytings2022-11-25 17:51:01 +0000
committerGregory Heytings2022-11-25 18:51:39 +0100
commit9dee6df39cd14be78ff96cb24169842f4772488a (patch)
tree6f9ffed71e3684ac7a7f6a76025363ec4fa668ff
parentba9315b1641b483f2bf843c38dcdba0cd1643a55 (diff)
downloademacs-9dee6df39cd14be78ff96cb24169842f4772488a.tar.gz
emacs-9dee6df39cd14be78ff96cb24169842f4772488a.zip
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.
-rw-r--r--lisp/subr.el19
-rw-r--r--src/editfns.c212
-rw-r--r--src/lisp.h1
-rw-r--r--src/xdisp.c34
4 files changed, 179 insertions, 87 deletions
diff --git a/lisp/subr.el b/lisp/subr.el
index 7dd8ff2081b..196e7f881b6 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -3943,14 +3943,17 @@ within the START and END limits, unless the restrictions are
3943unlocked by calling `narrowing-unlock' with TAG. See 3943unlocked by calling `narrowing-unlock' with TAG. See
3944`narrowing-lock' for a more detailed description. The current 3944`narrowing-lock' for a more detailed description. The current
3945restrictions, if any, are restored upon return." 3945restrictions, if any, are restored upon return."
3946 `(save-restriction 3946 `(with-locked-narrowing-1 ,start ,end ,tag (lambda () ,@body)))
3947 (unwind-protect 3947
3948 (progn 3948(defun with-locked-narrowing-1 (start end tag body)
3949 (narrow-to-region ,start ,end) 3949 "Helper function for `with-locked-narrowing', which see."
3950 (narrowing-lock ,tag) 3950 (save-restriction
3951 ,@body) 3951 (unwind-protect
3952 (narrowing-unlock ,tag) 3952 (progn
3953 (widen)))) 3953 (narrow-to-region start end)
3954 (narrowing-lock tag)
3955 (funcall body))
3956 (narrowing-unlock tag))))
3954 3957
3955(defun find-tag-default-bounds () 3958(defun find-tag-default-bounds ()
3956 "Determine the boundaries of the default tag, based on text at point. 3959 "Determine the boundaries of the default tag, based on text at point.
diff --git a/src/editfns.c b/src/editfns.c
index c7cc63d8d3e..9c81d9c723f 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -2653,18 +2653,144 @@ DEFUN ("delete-and-extract-region", Fdelete_and_extract_region,
2653 return del_range_1 (XFIXNUM (start), XFIXNUM (end), 1, 1); 2653 return del_range_1 (XFIXNUM (start), XFIXNUM (end), 1, 1);
2654} 2654}
2655 2655
2656/* Alist of buffers in which locked narrowing is used. The car of
2657 each list element is a buffer, the cdr is a list of triplets (tag
2658 begv-marker zv-marker). The last element of that list always uses
2659 the (uninterned) Qoutermost_narrowing tag and records the narrowing
2660 bounds that were set by the user and that are visible on display.
2661 This alist is used internally by narrow-to-region, widen,
2662 narrowing-lock and narrowing-unlock. */
2663static Lisp_Object narrowing_locks;
2664
2665/* Retrieve one of the BEGV/ZV bounds of a narrowing in BUF from the
2666 narrowing_locks alist. When OUTERMOST is true, the bounds that
2667 were set by the user and that are visible on display are returned.
2668 Otherwise the innermost locked narrowing bounds are returned. */
2669static ptrdiff_t
2670narrowing_lock_get_bound (Lisp_Object buf, bool begv, bool outermost)
2671{
2672 if (NILP (Fbuffer_live_p (buf)))
2673 return 0;
2674 Lisp_Object buffer_locks = assq_no_quit (buf, narrowing_locks);
2675 if (NILP (buffer_locks))
2676 return 0;
2677 buffer_locks = Fcar (Fcdr (buffer_locks));
2678 Lisp_Object bounds
2679 = outermost
2680 ? Fcdr (assq_no_quit (Qoutermost_narrowing, buffer_locks))
2681 : Fcdr (Fcar (buffer_locks));
2682 eassert (! NILP (bounds));
2683 Lisp_Object marker = begv ? Fcar (bounds) : Fcar (Fcdr (bounds));
2684 eassert (MARKERP (marker));
2685 Lisp_Object pos = Fmarker_position (marker);
2686 eassert (! NILP (pos));
2687 return XFIXNUM (pos);
2688}
2689
2690/* Retrieve the tag of the innermost narrowing in BUF. */
2691static Lisp_Object
2692narrowing_lock_peek_tag (Lisp_Object buf)
2693{
2694 if (NILP (Fbuffer_live_p (buf)))
2695 return Qnil;
2696 Lisp_Object buffer_locks = assq_no_quit (buf, narrowing_locks);
2697 if (NILP (buffer_locks))
2698 return Qnil;
2699 Lisp_Object tag = Fcar (Fcar (Fcar (Fcdr (buffer_locks))));
2700 eassert (! NILP (tag));
2701 return tag;
2702}
2703
2704/* Add a LOCK in BUF in the narrowing_locks alist. */
2705static void
2706narrowing_lock_push (Lisp_Object buf, Lisp_Object lock)
2707{
2708 Lisp_Object buffer_locks = assq_no_quit (buf, narrowing_locks);
2709 if (NILP (buffer_locks))
2710 narrowing_locks = nconc2 (list1 (list2 (buf, list1 (lock))),
2711 narrowing_locks);
2712 else
2713 Fsetcdr (buffer_locks, list1 (nconc2 (list1 (lock),
2714 Fcar (Fcdr (buffer_locks)))));
2715}
2716
2717/* Remove the innermost lock in BUF from the narrowing_lock alist. */
2718static void
2719narrowing_lock_pop (Lisp_Object buf)
2720{
2721 Lisp_Object buffer_locks = assq_no_quit (buf, narrowing_locks);
2722 eassert (! NILP (buffer_locks));
2723 if (EQ (narrowing_lock_peek_tag (buf), Qoutermost_narrowing))
2724 narrowing_locks = Fdelq (Fassoc (buf, narrowing_locks, Qnil),
2725 narrowing_locks);
2726 else
2727 Fsetcdr (buffer_locks, list1 (Fcdr (Fcar (Fcdr (buffer_locks)))));
2728}
2729
2730static void
2731unwind_reset_outermost_narrowing (Lisp_Object buf)
2732{
2733 ptrdiff_t begv, zv;
2734 begv = narrowing_lock_get_bound (buf, true, false);
2735 zv = narrowing_lock_get_bound (buf, false, false);
2736 if (begv && zv)
2737 {
2738 SET_BUF_BEGV (XBUFFER (buf), begv);
2739 SET_BUF_ZV (XBUFFER (buf), zv);
2740 }
2741}
2742
2743/* When redisplay is called in a function executed while a locked
2744 narrowing is in effect, restore the narrowing bounds that were set
2745 by the user, and restore the bounds of the locked narrowing when
2746 returning from redisplay. */
2747void
2748reset_outermost_narrowings (void)
2749{
2750 Lisp_Object val, buf;
2751 for (val = narrowing_locks; CONSP (val); val = XCDR (val))
2752 {
2753 buf = Fcar (Fcar (val));
2754 eassert (BUFFERP (buf));
2755 ptrdiff_t begv = narrowing_lock_get_bound (buf, true, true);
2756 ptrdiff_t zv = narrowing_lock_get_bound (buf, false, true);
2757 SET_BUF_BEGV (XBUFFER (buf), begv);
2758 SET_BUF_ZV (XBUFFER (buf), zv);
2759 record_unwind_protect (unwind_reset_outermost_narrowing, buf);
2760 }
2761}
2762
2763static void
2764unwind_narrow_to_region_locked (Lisp_Object tag)
2765{
2766 Fnarrowing_unlock (tag);
2767 Fwiden ();
2768}
2769
2770/* Narrow current_buffer to BEGV-ZV with a locked narrowing */
2771void
2772narrow_to_region_locked (Lisp_Object begv, Lisp_Object zv, Lisp_Object tag)
2773{
2774 Fnarrow_to_region (begv, zv);
2775 Fnarrowing_lock (tag);
2776 record_unwind_protect (restore_point_unwind, Fpoint_marker ());
2777 record_unwind_protect (unwind_narrow_to_region_locked, tag);
2778}
2779
2656DEFUN ("widen", Fwiden, Swiden, 0, 0, "", 2780DEFUN ("widen", Fwiden, Swiden, 0, 0, "",
2657 doc: /* Remove restrictions (narrowing) from current buffer. 2781 doc: /* Remove restrictions (narrowing) from current buffer.
2658 2782
2659This allows the buffer's full text to be seen and edited, unless 2783This allows the buffer's full text to be seen and edited, unless
2660restrictions have been locked with `narrowing-lock', which see, in 2784restrictions have been locked with `narrowing-lock', which see, in
2661which case the restrictions that were current when `narrowing-lock' 2785which case the narrowing that was current when `narrowing-lock' was
2662was called are restored. */) 2786called is restored. */)
2663 (void) 2787 (void)
2664{ 2788{
2665 Fset (Qoutermost_narrowing, Qnil); 2789 Fset (Qoutermost_narrowing, Qnil);
2790 Lisp_Object buf = Fcurrent_buffer ();
2791 Lisp_Object tag = narrowing_lock_peek_tag (buf);
2666 2792
2667 if (NILP (Vnarrowing_locks)) 2793 if (NILP (tag))
2668 { 2794 {
2669 if (BEG != BEGV || Z != ZV) 2795 if (BEG != BEGV || Z != ZV)
2670 current_buffer->clip_changed = 1; 2796 current_buffer->clip_changed = 1;
@@ -2674,14 +2800,18 @@ was called are restored. */)
2674 } 2800 }
2675 else 2801 else
2676 { 2802 {
2677 ptrdiff_t begv = XFIXNUM (Fcar (Fcdr (Fcar (Vnarrowing_locks)))); 2803 ptrdiff_t begv = narrowing_lock_get_bound (buf, true, false);
2678 ptrdiff_t zv = XFIXNUM (Fcdr (Fcdr (Fcar (Vnarrowing_locks)))); 2804 ptrdiff_t zv = narrowing_lock_get_bound (buf, false, false);
2679 if (begv != BEGV || zv != ZV) 2805 if (begv != BEGV || zv != ZV)
2680 current_buffer->clip_changed = 1; 2806 current_buffer->clip_changed = 1;
2681 SET_BUF_BEGV (current_buffer, begv); 2807 SET_BUF_BEGV (current_buffer, begv);
2682 SET_BUF_ZV (current_buffer, zv); 2808 SET_BUF_ZV (current_buffer, zv);
2683 if (EQ (Fcar (Fcar (Vnarrowing_locks)), Qoutermost_narrowing)) 2809 /* If the only remaining bounds in narrowing_locks for
2684 Fset (Qnarrowing_locks, Qnil); 2810 current_buffer are the bounds that were set by the user, no
2811 locked narrowing is in effect in current_buffer anymore:
2812 remove it from the narrowing_locks alist. */
2813 if (EQ (tag, Qoutermost_narrowing))
2814 narrowing_lock_pop (buf);
2685 } 2815 }
2686 /* Changing the buffer bounds invalidates any recorded current column. */ 2816 /* Changing the buffer bounds invalidates any recorded current column. */
2687 invalidate_current_column (); 2817 invalidate_current_column ();
@@ -2716,20 +2846,25 @@ limit of the locked restriction is used instead of the argument. */)
2716 if (!(BEG <= s && s <= e && e <= Z)) 2846 if (!(BEG <= s && s <= e && e <= Z))
2717 args_out_of_range (start, end); 2847 args_out_of_range (start, end);
2718 2848
2719 if (! NILP (Vnarrowing_locks)) 2849 Lisp_Object buf = Fcurrent_buffer ();
2850 if (! NILP (narrowing_lock_peek_tag (buf)))
2720 { 2851 {
2721 ptrdiff_t begv = XFIXNUM (Fcar (Fcdr (Fcar (Vnarrowing_locks)))); 2852 ptrdiff_t begv = narrowing_lock_get_bound (buf, true, false);
2722 ptrdiff_t zv = XFIXNUM (Fcdr (Fcdr (Fcar (Vnarrowing_locks)))); 2853 ptrdiff_t zv = narrowing_lock_get_bound (buf, false, false);
2854 /* Limit the start and end positions to those of the locked
2855 narrowing. */
2723 if (s < begv) s = begv; 2856 if (s < begv) s = begv;
2724 if (s > zv) s = zv; 2857 if (s > zv) s = zv;
2725 if (e < begv) e = begv; 2858 if (e < begv) e = begv;
2726 if (e > zv) e = zv; 2859 if (e > zv) e = zv;
2727 } 2860 }
2728 2861
2729 Fset (Qoutermost_narrowing, 2862 /* Record the accessible range of the buffer when narrow-to-region
2730 Fcons (Fcons (Qoutermost_narrowing, 2863 is called, that is, before applying the narrowing. It is used
2731 Fcons (make_fixnum (BEGV), make_fixnum (ZV))), 2864 only by narrowing-lock. */
2732 Qnil)); 2865 Fset (Qoutermost_narrowing, list3 (Qoutermost_narrowing,
2866 Fpoint_min_marker (),
2867 Fpoint_max_marker ()));
2733 2868
2734 if (BEGV != s || ZV != e) 2869 if (BEGV != s || ZV != e)
2735 current_buffer->clip_changed = 1; 2870 current_buffer->clip_changed = 1;
@@ -2766,11 +2901,18 @@ Locked restrictions are never visible on display, and can therefore
2766not be used as a stronger variant of normal restrictions. */) 2901not be used as a stronger variant of normal restrictions. */)
2767 (Lisp_Object tag) 2902 (Lisp_Object tag)
2768{ 2903{
2769 if (NILP (Vnarrowing_locks)) 2904 Lisp_Object buf = Fcurrent_buffer ();
2770 Fset (Qnarrowing_locks, Voutermost_narrowing); 2905 Lisp_Object outermost_narrowing
2771 Fset (Qnarrowing_locks, 2906 = buffer_local_value (Qoutermost_narrowing, buf);
2772 Fcons (Fcons (tag, Fcons (make_fixnum (BEGV), make_fixnum (ZV))), 2907 /* If narrowing-lock is called without being preceded by
2773 Vnarrowing_locks)); 2908 narrow-to-region, do nothing. */
2909 if (NILP (outermost_narrowing))
2910 return Qnil;
2911 if (NILP (narrowing_lock_peek_tag (buf)))
2912 narrowing_lock_push (buf, outermost_narrowing);
2913 narrowing_lock_push (buf, list3 (tag,
2914 Fpoint_min_marker (),
2915 Fpoint_max_marker ()));
2774 return Qnil; 2916 return Qnil;
2775} 2917}
2776 2918
@@ -2786,27 +2928,12 @@ by Emacs around low-level hooks such as `fontification-functions' or
2786`post-command-hook'. */) 2928`post-command-hook'. */)
2787 (Lisp_Object tag) 2929 (Lisp_Object tag)
2788{ 2930{
2789 if (EQ (Fcar (Fcar (Vnarrowing_locks)), tag)) 2931 Lisp_Object buf = Fcurrent_buffer ();
2790 Fset (Qnarrowing_locks, Fcdr (Vnarrowing_locks)); 2932 if (EQ (narrowing_lock_peek_tag (buf), tag))
2933 narrowing_lock_pop (buf);
2791 return Qnil; 2934 return Qnil;
2792} 2935}
2793 2936
2794static void
2795unwind_narrow_to_region_locked (Lisp_Object tag)
2796{
2797 Fnarrowing_unlock (tag);
2798 Fwiden ();
2799}
2800
2801void
2802narrow_to_region_locked (Lisp_Object begv, Lisp_Object zv, Lisp_Object tag)
2803{
2804 Fnarrow_to_region (begv, zv);
2805 Fnarrowing_lock (tag);
2806 record_unwind_protect (restore_point_unwind, Fpoint_marker ());
2807 record_unwind_protect (unwind_narrow_to_region_locked, tag);
2808}
2809
2810Lisp_Object 2937Lisp_Object
2811save_restriction_save (void) 2938save_restriction_save (void)
2812{ 2939{
@@ -4564,6 +4691,8 @@ syms_of_editfns (void)
4564 DEFSYM (Qwall, "wall"); 4691 DEFSYM (Qwall, "wall");
4565 DEFSYM (Qpropertize, "propertize"); 4692 DEFSYM (Qpropertize, "propertize");
4566 4693
4694 staticpro (&narrowing_locks);
4695
4567 DEFVAR_LISP ("inhibit-field-text-motion", Vinhibit_field_text_motion, 4696 DEFVAR_LISP ("inhibit-field-text-motion", Vinhibit_field_text_motion,
4568 doc: /* Non-nil means text motion commands don't notice fields. */); 4697 doc: /* Non-nil means text motion commands don't notice fields. */);
4569 Vinhibit_field_text_motion = Qnil; 4698 Vinhibit_field_text_motion = Qnil;
@@ -4623,18 +4752,11 @@ This variable is experimental; email 32252@debbugs.gnu.org if you need
4623it to be non-nil. */); 4752it to be non-nil. */);
4624 binary_as_unsigned = false; 4753 binary_as_unsigned = false;
4625 4754
4626 DEFSYM (Qnarrowing_locks, "narrowing-locks");
4627 DEFVAR_LISP ("narrowing-locks", Vnarrowing_locks,
4628 doc: /* List of narrowing locks in the current buffer. Internal use only. */);
4629 Vnarrowing_locks = Qnil;
4630 Fmake_variable_buffer_local (Qnarrowing_locks);
4631 Funintern (Qnarrowing_locks, Qnil);
4632
4633 DEFSYM (Qoutermost_narrowing, "outermost-narrowing");
4634 DEFVAR_LISP ("outermost-narrowing", Voutermost_narrowing, 4755 DEFVAR_LISP ("outermost-narrowing", Voutermost_narrowing,
4635 doc: /* Outermost narrowing bounds, if any. Internal use only. */); 4756 doc: /* Outermost narrowing bounds, if any. Internal use only. */);
4636 Voutermost_narrowing = Qnil; 4757 Voutermost_narrowing = Qnil;
4637 Fmake_variable_buffer_local (Qoutermost_narrowing); 4758 Fmake_variable_buffer_local (Qoutermost_narrowing);
4759 DEFSYM (Qoutermost_narrowing, "outermost-narrowing");
4638 Funintern (Qoutermost_narrowing, Qnil); 4760 Funintern (Qoutermost_narrowing, Qnil);
4639 4761
4640 defsubr (&Spropertize); 4762 defsubr (&Spropertize);
diff --git a/src/lisp.h b/src/lisp.h
index 8a5b8dad831..373aee2287d 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4683,6 +4683,7 @@ extern Lisp_Object make_buffer_string (ptrdiff_t, ptrdiff_t, bool);
4683extern Lisp_Object make_buffer_string_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, 4683extern Lisp_Object make_buffer_string_both (ptrdiff_t, ptrdiff_t, ptrdiff_t,
4684 ptrdiff_t, bool); 4684 ptrdiff_t, bool);
4685extern void narrow_to_region_locked (Lisp_Object, Lisp_Object, Lisp_Object); 4685extern void narrow_to_region_locked (Lisp_Object, Lisp_Object, Lisp_Object);
4686extern void reset_outermost_narrowings (void);
4686extern void init_editfns (void); 4687extern void init_editfns (void);
4687extern void syms_of_editfns (void); 4688extern void syms_of_editfns (void);
4688 4689
diff --git a/src/xdisp.c b/src/xdisp.c
index fa5ce84b1c4..658ce57b7ea 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -16266,40 +16266,6 @@ do { if (! polling_stopped_here) stop_polling (); \
16266do { if (polling_stopped_here) start_polling (); \ 16266do { if (polling_stopped_here) start_polling (); \
16267 polling_stopped_here = false; } while (false) 16267 polling_stopped_here = false; } while (false)
16268 16268
16269static void
16270unwind_reset_outermost_narrowing (Lisp_Object buf)
16271{
16272 Lisp_Object innermost_narrowing =
16273 Fcar (buffer_local_value (Qnarrowing_locks, buf));
16274 if (! NILP (innermost_narrowing))
16275 {
16276 SET_BUF_BEGV (XBUFFER (buf),
16277 XFIXNUM (Fcar (Fcdr (innermost_narrowing))));
16278 SET_BUF_ZV (XBUFFER (buf),
16279 XFIXNUM (Fcdr (Fcdr (innermost_narrowing))));
16280 }
16281}
16282
16283static void
16284reset_outermost_narrowings (void)
16285{
16286 Lisp_Object tail, buf, outermost_narrowing;
16287 FOR_EACH_LIVE_BUFFER (tail, buf)
16288 {
16289 outermost_narrowing =
16290 Fassq (Qoutermost_narrowing,
16291 buffer_local_value (Qnarrowing_locks, buf));
16292 if (!NILP (outermost_narrowing))
16293 {
16294 SET_BUF_BEGV (XBUFFER (buf),
16295 XFIXNUM (Fcar (Fcdr (outermost_narrowing))));
16296 SET_BUF_ZV (XBUFFER (buf),
16297 XFIXNUM (Fcdr (Fcdr (outermost_narrowing))));
16298 record_unwind_protect (unwind_reset_outermost_narrowing, buf);
16299 }
16300 }
16301}
16302
16303/* Perhaps in the future avoid recentering windows if it 16269/* Perhaps in the future avoid recentering windows if it
16304 is not necessary; currently that causes some problems. */ 16270 is not necessary; currently that causes some problems. */
16305 16271