unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* A programming puzzle with buffer-local hooks
@ 2017-05-18 15:10 Clément Pit-Claudel
  2017-05-18 15:16 ` Phillip Lord
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Clément Pit-Claudel @ 2017-05-18 15:10 UTC (permalink / raw)
  To: Emacs developers

Hey emacs-devel,

I'm writing a minor mode that shows notifications, but only if Emacs is in the background.  At first sight it looks simple enough:

    (defvar my--emacs-has-focus t)

    (defun my--notify-focus-in ()
      "Handle a focus-in event."
      (setq my--emacs-has-focus t))

    (defun my--notify-focus-out ()
      "Handle a focus-out event."
      (setq my--emacs-has-focus nil))

    (define-minor-mode my-notifying-mode
      "Maybe show notifications."
      :lighter " not"
      (cond
       (my-notifying-mode
        (add-hook 'focus-in-hook #'my--notify-focus-in)
        (add-hook 'focus-out-hook #'my--notify-focus-out))
       (t
        (remove-hook 'focus-in-hook #'my--notify-focus-in)
        (remove-hook 'focus-out-hook #'my--notify-focus-out))))

But now there's a trick: if the mode is disabled in one buffer (but not in others), it will remove its hook and break itself in all buffers in which it's still enabled.

The usual trick is to make the hook buffer local.  But this doesn't work here: making focus-in-hook buffer-local seems to cause it to run only if the buffer is current (or if the buffer's window is selected?).
I can think of two other tricks: reference counting (every time the mode is disabled, check whether it's enabled anywhere else), and never removing the hook.

Any better idea?

Thanks!
Clément.



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

* Re: A programming puzzle with buffer-local hooks
  2017-05-18 15:10 A programming puzzle with buffer-local hooks Clément Pit-Claudel
@ 2017-05-18 15:16 ` Phillip Lord
  2017-05-18 15:45   ` Clément Pit-Claudel
  2017-05-18 16:51 ` Stefan Monnier
  2017-05-19  6:30 ` martin rudalics
  2 siblings, 1 reply; 10+ messages in thread
From: Phillip Lord @ 2017-05-18 15:16 UTC (permalink / raw)
  To: "Clément Pit-Claudel"; +Cc: Emacs developers

On Thu, May 18, 2017 3:10 pm, Clément Pit-Claudel wrote:
> Hey emacs-devel,
>
>
> I'm writing a minor mode that shows notifications, but only if Emacs is
> in the background.  At first sight it looks simple enough:
>
> (defvar my--emacs-has-focus t)
>
>
> (defun my--notify-focus-in ()
> "Handle a focus-in event."
> (setq my--emacs-has-focus t))
>
>
> (defun my--notify-focus-out ()
> "Handle a focus-out event."
> (setq my--emacs-has-focus nil))
>
>
> (define-minor-mode my-notifying-mode
> "Maybe show notifications."
> :lighter " not"
> (cond
> (my-notifying-mode
> (add-hook 'focus-in-hook #'my--notify-focus-in)
> (add-hook 'focus-out-hook #'my--notify-focus-out))
> (t
> (remove-hook 'focus-in-hook #'my--notify-focus-in)
> (remove-hook 'focus-out-hook #'my--notify-focus-out))))
>
>
> But now there's a trick: if the mode is disabled in one buffer (but not
> in others), it will remove its hook and break itself in all buffers in
> which it's still enabled.
>
> The usual trick is to make the hook buffer local.  But this doesn't work
> here: making focus-in-hook buffer-local seems to cause it to run only if
> the buffer is current (or if the buffer's window is selected?). I can
> think of two other tricks: reference counting (every time the mode is
> disabled, check whether it's enabled anywhere else), and never removing
> the hook.
>
> Any better idea?

Add the hook globally, and then have your hook functions check whether the
mode is on or off before they do anything.

Phil





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

* Re: A programming puzzle with buffer-local hooks
  2017-05-18 15:16 ` Phillip Lord
