]> code.delx.au - gnu-emacs/blobdiff - lisp/emacs-lisp/easy-mmode.el
Make autoloading commands prompt for autoload file (Bug#7989)
[gnu-emacs] / lisp / emacs-lisp / easy-mmode.el
index 13e08667839e425ad85f0d65e73fb0101aed47e6..46dc1f162baa180934f898e55a67dbd721fb93ec 100644 (file)
@@ -1,10 +1,10 @@
 ;;; easy-mmode.el --- easy definition for major and minor modes
 
-;; Copyright (C) 1997, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-;;   2008, 2009, 2010  Free Software Foundation, Inc.
+;; Copyright (C) 1997, 2000-2011  Free Software Foundation, Inc.
 
 ;; Author: Georges Brun-Cottan <Georges.Brun-Cottan@inria.fr>
 ;; Maintainer: Stefan Monnier <monnier@gnu.org>
+;; Package: emacs
 
 ;; Keywords: extensions lisp
 
@@ -86,25 +86,24 @@ replacing its case-insensitive matches with the literal string in LIGHTER."
 ;;;###autoload
 (defmacro define-minor-mode (mode doc &optional init-value lighter keymap &rest body)
   "Define a new minor mode MODE.
-This function defines the associated control variable MODE, keymap MODE-map,
-and toggle command MODE.
-
+This defines the control variable MODE and the toggle command MODE.
 DOC is the documentation for the mode toggle command.
+
 Optional INIT-VALUE is the initial value of the mode's variable.
 Optional LIGHTER is displayed in the modeline when the mode is on.
-Optional KEYMAP is the default (defvar) keymap bound to the mode keymap.
-  If it is a list, it is passed to `easy-mmode-define-keymap'
-  in order to build a valid keymap.  It's generally better to use
-  a separate MODE-map variable than to use this argument.
-The above three arguments can be skipped if keyword arguments are
-used (see below).
-
-BODY contains code to execute each time the mode is activated or deactivated.
-  It is executed after toggling the mode,
-  and before running the hook variable `MODE-hook'.
-  Before the actual body code, you can write keyword arguments (alternating
-  keywords and values).  These following keyword arguments are supported (other
-  keywords will be passed to `defcustom' if the minor mode is global):
+Optional KEYMAP is the default keymap bound to the mode keymap.
+  If non-nil, it should be a variable name (whose value is a keymap),
+  or an expression that returns either a keymap or a list of
+  arguments for `easy-mmode-define-keymap'.  If KEYMAP is not a symbol,
+  this also defines the variable MODE-map.
+
+BODY contains code to execute each time the mode is enabled or disabled.
+  It is executed after toggling the mode, and before running MODE-hook.
+  Before the actual body code, you can write keyword arguments, i.e.
+  alternating keywords and values.  These following special keywords
+  are supported (other keywords are passed to `defcustom' if the minor
+  mode is global):
+
 :group GROUP   Custom group name to use in all generated `defcustom' forms.
                Defaults to MODE without the possible trailing \"-mode\".
                Don't use this default group name unless you have written a
@@ -116,6 +115,12 @@ BODY contains code to execute each time the mode is activated or deactivated.
 :lighter SPEC  Same as the LIGHTER argument.
 :keymap MAP    Same as the KEYMAP argument.
 :require SYM   Same as in `defcustom'.
+:variable PLACE        The location (as can be used with `setf') to use instead
+               of the variable MODE to store the state of the mode.  PLACE
+               can also be of the form (GET . SET) where GET is an expression
+               that returns the current state and SET is a function that takes
+               a new state and sets it.  If you specify a :variable, this
+               function assumes it is defined elsewhere.
 
 For example, you could write
   (define-minor-mode foo-mode \"If enabled, foo on you!\"
@@ -147,6 +152,9 @@ For example, you could write
         (type nil)
         (extra-args nil)
         (extra-keywords nil)
+         (variable nil)          ;The PLACE where the state is stored.
+         (setter nil)            ;The function (if any) to set the mode var.
+         (modefun mode)          ;The minor mode function name we're defining.
         (require t)
         (hook (intern (concat mode-name "-hook")))
         (hook-on (intern (concat mode-name "-on-hook")))
@@ -167,6 +175,12 @@ For example, you could write
        (:type (setq type (list :type (pop body))))
        (:require (setq require (pop body)))
        (:keymap (setq keymap (pop body)))
+        (:variable (setq variable (pop body))
+         (if (not (functionp (cdr-safe variable)))
+             ;; PLACE is not of the form (GET . SET).
+             (setq mode variable)
+           (setq mode (car variable))
+           (setq setter (cdr variable))))
        (t (push keyw extra-keywords) (push (pop body) extra-keywords))))
 
     (setq keymap-sym (if (and keymap (symbolp keymap)) keymap
@@ -183,16 +197,21 @@ For example, you could write
            `(:group ',(intern (replace-regexp-in-string
                                "-mode\\'" "" mode-name)))))
 
+    ;; TODO? Mark booleans as safe if booleanp?  Eg abbrev-mode.
     (unless type (setq type '(:type 'boolean)))
 
     `(progn
        ;; Define the variable to enable or disable the mode.
-       ,(if (not globalp)
-           `(progn
-              (defvar ,mode ,init-value ,(format "Non-nil if %s is enabled.
+       ,(cond
+         ;; If :variable is specified, then the var will be
+         ;; declared elsewhere.
+         (variable nil)
+         ((not globalp)
+          `(progn
+             (defvar ,mode ,init-value ,(format "Non-nil if %s is enabled.
 Use the command `%s' to change this variable." pretty-name mode))
-              (make-variable-buffer-local ',mode))
-
+             (make-variable-buffer-local ',mode)))
+         (t
          (let ((base-doc-string
                  (concat "Non-nil if %s is enabled.
 See the command `%s' for a description of this minor mode."
@@ -207,10 +226,10 @@ or call the function `%s'."))))
               ,@group
               ,@type
               ,@(unless (eq require t) `(:require ,require))
-               ,@(nreverse extra-keywords))))
+               ,@(nreverse extra-keywords)))))
 
        ;; The actual function.
-       (defun ,mode (&optional arg ,@extra-args)
+       (defun ,modefun (&optional arg ,@extra-args)
         ,(or doc
              (format (concat "Toggle %s on or off.
 Interactively, with no prefix argument, toggle the mode.
@@ -221,22 +240,19 @@ With zero or negative ARG turn mode off.
         ;; repeat-command still does the toggling correctly.
         (interactive (list (or current-prefix-arg 'toggle)))
         (let ((,last-message (current-message)))
-           (setq ,mode
-                 (cond
-                  ((eq arg 'toggle) (not ,mode))
-                  (arg (> (prefix-numeric-value arg) 0))
-                  (t
-                   (if (null ,mode) t
-                     (message
-                      "Toggling %s off; better pass an explicit argument."
-                      ',mode)
-                     nil))))
+           (,@(if setter (list setter)
+                (list (if (symbolp mode) 'setq 'setf) mode))
+            (if (eq arg 'toggle)
+                (not ,mode)
+              ;; A nil argument also means ON now.
+              (> (prefix-numeric-value arg) 0)))
            ,@body
            ;; The on/off hooks are here for backward compatibility only.
            (run-hooks ',hook (if ,mode ',hook-on ',hook-off))
            (if (called-interactively-p 'any)
                (progn
-                 ,(if globalp `(customize-mark-as-set ',mode))
+                 ,(if (and globalp (symbolp mode))
+                      `(customize-mark-as-set ',mode))
                  ;; Avoid overwriting a message shown by the body,
                  ;; but do overwrite previous messages.
                  (unless (and (current-message)
@@ -258,12 +274,18 @@ With zero or negative ARG turn mode off.
             (let ((m ,keymap))
               (cond ((keymapp m) m)
                     ((listp m) (easy-mmode-define-keymap m))
-                    (t (error "Invalid keymap %S" ,keymap))))
+                    (t (error "Invalid keymap %S" m))))
             ,(format "Keymap for `%s'." mode-name)))
 
-       (add-minor-mode ',mode ',lighter
-                      ,(if keymap keymap-sym
-                         `(if (boundp ',keymap-sym) ,keymap-sym))))))
+       ,(if (not (symbolp mode))
+            (if (or lighter keymap)
+                (error ":lighter and :keymap unsupported with mode expression %s" mode))
+          `(with-no-warnings
+             (add-minor-mode ',mode ',lighter
+                           ,(if keymap keymap-sym
+                                `(if (boundp ',keymap-sym) ,keymap-sym))
+                             nil
+                             ,(unless (eq mode modefun) 'modefun)))))))
 \f
 ;;;
 ;;; make global minor mode
@@ -343,9 +365,11 @@ See `%s' for more information on %s."
             (progn
               (add-hook 'after-change-major-mode-hook
                         ',MODE-enable-in-buffers)
+              (add-hook 'fundamental-mode-hook ',MODE-enable-in-buffers)
               (add-hook 'find-file-hook ',MODE-check-buffers)
               (add-hook 'change-major-mode-hook ',MODE-cmhh))
           (remove-hook 'after-change-major-mode-hook ',MODE-enable-in-buffers)
+           (remove-hook 'fundamental-mode-hook ',MODE-enable-in-buffers)
           (remove-hook 'find-file-hook ',MODE-check-buffers)
           (remove-hook 'change-major-mode-hook ',MODE-cmhh))
 
@@ -366,13 +390,14 @@ See `%s' for more information on %s."
         (dolist (buf ,MODE-buffers)
           (when (buffer-live-p buf)
             (with-current-buffer buf
-              (if ,mode
-                  (unless (eq ,MODE-major-mode major-mode)
-                    (,mode -1)
-                    (,turn-on)
-                    (setq ,MODE-major-mode major-mode))
-                (,turn-on)
-                (setq ,MODE-major-mode major-mode))))))
+               (unless (eq ,MODE-major-mode major-mode)
+                 (if ,mode
+                     (progn
+                       (,mode -1)
+                       (,turn-on)
+                       (setq ,MODE-major-mode major-mode))
+                   (,turn-on)
+                   (setq ,MODE-major-mode major-mode)))))))
        (put ',MODE-enable-in-buffers 'definition-name ',global-mode)
 
        (defun ,MODE-check-buffers ()
@@ -560,5 +585,4 @@ BODY is executed after moving to the destination location."
 
 (provide 'easy-mmode)
 
-;; arch-tag: d48a5250-6961-4528-9cb0-3c9ea042a66a
 ;;; easy-mmode.el ends here