Limit number of GnuTLS handshakes per connection.
[bpt/emacs.git] / lisp / emacs-lisp / easy-mmode.el
index 5a21946..88698a1 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-2012  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,34 @@ 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 toggle command MODE and (by default) a control variable
+MODE (you can override this with the :variable keyword, see below).
 DOC is the documentation for the mode toggle command.
+
+The defined mode command takes one optional (prefix) argument.
+Interactively with no prefix argument it toggles the mode.
+With a prefix argument, it enables the mode if the argument is
+positive and otherwise disables it.  When called from Lisp, it
+enables the mode if the argument is omitted or nil, and toggles
+the mode if the argument is `toggle'.  If DOC is nil this
+function adds a basic doc-string stating these facts.
+
 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 you supply a KEYMAP
+  argument that is not a symbol, this macro defines the variable
+  MODE-map and gives it the value that KEYMAP specifies.
+
+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
@@ -113,14 +122,21 @@ BODY contains code to execute each time the mode is activated or deactivated.
                buffer-local, so don't make the variable MODE buffer-local.
                By default, the mode is buffer-local.
 :init-value VAL        Same as the INIT-VALUE argument.
+               Not used if you also specify :variable.
 :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.
+:variable PLACE        The location to use instead of the variable MODE to store
+               the state of the mode.  This can be simply a different
+               named variable, or more generally anything that can be used
+               with the CL macro `setf'.  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 one argument,
+               the new state, and sets it.  If you specify a :variable,
+               this function does not define a MODE variable (nor any of
+               the terms used in :variable).
+:after-hook     A single lisp form which is evaluated after the mode hooks
+                have been run.  It should not be quoted.
 
 For example, you could write
   (define-minor-mode foo-mode \"If enabled, foo on you!\"
@@ -156,10 +172,11 @@ For example, you could write
          (setter nil)            ;The function (if any) to set the mode var.
          (modefun mode)          ;The minor mode function name we're defining.
         (require t)
+        (after-hook nil)
         (hook (intern (concat mode-name "-hook")))
         (hook-on (intern (concat mode-name "-on-hook")))
         (hook-off (intern (concat mode-name "-off-hook")))
-        keyw keymap-sym)
+        keyw keymap-sym tmp)
 
     ;; Check keys.
     (while (keywordp (setq keyw (car body)))
@@ -176,11 +193,14 @@ For example, you could write
        (:require (setq require (pop body)))
        (:keymap (setq keymap (pop body)))
         (:variable (setq variable (pop body))
-         (if (not (functionp (cdr-safe variable)))
+         (if (not (and (setq tmp (cdr-safe variable))
+                       (or (symbolp tmp)
+                           (functionp tmp))))
              ;; PLACE is not of the form (GET . SET).
              (setq mode variable)
            (setq mode (car variable))
            (setq setter (cdr variable))))
+       (:after-hook (setq after-hook (pop body)))
        (t (push keyw extra-keywords) (push (pop body) extra-keywords))))
 
     (setq keymap-sym (if (and keymap (symbolp keymap)) keymap
@@ -197,6 +217,7 @@ 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
@@ -231,10 +252,10 @@ or call the function `%s'."))))
        (defun ,modefun (&optional arg ,@extra-args)
         ,(or doc
              (format (concat "Toggle %s on or off.
-Interactively, with no prefix argument, toggle the mode.
-With universal prefix ARG turn mode on.
-With zero or negative ARG turn mode off.
-\\{%s}") pretty-name keymap-sym))
+With a prefix argument ARG, enable %s if ARG is
+positive, and disable it otherwise.  If called from Lisp, enable
+the mode if ARG is omitted or nil, and toggle it if ARG is `toggle'.
+\\{%s}") pretty-name pretty-name keymap-sym))
         ;; Use `toggle' rather than (if ,mode 0 1) so that using
         ;; repeat-command still does the toggling correctly.
         (interactive (list (or current-prefix-arg 'toggle)))
@@ -258,7 +279,8 @@ With zero or negative ARG turn mode off.
                               (not (equal ,last-message
                                           (current-message))))
                    (message ,(format "%s %%sabled" pretty-name)
-                            (if ,mode "en" "dis"))))))
+                            (if ,mode "en" "dis")))))
+          ,@(when after-hook `(,after-hook)))
         (force-mode-line-update)
         ;; Return the new setting.
         ,mode)
@@ -273,7 +295,7 @@ 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)))
 
        ,(if (not (symbolp mode))
@@ -284,7 +306,7 @@ With zero or negative ARG turn mode off.
                            ,(if keymap keymap-sym
                                 `(if (boundp ',keymap-sym) ,keymap-sym))
                              nil
-                             ,(unless (eq mode modefun) 'modefun)))))))
+                             ,(unless (eq mode modefun) `',modefun)))))))
 \f
 ;;;
 ;;; make global minor mode
@@ -349,14 +371,16 @@ call another major mode in their body."
        (define-minor-mode ,global-mode
         ;; Very short lines to avoid too long lines in the generated
         ;; doc string.
-        ,(format "Toggle %s in every possible buffer.
-With prefix ARG, turn %s on if and only if
-ARG is positive.
+        ,(format "Toggle %s in all buffers.
+With prefix ARG, enable %s if ARG is positive;
+otherwise, disable it.  If called from Lisp, enable the mode if
+ARG is omitted or nil.
+
 %s is enabled in all buffers where
 \`%s' would do it.
 See `%s' for more information on %s."
-                 pretty-name pretty-global-name pretty-name turn-on
-                 mode pretty-name)
+                 pretty-name pretty-global-name
+                 pretty-name turn-on mode pretty-name)
         :global t ,@group ,@(nreverse extra-keywords)
 
         ;; Setup hook to handle future mode changes and new buffers.
@@ -364,11 +388,13 @@ 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 'change-major-mode-after-body-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 'change-major-mode-after-body-hook
+                       ',MODE-enable-in-buffers)
           (remove-hook 'find-file-hook ',MODE-check-buffers)
           (remove-hook 'change-major-mode-hook ',MODE-cmhh))
 
@@ -584,5 +610,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