@ 2017-05-18 15:45   ` Clément Pit-Claudel
  0 siblings, 0 replies; 10+ messages in thread
From: Clément Pit-Claudel @ 2017-05-18 15:45 UTC (permalink / raw)
  To: Phillip Lord; +Cc: Emacs developers

On 2017-05-18 11:16, Phillip Lord wrote:
> Add the hook globally, and then have your hook functions check whether the
> mode is on or off before they do anything.

I think that's mostly what I meant by "never removing the hook". Am I misunderstanding you?



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

* Re: A programming puzzle with buffer-local hooks
@ 2017-05-18 15:54 Phillip Lord
  2017-05-18 15:56 ` Clément Pit-Claudel
  0 siblings, 1 reply; 10+ messages in thread
From: Phillip Lord @ 2017-05-18 15:54 UTC (permalink / raw)
  To: "Clément Pit-Claudel"; +Cc: Emacs developers, Phillip Lord

On Thu, May 18, 2017 3:45 pm, Clément Pit-Claudel wrote:
> On 2017-05-18 11:16, Phillip Lord wrote:
>
>> Add the hook globally, and then have your hook functions check whether
>> the mode is on or off before they do anything.
>
> I think that's mostly what I meant by "never removing the hook". Am I
> misunderstanding you?


Well, combined with making it global, yes.

I always found developing a minor mode where we add and remove hooks to be
a bit of a pain, because you can easily end up with different buffers have
different state during development. On the other hand, if you have a
single global hook, it's either there or not, just whether it works or not
is dependent only on whether the minor-mode is on or not.

Seems a lot nicer to me.





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

* Re: A programming puzzle with buffer-local hooks
  2017-05-18 15:54 Phillip Lord
@ 2017-05-18 15:56 ` Clément Pit-Claudel
  2017-05-18 18:46   ` Phillip Lord
  0 siblings, 1 reply; 10+ messages in thread
From: Clément Pit-Claudel @ 2017-05-18 15:56 UTC (permalink / raw)
  To: Phillip Lord; +Cc: Emacs developers

On 2017-05-18 11:54, Phillip Lord wrote:
> On Thu, May 18, 2017 3:45 pm, Clément Pit-Claudel wrote:
>> On 2017-05-18 11:16, Phillip Lord wrote:
>>
>>> Add the hook globally, and then have your hook functions check whether
>>> the mode is on or off before they do anything.
>>
>> I think that's mostly what I meant by "never removing the hook". Am I
>> misunderstanding you?
> 
> Well, combined with making it global, yes.
> 
> I always found developing a minor mode where we add and remove hooks to be
> a bit of a pain, because you can easily end up with different buffers have
> different state during development. On the other hand, if you have a
> single global hook, it's either there or not, just whether it works or not
> is dependent only on whether the minor-mode is on or not.
> 
> Seems a lot nicer to me.

I entirely agree.  But as a user I dislike these zombie hooks :)



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

* Re: A programming puzzle with buffer-local hooks
  2017-05-18 15:10 A programming puzzle with buffer-local hooks Clément Pit-Claudel
  2017-05-18 15:16 ` Phillip Lord
@ 2017-05-18 16:51 ` Stefan Monnier
  2017-05-18 18:38   ` Clément Pit-Claudel
  2017-05-19  6:30 ` martin rudalics
  2 siblings, 1 reply; 10+ messages in thread
From: Stefan Monnier @ 2017-05-18 16:51 UTC (permalink / raw)
  To: emacs-devel

> The usual trick is to make the hook buffer local.

Can't work because the focus events don't care about the current-buffer.

