3

I am programming my own Emacs minor mode using the idioms and macros similar to this minimal example:

(define-minor-mode foo-mode
  "Toggle Foo mode."
  :init-value nil
  :lighter " Foo"
  :group 'foo
  (if foo-mode
      (do-enable-foo)
    (do-disable-foo))
  )

(defun do-enable-foo ()
  "Enable foo minor mode"
  (message "Enabling foo...")
  (if test-something
      (message "Foo enabled after disabling was canceled!")
    (message "Foo enabled from scratch"))
  )

(defun do-disable-foo ()
  "Disable foo minor mode"
  (message "Disabling foo...")
  (if (not certain-situation)
      (message "... done.") ; finish disabling foo
    ;; else forms:
    (message "Need to cancel disabling foo!")
    (foo-mode 1)) ; turning foo mode on again
  )

During the toggling off of the minor mode, a 'certain-situation may arise when I have to cancel toggling off. Currently, I am thinking since I am using the define-minor-mode macro, that I cannot bail out but just have to programmatically turn the mode on again using (foo-mode 1) as seen in the code.

If I go this route, I will have to handle this differently in the enabling function do-enable-foo -- so my first question is how to detect this case using the placeholder 'test-something in the code above?

Or, is there a cleaner way to achieve the cancel, for example, by signaling an error instead of (foo-mode 1) to prevent the mode toggle from going through?

Linda
  • 131
  • 1
  • 4

3 Answers3

2

If you want to cancel the "turn off", rather than call (foo-mode 1), you can just (setq foo-mode t).

If for some reason you really want to call (foo-mode 1) recursively to (re)enable the mode, then you can do it in the following way:

(defvar foo-mode--reenabling nil)
....
(defun do-enable-foo ()
  (if foo-mode--reenabling
      ...
    ...))
...
(defun do-disable-foo ()
  ...
  (let ((foo-mode--reenabling t))
    (foo-mode 1)))
Stefan
  • 27,908
  • 4
  • 53
  • 82
0

I would be very scared about preventing the user from turning off a minor mode. I mean, if the minor mode is broken, or misbehaving, you leave them with with a broken Emacs that must be killed. What is the condition that you are thinking off?

The opposite situation -- a mode which refuses to be turned on under certain circumstances -- already happens -- paredit-mode is a nice example. It just throws an error in the define-minor-mode body.

Phil Lord
  • 2,917
  • 1
  • 20
  • 31
0

I ended up using Stefan's suggestion in the following way using the variable to signal to the minor mode definition that the mode was enabled as a result of cancelling the disable process (actually as a result of a user query). I didn't dare to use the idea of simply setting the mode variable to t but I cannot find the documentation anymore that cautioned against it. It might be worthwhile to see if using (setq foo-mode t) actually lets me eliminate the new variable canceled-foo-off.

(defvar canceled-foo-off nil "Set to `true' if user canceled toggling off foo.")
(make-variable-buffer-local 'canceled-foo-off)

(define-minor-mode foo-mode
  ...
  (if foo-mode
      (if canceled-foo-off
        (setq canceled-foo-off nil) ; Mode was turned back on from cancelling 
      (do-enable-foo)) ; Mode was turned on from scratch
    (do-disable-foo))
  )

(defun do-disable-foo ()
  "Disable foo minor mode"
  (if (not certain-situation)
      ...
    ;; else forms:
    (setq canceled-foo-off t) ; make sure mode starting procedure is not run!
    (foo-mode 1)) ; turning foo mode on again
  )
Linda
  • 131
  • 1
  • 4