]> code.delx.au - gnu-emacs/blobdiff - lisp/emacs-lisp/easy-mmode.el
Add a provide statement.
[gnu-emacs] / lisp / emacs-lisp / easy-mmode.el
index 8d814ea1e3f17be7c8165fce993200dfbdd9528d..b6b91710ed426cd5187d5936bb633c52c35e9318 100644 (file)
@@ -1,6 +1,6 @@
 ;;; easy-mmode.el --- easy definition for major and minor modes
 
-;; Copyright (C) 1997, 2000, 2001 Free Software Foundation, Inc.
+;; Copyright (C) 1997,2000,01,02,03,2004  Free Software Foundation, Inc.
 
 ;; Author: Georges Brun-Cottan <Georges.Brun-Cottan@inria.fr>
 ;; Maintainer: Stefan Monnier <monnier@gnu.org>
@@ -88,14 +88,30 @@ used (see below).
 
 BODY contains code that will be executed each time the mode is (dis)activated.
   It will be executed after any toggling but before running the hooks.
-  BODY can start with a list of CL-style keys specifying additional arguments.
-  The following keyword arguments are supported:
-:group GROUP   Group name to use for any generated `defcustom'.
+  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):
+:group GROUP   Custom group name to use in all generated `defcustom' forms.
 :global GLOBAL If non-nil specifies that the minor mode is not meant to be
-               buffer-local.  By default, the variable is made buffer-local.
+               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.
 :lighter SPEC  Same as the LIGHTER argument.
-:require SYM   Same as defcustom's :require argument."
+:keymap MAP    Same as the KEYMAP argument.
+:require SYM   Same as in `defcustom'.
+
+For example, you could write
+  (define-minor-mode foo-mode \"If enabled, foo on you!\"
+    :lighter \" Foo\" :require 'foo :global t :group 'hassle :version \"27.5\"
+    ...BODY CODE...)"
+  (declare (debug (&define name stringp
+                          [&optional [&not keywordp] sexp
+                           &optional [&not keywordp] sexp
+                           &optional [&not keywordp] sexp]
+                          [&rest [keywordp sexp]]
+                          def-body)))
+
   ;; Allow skipping the first three args.
   (cond
    ((keywordp init-value)
@@ -110,29 +126,35 @@ BODY contains code that will be executed each time the mode is (dis)activated.
         (globalp nil)
         (group nil)
         (extra-args nil)
+        (extra-keywords nil)
         (require t)
-        (keymap-sym (if (and keymap (symbolp keymap)) keymap
-                      (intern (concat mode-name "-map"))))
         (hook (intern (concat mode-name "-hook")))
         (hook-on (intern (concat mode-name "-on-hook")))
-        (hook-off (intern (concat mode-name "-off-hook"))))
+        (hook-off (intern (concat mode-name "-off-hook")))
+        keyw keymap-sym)
 
     ;; Check keys.
-    (while (keywordp (car body))
-      (case (pop body)
+    (while (keywordp (setq keyw (car body)))
+      (setq body (cdr body))
+      (case keyw
        (:init-value (setq init-value (pop body)))
        (:lighter (setq lighter (pop body)))
        (:global (setq globalp (pop body)))
        (:extra-args (setq extra-args (pop body)))
        (:group (setq group (nconc group (list :group (pop body)))))
        (:require (setq require (pop body)))
-       (t (pop body))))
+       (:keymap (setq keymap (pop body)))
+       (t (push keyw extra-keywords) (push (pop body) extra-keywords))))
+
+    (setq keymap-sym (if (and keymap (symbolp keymap)) keymap
+                      (intern (concat mode-name "-map"))))
 
     (unless group
       ;; We might as well provide a best-guess default group.
       (setq group
-           `(:group ',(intern (replace-regexp-in-string "-mode\\'" ""
-                                                        mode-name)))))
+           `(:group ',(or (custom-current-group)
+                          (intern (replace-regexp-in-string
+                                   "-mode\\'" "" mode-name))))))
 
     `(progn
        ;; Define the variable to enable or disable the mode.
@@ -151,7 +173,7 @@ See the command `%s' for a description of this minor-mode.
 Setting this variable directly does not take effect;
 use either \\[customize] or the function `%s'."
                        pretty-name mode mode)
