What is the correct way to setup/teardown modes?

I’m having some problems with my setup/teardown for a mode. It looks like enable is called three times…? And my failsafe to avoid running more than once doesn’t work?

The code tries to add an extra hint-selector, , div[role='link'] when starting, and tries to remove it when stopping. It only adds if it doesn’t find it already, and only removes a single instance if it added it.

But somehow three instances are added, and none removed. I don’t know how to correctly debug this. sly-db-break-on-signal gives too much noise as there’s a lot of signals. Tried using sly stickers, but couldn’t get it to break.

;; TODO: This probably exist somewhere already
(defun find-mode (mode &optional (buffer (current-buffer)))
  (find mode (modes buffer) :test #'equal :key #'name))

(define-mode gmail-mode ()
  ((extra-hints ", div[role='link']")
   (extra-hints-added nil)))

(defmethod enable ((mode gmail-mode) &key)
  (let* ((hint-mode (find-mode 'nyxt/mode/hint:hint-mode (buffer mode)))
         (hints-selector (nyxt/mode/hint:hints-selector hint-mode)))
    (unless (find (extra-hints mode) hints-selector :test #'equal)
      (setf (extra-hints-added mode) (extra-hints mode)
            (nyxt/mode/hint:hints-selector hint-mode) (str:concat hints-selector (extra-hints mode))))))

(defmethod disable ((mode gmail-mode) &key)
  (when (extra-hints-added mode)
    (let* ((hint-mode (find-mode 'nyxt/mode/hint:hint-mode (buffer mode)))
           (new-selector (cl-ppcre:regex-replace (extra-hints-added mode) (nyxt/mode/hint:hints-selector hint-mode) "")))
      (setf (nyxt/mode/hint:hints-selector hint-mode) new-selector
            (extra-hints-added mode) nil))))

(define-auto-rule '(match-host "mail.google.com")
  :included '(gmail-mode))

:person_facepalming: of course regex-replace doesn’t work. Replaced with str:replace-first and now it’s removed properly. This also fixes the multiple values in the hints added, but that really just indicate that the mode is enabled and disabled several times – why is this the case? It should only be enabled for gmail buffers, and I only have a single gmail buffer open (even just a single buffer in total).

So why is the mode enabled and disabled several times?

;; TODO: This probably exist somewhere already

You might be looking for find-submode.

As for the main question, we'd need to look deeper into it. Maybe @aartaka can help.

Two responses here:

  • Do you maybe need hint-selector of hint-mode? It’s exactly this selector adjustment that you might need. And we actually thought about including all the actionable ARIA roles into the default selector, just didn’t get to it yet :slight_smile:

  • An important fact that you probably don’t need now that you figured your problem: enable method can be invoked several times per each mode your mode depends on. So you can make your mode inherit from hint-mode and then rely on the enable/disable of hint-mode somehow. Not sure it’s going to be that useful, but still :wink:

That's what I'm using. My problem was in my cleanup function.

Hmm, didn't consider that. But I guess that will cause problems? The order of the modes will determine who get's to handle the key? Unless my mode explicitly disables hint-mode during initialization and reinstates it on disable (much like I do with the css selector). But that won't play nicely together with other modes which might relay on hint-mode I guess.