unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
@ 2022-01-16  5:13 Andrew Hyatt
  2022-01-16  9:22 ` Eli Zaretskii
  2022-02-16 17:41 ` Anders Johansson
  0 siblings, 2 replies; 18+ messages in thread
From: Andrew Hyatt @ 2022-01-16  5:13 UTC (permalink / raw)
  To: 53294

[-- Attachment #1: text-scale-patch --]
[-- Type: application/octet-stream, Size: 590 bytes --]

diff --git a/lisp/face-remap.el b/lisp/face-remap.el
index 00560f9d2e..df35d88933 100644
--- a/lisp/face-remap.el
+++ b/lisp/face-remap.el
@@ -134,6 +134,11 @@ face-remap-add-relative
     (let ((faces (cdr entry)))
       (if (symbolp faces)
 	  (setq faces (list faces)))
+      (setq face-remapping-alist
+	    (mapcar (lambda (kv)
+		      (if (eq (car kv) face)
+			  (cons face (face-remap-order (cons specs faces)))
+			kv)) face-remapping-alist))
       (setcdr entry (face-remap-order (cons specs faces)))
       ;; Force redisplay of this buffer.
       (force-mode-line-update))

[-- Attachment #2: Type: text/plain, Size: 2185 bytes --]


Hi all,

I noticed a bug recently where if I scale up fonts in an org 
capture buffer, it affects the original buffer, which keeps 
getting bigger and bigger every time org-capture is run.

However, you don't need org to reproduce this.  Here's a quick way 
to reproduce, which works with emacs -Q:

(require 'face-remap) (defun ash/big-font () 
  "Creates a font that is big enough for about 20 lines of text." 
  (interactive) (let ((text-scale-mode-amount (/ (frame-height) 
  20))) 
    (text-scale-mode 1))) 
 
(defun ash/reproduce-with-indirect-buffer () 
  (interactive) (let ((buf (get-buffer-create "*Orig buffer*"))) 
    (set-buffer buf) (variable-pitch-mode 1) ;; same way org mode 
    creates indirect buffer (set-buffer (make-indirect-buffer buf 
    "*Indirect buffer*" 'clone)) (ash/big-font-new) (kill-buffer 
    (current-buffer)))) 

Running ash/reproduce-with-indirect-buffer will increase the 
indirect buffer in size each time.  If you look at 
face-remapping-alist, it's clear that the original buffer's value 
is being altered by the indirect buffer.

I traced this down to the setcdr in face-remove-add-relative, 
which is incorrectly alterting a buffer local variable, by setting 
parts of a variable in a way that will affect the original 
variable.  Evidently making something buffer local doesn't clone 
it, it just copies the value, and so you can alter the original by 
operations such as setcdr. 

Assuming that the fixing how variables becomes buffer local is too 
much, I've fixed this in face-remap.el.  The patch is attached.

 
In GNU Emacs 29.0.50 (build 1, aarch64-apple-darwin21.2.0, NS 
appkit-2113.20 Version 12.1 (Build 21C52)) 
 of 2021-12-26 built on andrews-mbp.lan 
Repository revision: 978987f7ad58cd66fe51cefde53ba4771b189aeb 
Repository branch: master Windowing system distributor 'Apple', 
version 10.3.2113 System Description:  macOS 12.1
 
Configured using:
'configure --with-native-
Configured features:
ACL GLIB GNUTLS JSON LCMS2 LIBXML2 MODULES NATIVE_COMP NOTIFY 
KQUEUE NS
PDUMPER PNG RSVG SQLITE3 THREADS TOOLKIT_SCROLL_BARS XIM ZLIB
Important settings:
  value of $LANG: en_US.UTF-8
   
 locale-coding-system: utf-8-unix



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-16  5:13 bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer Andrew Hyatt
@ 2022-01-16  9:22 ` Eli Zaretskii
  2022-01-16 14:43   ` Andrew Hyatt
  2022-02-16 17:41 ` Anders Johansson
  1 sibling, 1 reply; 18+ messages in thread
From: Eli Zaretskii @ 2022-01-16  9:22 UTC (permalink / raw)
  To: Andrew Hyatt; +Cc: 53294

> From: Andrew Hyatt <ahyatt@gmail.com>
> Date: Sun, 16 Jan 2022 00:13:26 -0500
> 
> I noticed a bug recently where if I scale up fonts in an org 
> capture buffer, it affects the original buffer, which keeps 
> getting bigger and bigger every time org-capture is run.
> 
> However, you don't need org to reproduce this.  Here's a quick way 
> to reproduce, which works with emacs -Q:
> 
> (require 'face-remap) (defun ash/big-font () 
>   "Creates a font that is big enough for about 20 lines of text." 
>   (interactive) (let ((text-scale-mode-amount (/ (frame-height) 
>   20))) 
>     (text-scale-mode 1))) 
>  
> (defun ash/reproduce-with-indirect-buffer () 
>   (interactive) (let ((buf (get-buffer-create "*Orig buffer*"))) 
>     (set-buffer buf) (variable-pitch-mode 1) ;; same way org mode 
>     creates indirect buffer (set-buffer (make-indirect-buffer buf 
>     "*Indirect buffer*" 'clone)) (ash/big-font-new) (kill-buffer 
>     (current-buffer)))) 
> 
> Running ash/reproduce-with-indirect-buffer will increase the 
> indirect buffer in size each time.  If you look at 
> face-remapping-alist, it's clear that the original buffer's value 
> is being altered by the indirect buffer.

I don't think I understand what I should see and pay attention to with
this recipe (and it includes several errors that took me some time to
fix, before I could run it), but isn't this because you used non-nil
CLONE argument to make-indirect-buffer?





^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-16  9:22 ` Eli Zaretskii
@ 2022-01-16 14:43   ` Andrew Hyatt
  2022-01-16 15:00     ` Eli Zaretskii
  0 siblings, 1 reply; 18+ messages in thread
From: Andrew Hyatt @ 2022-01-16 14:43 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 53294


On Sun, Jan 16, 2022 at 11:22 AM Eli Zaretskii <eliz@gnu.org> 
wrote: 

>> From: Andrew Hyatt <ahyatt@gmail.com> Date: Sun, 16 Jan 2022 
>> 00:13:26 -0500  I noticed a bug recently where if I scale up 
>> fonts in an org  capture buffer, it affects the original 
>> buffer, which keeps  getting bigger and bigger every time 
>> org-capture is run.   However, you don't need org to reproduce 
>> this.  Here's a quick way  to reproduce, which works with emacs 
>> -Q:  (require 'face-remap) (defun ash/big-font ()  
>>   "Creates a font that is big enough for about 20 lines of 
>>   text."  (interactive) (let ((text-scale-mode-amount (/ 
>>   (frame-height)  20)))  
>>     (text-scale-mode 1)))  
>>   
>> (defun ash/reproduce-with-indirect-buffer ()  
>>   (interactive) (let ((buf (get-buffer-create "*Orig 
>>   buffer*")))  
>>     (set-buffer buf) (variable-pitch-mode 1) ;; same way org 
>>     mode  creates indirect buffer (set-buffer 
>>     (make-indirect-buffer buf  "*Indirect buffer*" 'clone)) 
>>     (ash/big-font-new) (kill-buffer  (current-buffer))))  
>>  Running ash/reproduce-with-indirect-buffer will increase the 
>> indirect buffer in size each time.  If you look at 
>> face-remapping-alist, it's clear that the original buffer's 
>> value  is being altered by the indirect buffer. 
> 
> I don't think I understand what I should see and pay attention 
> to with this recipe (and it includes several errors that took me 
> some time to fix, before I could run it), but isn't this because 
> you used non-nil CLONE argument to make-indirect-buffer? 


Sorry for any errors, I simplified it a bit before I sent it out 
and perhaps made a few mistakes. What you should see, if you go 
the *Orig Buffer*, is that the font scale keeps increasing. If you 
look at the face-remapping-alist of that buffer, it will be 
growing with duplicate height specs, one for every time you called 
the ash/reproduce-with-indirect-buffer.

Yes, the non-nil CLONE argument is essential to reproduce. But 
that just means the indirect buffer will inherit the state from 
the direct buffer.  It doesn't imply that changes made to the 
indirect buffer's state will affect the original buffer, which is 
what is happening here.





^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-16 14:43   ` Andrew Hyatt
@ 2022-01-16 15:00     ` Eli Zaretskii
  2022-01-16 15:28       ` Andrew Hyatt
  0 siblings, 1 reply; 18+ messages in thread
From: Eli Zaretskii @ 2022-01-16 15:00 UTC (permalink / raw)
  To: Andrew Hyatt, Stefan Monnier; +Cc: 53294

> From: Andrew Hyatt <ahyatt@gmail.com>
> Cc: 53294@debbugs.gnu.org
> Date: Sun, 16 Jan 2022 09:43:16 -0500
> 
> Yes, the non-nil CLONE argument is essential to reproduce. But 
> that just means the indirect buffer will inherit the state from 
> the direct buffer.  It doesn't imply that changes made to the 
> indirect buffer's state will affect the original buffer, which is 
> what is happening here.

But "inheriting" the state means the indirect buffer gets the copy of
the variables of the original buffer, and that is not a deep copy,
AFAIU.

Stefan, any comments on this issue?





^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-16 15:00     ` Eli Zaretskii
@ 2022-01-16 15:28       ` Andrew Hyatt
  2022-01-16 15:41         ` Eli Zaretskii
  0 siblings, 1 reply; 18+ messages in thread
From: Andrew Hyatt @ 2022-01-16 15:28 UTC (permalink / raw)
  To: Eli Zaretskii, Stefan Monnier; +Cc: 53294

On Sun, Jan 16, 2022 at 05:00 PM Eli Zaretskii <eliz@gnu.org> 
wrote: 

>> From: Andrew Hyatt <ahyatt@gmail.com> Cc: 53294@debbugs.gnu.org 
>> Date: Sun, 16 Jan 2022 09:43:16 -0500  Yes, the non-nil CLONE 
>> argument is essential to reproduce. But  that just means the 
>> indirect buffer will inherit the state from  the direct buffer. 
>> It doesn't imply that changes made to the  indirect buffer's 
>> state will affect the original buffer, which is  what is 
>> happening here. 
> 
> But "inheriting" the state means the indirect buffer gets the 
> copy of the variables of the original buffer, and that is not a 
> deep copy, AFAIU. 
> 
> Stefan, any comments on this issue? 

Sorry, I may have been unclear. I'm not disagreeing - what you 
just said is correct. But, because of that, it's a bug for code to 
make an indirect buffer, then perform operations on it via setcdr 
or setf like things, which then will affect the original buffer's 
variables.

Alternatively, it'd perhaps would be a better fix to make the 
indirect buffer's copy a deep copy instead of the shallow copy it 
is now, so that these situations don't arise. I don't have a patch 
for that, though, but could create one if you thought it was a 
good idea.






^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-16 15:28       ` Andrew Hyatt
@ 2022-01-16 15:41         ` Eli Zaretskii
  2022-01-16 17:11           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 18+ messages in thread
From: Eli Zaretskii @ 2022-01-16 15:41 UTC (permalink / raw)
  To: Andrew Hyatt; +Cc: 53294, monnier

> From: Andrew Hyatt <ahyatt@gmail.com>
> Cc: 53294@debbugs.gnu.org
> Date: Sun, 16 Jan 2022 10:28:40 -0500
> 
> > But "inheriting" the state means the indirect buffer gets the 
> > copy of the variables of the original buffer, and that is not a 
> > deep copy, AFAIU. 
> > 
> > Stefan, any comments on this issue? 
> 
> Sorry, I may have been unclear. I'm not disagreeing - what you 
> just said is correct. But, because of that, it's a bug for code to 
> make an indirect buffer, then perform operations on it via setcdr 
> or setf like things, which then will affect the original buffer's 
> variables.

I'm not sure it's a bug.  It could be a "feature", not limited to
face-remapping-alist, but instead affecting every buffer-local
variable that is not a simple scalar.





^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-16 15:41         ` Eli Zaretskii
@ 2022-01-16 17:11           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-01-16 18:16             ` Eli Zaretskii
  0 siblings, 1 reply; 18+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-01-16 17:11 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Andrew Hyatt, 53294

>> > But "inheriting" the state means the indirect buffer gets the 
>> > copy of the variables of the original buffer, and that is not a 
>> > deep copy, AFAIU. 
>> > Stefan, any comments on this issue? 
>> Sorry, I may have been unclear. I'm not disagreeing - what you 
>> just said is correct. But, because of that, it's a bug for code to 
>> make an indirect buffer, then perform operations on it via setcdr 
>> or setf like things, which then will affect the original buffer's 
>> variables.
> I'm not sure it's a bug.  It could be a "feature", not limited to
> face-remapping-alist, but instead affecting every buffer-local
> variable that is not a simple scalar.

`make-indirect-buffer` can't do the right thing, indeed, because
different variables need different handling.  `clone-buffer` tries to
handle these issues by relying on `clone-buffer-hook` to handle the
various variables on a case-by-case basis, but `make-indirect-buffer`
doesn't come with such a hook.

Some ways we can fix this:

- In `face-remap.el`, refrain from modifying the `face-remapping-alist`
  by side-effects (i.e. avoid `delq`, `setcdr`, and friends).

- Add a `make-indirect-buffer-hook` and arrange for `face-remap.el` to
  add a function there that does a deep enough copy of
  `face-remapping-alist`.

- Remember that indirect buffers are an attractive nuisance and should
  be deprecated (but note that I suspect the same bug affects
  `clone-buffer` because it doesn't make a deep enough copy of
  `face-remapping-alist` either).


        Stefan






^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-16 17:11           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-01-16 18:16             ` Eli Zaretskii
  2022-01-16 21:41               ` Andrew Hyatt
  2022-01-17 21:47               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 18+ messages in thread
From: Eli Zaretskii @ 2022-01-16 18:16 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: ahyatt, 53294

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Andrew Hyatt <ahyatt@gmail.com>,  53294@debbugs.gnu.org
> Date: Sun, 16 Jan 2022 12:11:39 -0500
> 
> Some ways we can fix this:
> 
> - In `face-remap.el`, refrain from modifying the `face-remapping-alist`
>   by side-effects (i.e. avoid `delq`, `setcdr`, and friends).
> 
> - Add a `make-indirect-buffer-hook` and arrange for `face-remap.el` to
>   add a function there that does a deep enough copy of
>   `face-remapping-alist`.
> 
> - Remember that indirect buffers are an attractive nuisance and should
>   be deprecated (but note that I suspect the same bug affects
>   `clone-buffer` because it doesn't make a deep enough copy of
>   `face-remapping-alist` either).

The last one tells me we are better with leaving this sleeping dog
lie.





^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-16 18:16             ` Eli Zaretskii
@ 2022-01-16 21:41               ` Andrew Hyatt
  2022-01-17 21:47               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 18+ messages in thread
From: Andrew Hyatt @ 2022-01-16 21:41 UTC (permalink / raw)
  To: Eli Zaretskii, Stefan Monnier; +Cc: 53294

On Sun, Jan 16, 2022 at 08:16 PM Eli Zaretskii <eliz@gnu.org> 
wrote: 

>> From: Stefan Monnier <monnier@iro.umontreal.ca> Cc: Andrew 
>> Hyatt <ahyatt@gmail.com>,  53294@debbugs.gnu.org Date: Sun, 16 
>> Jan 2022 12:11:39 -0500  Some ways we can fix this:  - In 
>> `face-remap.el`, refrain from modifying the 
>> `face-remapping-alist` 
>>   by side-effects (i.e. avoid `delq`, `setcdr`, and friends). 
>>  - Add a `make-indirect-buffer-hook` and arrange for 
>> `face-remap.el` to 
>>   add a function there that does a deep enough copy of 
>>   `face-remapping-alist`. 
>>  - Remember that indirect buffers are an attractive nuisance 
>> and should 
>>   be deprecated (but note that I suspect the same bug affects 
>>   `clone-buffer` because it doesn't make a deep enough copy of 
>>   `face-remapping-alist` either). 
> 
> The last one tells me we are better with leaving this sleeping 
> dog lie. 

I agree the use of indirect buffers is problematic, but this 
problem actually results in user-visible bugs. Anyone who likes 
their org-mode buffer to be variable-pitch, and likes their 
capture buffer to be in a larger font (both pretty reasonable 
things), will run into this problem.

My patch fixes this in a way whose only downside is that it would 
be less efficient notably when you have a lot of face-remappings. 
But it's not clear to me that face-remapping-alist ever gets so 
big or is changed so often that this would be a problem.

The only other option is to fix this in org-mode, but they are 
cloning their indirect buffer presumably so that the capture 
buffer looks and behaves like the parent buffer, which is 
reasonable. I'd have to break that, or maybe just add a hack to 
deep copy face-remapping-alist.  Both options seem a bit wrong.





^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-16 18:16             ` Eli Zaretskii
  2022-01-16 21:41               ` Andrew Hyatt
@ 2022-01-17 21:47               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-01-18  2:24                 ` Andrew Hyatt
  1 sibling, 1 reply; 18+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-01-17 21:47 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: ahyatt, 53294

>> - In `face-remap.el`, refrain from modifying the `face-remapping-alist`
>>   by side-effects (i.e. avoid `delq`, `setcdr`, and friends).
>> 
>> - Add a `make-indirect-buffer-hook` and arrange for `face-remap.el` to
>>   add a function there that does a deep enough copy of
>>   `face-remapping-alist`.
>> 
>> - Remember that indirect buffers are an attractive nuisance and should
>>   be deprecated (but note that I suspect the same bug affects
>>   `clone-buffer` because it doesn't make a deep enough copy of
>>   `face-remapping-alist` either).
>
> The last one tells me we are better with leaving this sleeping dog
> lie.

Actually, looking back at the code, I see we already have the needed
hook (tho called from `clone-indirect-buffer`), so I think the better
option is to change `make-indirect-buffer` so it runs
`clone-indirect-buffer-hook` (when called with a non-nil `clone` arg)
instead of having `clone-indirect-buffer` run it.  And then in
`face-remap.el` add a function to that hook which copies
`face-remapping-alist`.

An intermediate option is to change the Org code to use
`clone-indirect-buffer` instead of `make-indirect-buffer` (but that
still requires the `face-remap.el` addition to the hook).

[ Sorry Andrew for not noticing your earlier patch which does something
  similar to my first suggestion above.  ]

Andrew, would you be willing to write that patch?


        Stefan






^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-17 21:47               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-01-18  2:24                 ` Andrew Hyatt
  2022-01-18  2:47                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 18+ messages in thread
From: Andrew Hyatt @ 2022-01-18  2:24 UTC (permalink / raw)
  To: Stefan Monnier, Eli Zaretskii; +Cc: 53294

[-- Attachment #1: Type: text/plain, Size: 2090 bytes --]

On Mon, Jan 17, 2022 at 04:47 PM Stefan Monnier 
<monnier@iro.umontreal.ca> wrote: 

>>> - In `face-remap.el`, refrain from modifying the 
>>> `face-remapping-alist` 
>>>   by side-effects (i.e. avoid `delq`, `setcdr`, and friends). 
>>>  - Add a `make-indirect-buffer-hook` and arrange for 
>>> `face-remap.el` to 
>>>   add a function there that does a deep enough copy of 
>>>   `face-remapping-alist`. 
>>>  - Remember that indirect buffers are an attractive nuisance 
>>> and should 
>>>   be deprecated (but note that I suspect the same bug affects 
>>>   `clone-buffer` because it doesn't make a deep enough copy of 
>>>   `face-remapping-alist` either). 
>> 
>> The last one tells me we are better with leaving this sleeping 
>> dog lie. 
> 
> Actually, looking back at the code, I see we already have the 
> needed hook (tho called from `clone-indirect-buffer`), so I 
> think the better option is to change `make-indirect-buffer` so 
> it runs `clone-indirect-buffer-hook` (when called with a non-nil 
> `clone` arg) instead of having `clone-indirect-buffer` run it. 
> And then in `face-remap.el` add a function to that hook which 
> copies `face-remapping-alist`. 
> 
> An intermediate option is to change the Org code to use 
> `clone-indirect-buffer` instead of `make-indirect-buffer` (but 
> that still requires the `face-remap.el` addition to the hook). 
> 
> [ Sorry Andrew for not noticing your earlier patch which does 
> something 
>   similar to my first suggestion above.  ] 
> 
> Andrew, would you be willing to write that patch?
>  
>         Stefan 

That sounds reasonable, I can do that. In fact, I just did this 
based on your suggestions, and it does work well. The only weird 
thing is that I had to pull `clone-indirect-buffer-hook' into the 
c code, because that's where `make-indirect-buffer' is. Let me 
know if that seems wrong.

I've attached the patch, please let me know if there is an issue. 
I have commit access, so I can just commit it myself after your OK 
(if so, I'll wait for a week or so to see if Eli has a comment as 
well before checkin).


[-- Attachment #2: text-scale-patch-v2 --]
[-- Type: application/octet-stream, Size: 2895 bytes --]

diff --git a/lisp/face-remap.el b/lisp/face-remap.el
index 00560f9d2e..fc0edb7119 100644
--- a/lisp/face-remap.el
+++ b/lisp/face-remap.el
@@ -70,6 +70,14 @@ internal-lisp-face-attributes
    :foreground :background :stipple :overline :strike-through :box
    :font :inherit :fontset :distant-foreground :extend :vector])
 
+(defun face-attrs--make-indirect-safe ()
+  "Do a deep copy of `face-remapping-alist' to keep the original buffer safe."
+  (setq-local face-remapping-alist
+              (copy-tree
+               (buffer-local-value 'face-remapping-alist (buffer-base-buffer)))))
+
+(add-hook 'clone-indirect-buffer-hook #'face-attrs--make-indirect-safe)
+
 (defun face-attrs-more-relative-p (attrs1 attrs2)
   "Return true if ATTRS1 contains a greater number of relative
 face-attributes than ATTRS2.  A face attribute is considered
diff --git a/lisp/simple.el b/lisp/simple.el
index cbcde9fb8d..3ef9cca249 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -9441,9 +9441,6 @@ function-key-map
 (defvar clone-buffer-hook nil
   "Normal hook to run in the new buffer at the end of `clone-buffer'.")
 
-(defvar clone-indirect-buffer-hook nil
-  "Normal hook to run in the new buffer at the end of `clone-indirect-buffer'.")
-
 (defun clone-process (process &optional newname)
   "Create a twin copy of PROCESS.
 If NEWNAME is nil, it defaults to PROCESS' name;
diff --git a/src/buffer.c b/src/buffer.c
index 10ac91915c..00646f8779 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -912,6 +912,10 @@ DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer,
       Fset (intern ("buffer-save-without-query"), Qnil);
       Fset (intern ("buffer-file-number"), Qnil);
       Fset (intern ("buffer-stale-function"), Qnil);
+      /* Cloned buffers need extra setup, to do things such as deep
+	 variable copies for list variables that might be mangled due
+	 to destructive operations in the indirect buffer. */
+      safe_run_hooks (Qclone_indirect_buffer_hook);
       set_buffer_internal_1 (old_b);
     }
 
@@ -5568,6 +5572,9 @@ syms_of_buffer (void)
 	pure_list (Qprotected_field, Qerror));
   Fput (Qprotected_field, Qerror_message,
 	build_pure_c_string ("Attempt to modify a protected field"));
+  
+  DEFSYM (Qclone_indirect_buffer_hook, "clone-indirect-buffer-hook");
+ 
 
   DEFVAR_PER_BUFFER ("tab-line-format",
 		     &BVAR (current_buffer, tab_line_format),
@@ -6392,6 +6399,10 @@ Functions (implicitly) running this hook are `get-buffer-create',
 This is the default.  If nil, auto-save file deletion is inhibited.  */);
   delete_auto_save_files = 1;
 
+  DEFVAR_LISP ("clone-indirect-buffer-hook", Vclone_indirect_buffer_hook,
+	       doc: /* Normal hook to run in the new buffer at the end of `clone-indirect-buffer'. */);
+  Vclone_indirect_buffer_hook = Qnil;
+
   defsubr (&Sbuffer_live_p);
   defsubr (&Sbuffer_list);
   defsubr (&Sget_buffer);

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-18  2:24                 ` Andrew Hyatt
@ 2022-01-18  2:47                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-01-19  2:37                     ` Andrew Hyatt
  0 siblings, 1 reply; 18+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-01-18  2:47 UTC (permalink / raw)
  To: Andrew Hyatt; +Cc: Eli Zaretskii, 53294

> That sounds reasonable, I can do that. In fact, I just did this based on
> your suggestions, and it does work well.  The only weird thing is that I had
> to pull `clone-indirect-buffer-hook' into the c code, because that's where
> `make-indirect-buffer' is.

You could leave the `defvar` in Lisp and only pull the DEFSYM, but
yes, you need to pull at least part of it into C.

> Let me know if that seems wrong.

Nope.

> I've attached the patch, please let me know if there is an issue. I have
> commit access, so I can just commit it myself after your OK (if so, I'll
> wait for a week or so to see if Eli has a comment as well before checkin).

Comments below, thanks,


        Stefan


> diff --git a/lisp/face-remap.el b/lisp/face-remap.el
> index 00560f9d2e..fc0edb7119 100644
> --- a/lisp/face-remap.el
> +++ b/lisp/face-remap.el
> @@ -70,6 +70,14 @@ internal-lisp-face-attributes
>     :foreground :background :stipple :overline :strike-through :box
>     :font :inherit :fontset :distant-foreground :extend :vector])
>  
> +(defun face-attrs--make-indirect-safe ()
> +  "Do a deep copy of `face-remapping-alist' to keep the original buffer safe."
> +  (setq-local face-remapping-alist
> +              (copy-tree
> +               (buffer-local-value 'face-remapping-alist (buffer-base-buffer)))))

I think `mapcar #'copy-sequence` is slightly more correct than
`copy-tree`, and you shouldn't need
(buffer-local-value 'face-remapping-alist (buffer-base-buffer)) because
that buffer's value should already have been copied to the current buffer.

> @@ -912,6 +912,10 @@ DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer,
>        Fset (intern ("buffer-save-without-query"), Qnil);
>        Fset (intern ("buffer-file-number"), Qnil);
>        Fset (intern ("buffer-stale-function"), Qnil);
> +      /* Cloned buffers need extra setup, to do things such as deep
> +	 variable copies for list variables that might be mangled due
> +	 to destructive operations in the indirect buffer. */
> +      safe_run_hooks (Qclone_indirect_buffer_hook);

I think you want to use just `run_hook` here because there's no need to
catch errors.

More importantly, you need to remove the corresponding `run-hook` from
`clone-indirect-buffer`.


        Stefan






^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-18  2:47                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-01-19  2:37                     ` Andrew Hyatt
  2022-01-19  3:42                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 18+ messages in thread
From: Andrew Hyatt @ 2022-01-19  2:37 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 53294

[-- Attachment #1: Type: text/plain, Size: 2568 bytes --]

On Mon, Jan 17, 2022 at 09:47 PM Stefan Monnier 
<monnier@iro.umontreal.ca> wrote: 

>> That sounds reasonable, I can do that. In fact, I just did this 
>> based on your suggestions, and it does work well.  The only 
>> weird thing is that I had to pull `clone-indirect-buffer-hook' 
>> into the c code, because that's where `make-indirect-buffer' 
>> is. 
> 
> You could leave the `defvar` in Lisp and only pull the DEFSYM, 
> but yes, you need to pull at least part of it into C. 
> 
>> Let me know if that seems wrong. 
> 
> Nope. 
> 
>> I've attached the patch, please let me know if there is an 
>> issue. I have commit access, so I can just commit it myself 
>> after your OK (if so, I'll wait for a week or so to see if Eli 
>> has a comment as well before checkin). 
> 
> Comments below, thanks, 
>  
>         Stefan 
>  
>> diff --git a/lisp/face-remap.el b/lisp/face-remap.el index 
>> 00560f9d2e..fc0edb7119 100644 --- a/lisp/face-remap.el +++ 
>> b/lisp/face-remap.el @@ -70,6 +70,14 @@ 
>> internal-lisp-face-attributes 
>>     :foreground :background :stipple :overline :strike-through 
>>     :box :font :inherit :fontset :distant-foreground :extend 
>>     :vector]) 
>>   
>> +(defun face-attrs--make-indirect-safe () +  "Do a deep copy of 
>> `face-remapping-alist' to keep the original buffer safe."  + 
>> (setq-local face-remapping-alist +              (copy-tree + 
>> (buffer-local-value 'face-remapping-alist 
>> (buffer-base-buffer))))) 
> 
> I think `mapcar #'copy-sequence` is slightly more correct than 
> `copy-tree`, and you shouldn't need (buffer-local-value 
> 'face-remapping-alist (buffer-base-buffer)) because that 
> buffer's value should already have been copied to the current 
> buffer. 
> 
>> @@ -912,6 +912,10 @@ DEFUN ("make-indirect-buffer", 
>> Fmake_indirect_buffer, Smake_indirect_buffer, 
>>        Fset (intern ("buffer-save-without-query"), Qnil); Fset 
>>        (intern ("buffer-file-number"), Qnil); Fset (intern 
>>        ("buffer-stale-function"), Qnil); 
>> +      /* Cloned buffers need extra setup, to do things such as 
>> deep +	 variable copies for list variables that might be 
>> mangled due +	 to destructive operations in the indirect 
>> buffer. */ +      safe_run_hooks (Qclone_indirect_buffer_hook); 
> 
> I think you want to use just `run_hook` here because there's no 
> need to catch errors. 
> 
> More importantly, you need to remove the corresponding 
> `run-hook` from `clone-indirect-buffer`. 
>  
>         Stefan

Makes sense, thanks for the suggestions.  I've included the 
revised patch.

[-- Attachment #2: text-scale-patch-v3 --]
[-- Type: application/octet-stream, Size: 3178 bytes --]

diff --git a/lisp/face-remap.el b/lisp/face-remap.el
index 00560f9d2e..95dffcadd6 100644
--- a/lisp/face-remap.el
+++ b/lisp/face-remap.el
@@ -70,6 +70,13 @@ internal-lisp-face-attributes
    :foreground :background :stipple :overline :strike-through :box
    :font :inherit :fontset :distant-foreground :extend :vector])
 
+(defun face-attrs--make-indirect-safe ()
+  "Deep copy `face-remapping-alist' on cloning for safety."
+  (setq-local face-remapping-alist
+              (mapcar #'copy-sequence face-remapping-alist)))
+
+(add-hook 'clone-indirect-buffer-hook #'face-attrs--make-indirect-safe)
+
 (defun face-attrs-more-relative-p (attrs1 attrs2)
   "Return true if ATTRS1 contains a greater number of relative
 face-attributes than ATTRS2.  A face attribute is considered
diff --git a/lisp/simple.el b/lisp/simple.el
index cbcde9fb8d..8d0520d663 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -9441,9 +9441,6 @@ function-key-map
 (defvar clone-buffer-hook nil
   "Normal hook to run in the new buffer at the end of `clone-buffer'.")
 
-(defvar clone-indirect-buffer-hook nil
-  "Normal hook to run in the new buffer at the end of `clone-indirect-buffer'.")
-
 (defun clone-process (process &optional newname)
   "Create a twin copy of PROCESS.
 If NEWNAME is nil, it defaults to PROCESS' name;
@@ -9596,8 +9593,6 @@ clone-indirect-buffer
       (setq newname (substring newname 0 (match-beginning 0))))
   (let* ((name (generate-new-buffer-name newname))
 	 (buffer (make-indirect-buffer (current-buffer) name t)))
-    (with-current-buffer buffer
-      (run-hooks 'clone-indirect-buffer-hook))
     (when display-flag
       (pop-to-buffer buffer nil norecord))
     buffer))
diff --git a/src/buffer.c b/src/buffer.c
index 10ac91915c..3b17d6c9ce 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -912,6 +912,10 @@ DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer,
       Fset (intern ("buffer-save-without-query"), Qnil);
       Fset (intern ("buffer-file-number"), Qnil);
       Fset (intern ("buffer-stale-function"), Qnil);
+      /* Cloned buffers need extra setup, to do things such as deep
+	 variable copies for list variables that might be mangled due
+	 to destructive operations in the indirect buffer. */
+      run_hook (Qclone_indirect_buffer_hook);
       set_buffer_internal_1 (old_b);
     }
 
@@ -5569,6 +5573,9 @@ syms_of_buffer (void)
   Fput (Qprotected_field, Qerror_message,
 	build_pure_c_string ("Attempt to modify a protected field"));
 
+  DEFSYM (Qclone_indirect_buffer_hook, "clone-indirect-buffer-hook");
+
+
   DEFVAR_PER_BUFFER ("tab-line-format",
 		     &BVAR (current_buffer, tab_line_format),
 		     Qnil,
@@ -6392,6 +6399,10 @@ Functions (implicitly) running this hook are `get-buffer-create',
 This is the default.  If nil, auto-save file deletion is inhibited.  */);
   delete_auto_save_files = 1;
 
+  DEFVAR_LISP ("clone-indirect-buffer-hook", Vclone_indirect_buffer_hook,
+	       doc: /* Normal hook to run in the new buffer at the end of `clone-indirect-buffer'. */);
+  Vclone_indirect_buffer_hook = Qnil;
+
   defsubr (&Sbuffer_live_p);
   defsubr (&Sbuffer_list);
   defsubr (&Sget_buffer);

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-19  2:37                     ` Andrew Hyatt
@ 2022-01-19  3:42                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-01-20 13:42                         ` Lars Ingebrigtsen
  0 siblings, 1 reply; 18+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-01-19  3:42 UTC (permalink / raw)
  To: Andrew Hyatt; +Cc: Eli Zaretskii, 53294

> Makes sense, thanks for the suggestions.  I've included the revised patch.

Looks good to me, thanks,


        Stefan






^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-19  3:42                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-01-20 13:42                         ` Lars Ingebrigtsen
  0 siblings, 0 replies; 18+ messages in thread
From: Lars Ingebrigtsen @ 2022-01-20 13:42 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Andrew Hyatt, 53294

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Makes sense, thanks for the suggestions.  I've included the revised patch.
>
> Looks good to me, thanks,

So I've pushed the patch to Emacs 29.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-01-16  5:13 bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer Andrew Hyatt
  2022-01-16  9:22 ` Eli Zaretskii
@ 2022-02-16 17:41 ` Anders Johansson
  2022-02-17 11:41   ` Lars Ingebrigtsen
  2022-02-17 13:38   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 2 replies; 18+ messages in thread
From: Anders Johansson @ 2022-02-16 17:41 UTC (permalink / raw)
  To: Lars Ingebrigtsen, Stefan Monnier, Andrew Hyatt, 53294,
	Eli Zaretskii

Hi,

Stefan wrote:
> I think `mapcar #'copy-sequence` is slightly more correct than
> `copy-tree`,

This gives me  "Wrong type argument: listp, mini-modeline-mode-line-active"
For a face-remapping-alist that looks like:
((mode-line-active . mini-modeline-mode-line-active)
 (mode-line-inactive . mini-modeline-mode-line-inactive))

According to my reading of the docstring of face-remapping-alist, this
should be allowed, and does work (except for indirect buffers perhaps)

face-remap-add-relative would generate:
((mode-line-active mini-modeline-mode-line-active)
 (mode-line-inactive mini-modeline-mode-line-inactive))

mini-modeline (https://github.com/kiennq/emacs-mini-modeline/) sets
face-remapping-alist directly for various reasons. I guess this is not
really recommended. But this fix seems to cause problems in an
otherwise "correct" use of face-remapping-alist.

Best,
Anders Johansson





^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-02-16 17:41 ` Anders Johansson
@ 2022-02-17 11:41   ` Lars Ingebrigtsen
  2022-02-17 13:38   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 18+ messages in thread
From: Lars Ingebrigtsen @ 2022-02-17 11:41 UTC (permalink / raw)
  To: Anders Johansson; +Cc: Andrew Hyatt, 53294, Stefan Monnier

Anders Johansson <mejlaandersj@gmail.com> writes:

> This gives me  "Wrong type argument: listp, mini-modeline-mode-line-active"
> For a face-remapping-alist that looks like:
> ((mode-line-active . mini-modeline-mode-line-active)
>  (mode-line-inactive . mini-modeline-mode-line-inactive))

Do you have a recipe to reproduce the problem, starting from "emacs -Q"?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 18+ messages in thread

* bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer
  2022-02-16 17:41 ` Anders Johansson
  2022-02-17 11:41   ` Lars Ingebrigtsen
@ 2022-02-17 13:38   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 18+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-02-17 13:38 UTC (permalink / raw)
  To: Anders Johansson; +Cc: Lars Ingebrigtsen, 53294, Andrew Hyatt, Eli Zaretskii

>> I think `mapcar #'copy-sequence` is slightly more correct than
>> `copy-tree`,
>
> This gives me  "Wrong type argument: listp, mini-modeline-mode-line-active"
> For a face-remapping-alist that looks like:
> ((mode-line-active . mini-modeline-mode-line-active)
>  (mode-line-inactive . mini-modeline-mode-line-inactive))

I pushed a patch to `master` which should fix it.  Can you confirm that
it fixes it for you?


        Stefan






^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2022-02-17 13:38 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-01-16  5:13 bug#53294: 29.0.50; Indirect font changes incorrectly affecting original buffer Andrew Hyatt
2022-01-16  9:22 ` Eli Zaretskii
2022-01-16 14:43   ` Andrew Hyatt
2022-01-16 15:00     ` Eli Zaretskii
2022-01-16 15:28       ` Andrew Hyatt
2022-01-16 15:41         ` Eli Zaretskii
2022-01-16 17:11           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-01-16 18:16             ` Eli Zaretskii
2022-01-16 21:41               ` Andrew Hyatt
2022-01-17 21:47               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-01-18  2:24                 ` Andrew Hyatt
2022-01-18  2:47                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-01-19  2:37                     ` Andrew Hyatt
2022-01-19  3:42                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-01-20 13:42                         ` Lars Ingebrigtsen
2022-02-16 17:41 ` Anders Johansson
2022-02-17 11:41   ` Lars Ingebrigtsen
2022-02-17 13:38   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).