-              :set (lambda (symbol value) (funcall symbol (or value 0)))
+              :set 'custom-set-minor-mode
               :initialize 'custom-initialize-default
               ,@group
               :type 'boolean
@@ -160,7 +182,8 @@ use either \\[customize] or the function `%s'."
                  ((not (eq require t)) `(:require ,require))
                  (t `(:require
                       ',(intern (file-name-nondirectory
-                                 (file-name-sans-extension curfile)))))))))
+                                 (file-name-sans-extension curfile))))))
+              ,@(nreverse extra-keywords))))
 
        ;; The actual function.
        (defun ,mode (&optional arg ,@extra-args)
@@ -186,11 +209,12 @@ With zero or negative ARG turn mode off.
         ,@body
         ;; The on/off hooks are here for backward compatibility only.
         (run-hooks ',hook (if ,mode ',hook-on ',hook-off))
-        (if (interactive-p)
+        (if (called-interactively-p)
             (progn
               ,(if globalp `(customize-mark-as-set ',mode))
-              (message ,(format "%s %%sabled" pretty-name)
-                       (if ,mode "en" "dis"))))
+              (unless (current-message)
+                (message ,(format "%s %%sabled" pretty-name)
+                         (if ,mode "en" "dis")))))
         (force-mode-line-update)
         ;; Return the new setting.
         ,mode)
