2

I have a minor mode definition like this, and I want to prevent it from being enabled when the config variable example-mode-config has not been defined.

;;; ....

;;;###autoload
(define-minor-mode example-mode
  "Enables the example mode"
  (if example-mode
      (example-mode-enable)
    (example-mode-disable)))

(defun example-mode-enable ()
  (cond ((not example-mode-config)
         (message "please define example-mode-config before using example-mode")
         ;;; seem to need to do something here to disable the mode
         ;;; otherwise the mode gets enabled, but does not work
         )
        (t  ;;;; go ahead and set up .....
         )))

The problem is that if example-mode-config is undefined, the function example-mode-config returns doing nothing, but the calling framework still goes ahead and enables the mode.

  • If by "undefined" you mean example-mode-config might not yet be bound, you can test that with boundp. – Dan Jan 19 '18 at 11:15
  • Yes, although in my case it has been declared with defcustom but set to nil, and boundp returns t – wu-lee Jan 19 '18 at 11:24
2

The normal way to do that is simply to set example-mode within the minor mode's body (also I find it's rarely useful to have separate foo-enable and foo-disable functions):

(define-minor-mode example-mode
  "Enables the example mode"
  (cond
   ((not example-mode-config)
    (setq example-mode nil)
    (message "Set example-mode-config before using example-mode"))
   (example-mode
    ...go ahead and set it up...)
   (t
    ...disable the mode...))

If you want to avoid the execution of the example-mode-hook functions on a missing configuration just change the first message into error for a non-local exit.

  • Setting example-mode to nil does not prevent the execution of the hook functions even if the mode was never active. I think you need at least a non-local exit for that. (You never know what users do within the hook functions. It might be that they assume that example-mode was t if the hook function is called with a nil value for example-mode. That could cause access of void values and stuff like that.) – Tobias Jan 19 '18 at 14:54
  • 1
    @Tobias: the hook function of minor modes is run both when enabling and disabling the mode, including when enabling a mode that was already enabled and disabling a mode that was already disabled, so I don't see any reason why we should make extra efforts to avoid running the hook. But if you want that, just change the message into error. – Stefan Jan 19 '18 at 15:09
  • Okay I think I see what you mean. One can just run (example-mode -1) to make sure that example-mode is not active regardless of the value of example-mode. Good. One needs to keep that in mind when one writes hook functions for minor-modes. Thanks for the comment. – Tobias Jan 19 '18 at 15:15
  • What works for me is, when example-mode-config is not configured, to (example-mode -1) then (error "Set...") - this seems to successfully prevent example-mode getting marked enabled in the status line. – wu-lee Jan 19 '18 at 15:58
  • @wo-lee That is what I thought when I wrote up my solution after inspecting the code of define-minor-mode. Should I undelete my solution? Before I thought about the indicator in the mode line and the hook functions I tented to give Stefans solution of just setting the mode variable to nil. I re-thought after inspecting the code. Afterwards I read Stefan's solution. Stefan is generally more experienced than me. Therefore I accepted his simple solution and deleted mine. – Tobias Jan 19 '18 at 19:38
0

First of all: The answer of Stefan is right and it is good that you accepted it.

I re-visited the code of define-minor-mode. Maybe a small modification of your code is in place. So go on reading...

The structure of the generated mode-function example-mode is as follows:

  1. Setting the mode-variable
  2. Running body
  3. Running the hook(s)
  4. Printing a message when called interactively
  5. Mode line update.

So it seems best to handle a configuration error as follows in the body:

  1. Set the mode variable back.
  2. Call (error ...) to avoid the message and the mode-line-update. In the normal case you don't need the mode-line-update since the value of the mode variable was right (nil) before the call of the mode function.

If you want to allow a failing re-configuration through a call to (example-mode) even if example-mode is already t at invocation of (example-mode) add a (force-mode-line-update) after (setq example-mode nil) in the error case.

Since you are effectively switching off example-mode in the case of a configuration error it may even be good to call the mode hooks. So the only thing we avoid is the message.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.