> I can think of two other tricks: reference counting (every time the
> mode is disabled, check whether it's enabled anywhere else), and never
> removing the hook.

Before removing the hook, check if there's still a buffer where the mode
is activated.


        Stefan




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

* Re: A programming puzzle with buffer-local hooks
  2017-05-18 16:51 ` Stefan Monnier
@ 2017-05-18 18:38   ` Clément Pit-Claudel
  0 siblings, 0 replies; 10+ messages in thread
From: Clément Pit-Claudel @ 2017-05-18 18:38 UTC (permalink / raw)
  To: emacs-devel

On 2017-05-18 12:51, Stefan Monnier wrote:
>> I can think of two other tricks: reference counting (every time the
>> mode is disabled, check whether it's enabled anywhere else), and never
>> removing the hook.
> 
> Before removing the hook, check if there's still a buffer where the mode
> is activated.

That's what the line you quoted meant to say. Sorry if it wasn't clear :/

Clément.



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

* Re: A programming puzzle with buffer-local hooks
  2017-05-18 15:56 ` Clément Pit-Claudel
@ 2017-05-18 18:46   ` Phillip Lord
  2017-05-18 19:03     ` Clément Pit-Claudel
  0 siblings, 1 reply; 10+ messages in thread
From: Phillip Lord @ 2017-05-18 18:46 UTC (permalink / raw)
  To: "Clément Pit-Claudel"; +Cc: Emacs developers, Phillip Lord

On Thu, May 18, 2017 3:56 pm, Clément Pit-Claudel wrote:
> On 2017-05-18 11:54, Phillip Lord wrote:
>
>> On Thu, May 18, 2017 3:45 pm, Clément Pit-Claudel wrote:
>>
>>> On 2017-05-18 11:16, Phillip Lord wrote:
>>>
>>>
>>>> Add the hook globally, and then have your hook functions check
>>>> whether the mode is on or off before they do anything.
>>>
>>> I think that's mostly what I meant by "never removing the hook". Am I
>>>  misunderstanding you?
>>
>> Well, combined with making it global, yes.
>>
>>
>> I always found developing a minor mode where we add and remove hooks to
>> be a bit of a pain, because you can easily end up with different buffers
>> have different state during development. On the other hand, if you have
>> a single global hook, it's either there or not, just whether it works or
>> not is dependent only on whether the minor-mode is on or not.
>>
>> Seems a lot nicer to me.
>>
>
> I entirely agree.  But as a user I dislike these zombie hooks :)


Why? Perhaps the solution is to work out what you dislike about it, and
the see if we can do something generic to solve the problem. The issue is
not at all specific to your mode.

Phil




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

* Re: A programming puzzle with buffer-local hooks
  2017-05-18 18:46   ` Phillip Lord
@ 2017-05-18 19:03     ` Clément Pit-Claudel
  0 siblings, 0 replies; 10+ messages in thread
From: Clément Pit-Claudel @ 2017-05-18 19:03 UTC (permalink / raw)
  To: Phillip Lord; +Cc: Emacs developers

On 2017-05-18 14:46, Phillip Lord wrote:
> Why? Perhaps the solution is to work out what you dislike about it, and
> the see if we can do something generic to solve the problem. The issue is
> not at all specific to your mode.

It feels messy, mostly — I don't expect minor modes to leave code after I stop using them.



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

* Re: A programming puzzle with buffer-local hooks
  2017-05-18 15:10 A programming puzzle with buffer-local hooks Clément Pit-Claudel
  2017-05-18 15:16 ` Phillip Lord
  2017-05-18 16:51 ` Stefan Monnier
@ 2017-05-19  6:30 ` martin rudalics
  2 siblings, 0 replies; 10+ messages in thread
From: martin rudalics @ 2017-05-19  6:30 UTC (permalink / raw)
  To: Clément Pit-Claudel, Emacs developers

 > I can think of two other tricks: reference counting (every time the
 > mode is disabled, check whether it's enabled anywhere else), and never
 > removing the hook.

I would use reference counting with an increment call when the mode is
enabled in a buffer and a decrement call run by ‘kill-buffer-hook’ and
when the mode gets disabled in a buffer.  Obviously, the function on
‘kill-buffer-hook’ should be removed together with the other functions
when that count drops to zero.

martin




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

end of thread, other threads:[~2017-05-19  6:30 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-05-18 15:10 A programming puzzle with buffer-local hooks Clément Pit-Claudel
2017-05-18 15:16 ` Phillip Lord
2017-05-18 15:45   ` Clément Pit-Claudel
2017-05-18 16:51 ` Stefan Monnier
2017-05-18 18:38   ` Clément Pit-Claudel
2017-05-19  6:30 ` martin rudalics
  -- strict thread matches above, loose matches on Subject: below --
2017-05-18 15:54 Phillip Lord
2017-05-18 15:56 ` Clément Pit-Claudel
2017-05-18 18:46   ` Phillip Lord
2017-05-18 19:03     ` Clément Pit-Claudel

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).