@@ -202,7 +226,7 @@ With zero or negative ARG turn mode off.
        ;; The toggle's hook.
        (defcustom ,hook nil
         ,(format "Hook run at the end of function `%s'." mode-name)
-        :group ,(cadr group)
+        ,@group
         :type 'hook)
 
        ;; Define the minor-mode keymap.
@@ -218,7 +242,7 @@ With zero or negative ARG turn mode off.
                       ,(if keymap keymap-sym
                          `(if (boundp ',keymap-sym)
                               (symbol-value ',keymap-sym))))
-       
+
        ;; If the mode is global, call the function according to the default.
        ,(if globalp
            `(if (and load-file-name (not (equal ,init-value ,mode)))
@@ -254,8 +278,10 @@ KEYS is a list of CL-style keyword arguments:
     (unless group
       ;; We might as well provide a best-guess default group.
       (setq group
-           `(:group ',(intern (replace-regexp-in-string "-mode\\'" ""
-                                                        (symbol-name mode))))))
+           `(:group ',(or (custom-current-group)
+                          (intern (replace-regexp-in-string
+                                   "-mode\\'" "" (symbol-name mode)))))))
+
     `(progn
        ;; The actual global minor-mode
        (define-minor-mode ,global-mode
@@ -325,7 +351,7 @@ KEY and BINDINGS are suitable for `define-key'.
 Optional NAME is passed to `make-sparse-keymap'.
 Optional map M can be used to modify an existing map.
 ARGS is a list of additional keyword arguments."
-  (let (inherit dense suppress)
+  (let (inherit dense)
     (while args
       (let ((key (pop args))
            (val (pop args)))
@@ -334,7 +360,6 @@ ARGS is a list of additional keyword arguments."
         (:dense (setq dense val))
         (:inherit (setq inherit val))
         (:group)
-        ;;((eq key :suppress) (setq suppress val))
         (t (message "Unknown argument %s in defmap" key)))))
     (unless (keymapp m)
       (setq bs (append m bs))
@@ -394,7 +419,7 @@ CSS contains a list of syntax specifications of the form (CHAR . SYNTAX)."
 ;;; easy-mmode-define-navigation
 ;;;
 
-(defmacro easy-mmode-define-navigation (base re &optional name endfun)
+(defmacro easy-mmode-define-navigation (base re &optional name endfun narrowfun)
   "Define BASE-next and BASE-prev to navigate in the buffer.
 RE determines the places the commands should move point to.
 NAME should describe the entities matched by RE.  It is used to build
@@ -402,11 +427,20 @@ NAME should describe the entities matched by RE.  It is used to build
 BASE-next also tries to make sure that the whole entry is visible by
   searching for its end (by calling ENDFUN if provided or by looking for
   the next entry) and recentering if necessary.
-ENDFUN should return the end position (with or without moving point)."
+ENDFUN should return the end position (with or without moving point).
+NARROWFUN non-nil means to check for narrowing before moving, and if
+found, do widen first and then call NARROWFUN with no args after moving."
   (let* ((base-name (symbol-name base))
         (prev-sym (intern (concat base-name "-prev")))
-        (next-sym (intern (concat base-name "-next"))))
-    (unless name (setq name (symbol-name base-name)))
+        (next-sym (intern (concat base-name "-next")))
+         (check-narrow-maybe
+         (when narrowfun
+           '(setq was-narrowed
+                  (prog1 (or (< (- (point-max) (point-min)) (buffer-size)))
+                    (widen)))))
+         (re-narrow-maybe (when narrowfun
+                            `(when was-narrowed (,narrowfun)))))
+    (unless name (setq name base-name))
     `(progn
        (add-to-list 'debug-ignored-errors
                    ,(concat "^No \\(previous\\|next\\) " (regexp-quote name)))
@@ -415,28 +449,36 @@ ENDFUN should return the end position (with or without moving point)."
         (interactive)
         (unless count (setq count 1))
         (if (< count 0) (,prev-sym (- count))
-          (if (looking-at ,re) (incf count))
-          (if (not (re-search-forward ,re nil t count))
-              (if (looking-at ,re)
-                  (goto-char (or ,(if endfun `(,endfun)) (point-max)))
-                (error ,(format "No next %s" name)))
-            (goto-char (match-beginning 0))
-            (when (and (eq (current-buffer) (window-buffer (selected-window)))
-                       (interactive-p))
-              (let ((endpt (or (save-excursion
-                                 ,(if endfun `(,endfun)
-                                    `(re-search-forward ,re nil t 2)))
-                               (point-max))))
-                (unless (pos-visible-in-window-p endpt nil t)
-                  (recenter '(0))))))))
+          (if (looking-at ,re) (setq count (1+ count)))
+           (let (was-narrowed)
+             ,check-narrow-maybe
+             (if (not (re-search-forward ,re nil t count))
+                 (if (looking-at ,re)
+                     (goto-char (or ,(if endfun `(,endfun)) (point-max)))
+                   (error "No next %s" ,name))
+               (goto-char (match-beginning 0))
+               (when (and (eq (current-buffer) (window-buffer (selected-window)))
+                          (interactive-p))
+                 (let ((endpt (or (save-excursion
+                                    ,(if endfun `(,endfun)
+                                       `(re-search-forward ,re nil t 2)))
+                                  (point-max))))
+                   (unless (pos-visible-in-window-p endpt nil t)
+                     (recenter '(0))))))
+             ,re-narrow-maybe)))
        (defun ,prev-sym (&optional count)
         ,(format "Go to the previous COUNT'th %s" (or name base-name))
         (interactive)
         (unless count (setq count 1))
         (if (< count 0) (,next-sym (- count))
-          (unless (re-search-backward ,re nil t count)
-            (error ,(format "No previous %s" name))))))))
+           (let (was-narrowed)
+             ,check-narrow-maybe
+             (unless (re-search-backward ,re nil t count)
+               (error "No previous %s" ,name))
+             ,re-narrow-maybe))))))
+
 
 (provide 'easy-mmode)
 
+;;; arch-tag: d48a5250-6961-4528-9cb0-3c9ea042a66a
 ;;; easy-mmode.el ends here