]> code.delx.au - gnu-emacs/blobdiff - lisp/subr.el
(add-minor-mode): Don't eval NAME.
[gnu-emacs] / lisp / subr.el
index 29af26732dfd250a70683e1e524e9db4e5b24299..4d0cef6a08747944c69865aceb98d232d45ce114 100644 (file)
@@ -135,6 +135,22 @@ If N is bigger than the length of X, return X."
       (setq x (cdr x)))
     x))
 
+(defun remove (elt seq)
+  "Return a copy of SEQ with all occurences of ELT removed.
+SEQ must be a list, vector, or string.  The comparison is done with `equal'."
+  (if (nlistp seq)
+      ;; If SEQ isn't a list, there's no need to copy SEQ because
+      ;; `delete' will return a new object.
+      (delete elt seq)
+    (delete elt (copy-sequence seq))))
+
+(defun remq (elt list)
+  "Return a copy of LIST with all occurences of ELT removed.
+The comparison is done with `eq'."
+  (if (memq elt list)
+      (delq elt (copy-sequence list))
+    list))
+
 (defun assoc-default (key alist &optional test default)
   "Find object KEY in a pseudo-alist ALIST.
 ALIST is a list of conses or objects.  Each element (or the element's car,
@@ -174,6 +190,18 @@ Unibyte strings are converted to multibyte for comparison."
          (setq element (car alist)))
       (setq alist (cdr alist)))
     element))
+
+(defun member-ignore-case (elt list)
+  "Like `member', but ignores differences in case and text representation.
+ELT must be a string.  Upper-case and lower-case letters are treated as equal.
+Unibyte strings are converted to multibyte for comparison."
+  (let (element)
+    (while (and list (not element))
+      (if (eq t (compare-strings elt 0 nil (car list) 0 nil t))
+         (setq element (car list)))
+      (setq list (cdr list)))
+      element))
+
 \f
 ;;;; Keymap support.
 
@@ -214,8 +242,15 @@ but optional second arg NODIGITS non-nil treats them like other chars."
 (defun substitute-key-definition (olddef newdef keymap &optional oldmap prefix)
   "Replace OLDDEF with NEWDEF for any keys in KEYMAP now defined as OLDDEF.
 In other words, OLDDEF is replaced with NEWDEF where ever it appears.
-If optional fourth argument OLDMAP is specified, we redefine
+Alternatively, if optional fourth argument OLDMAP is specified, we redefine
 in KEYMAP as NEWDEF those chars which are defined as OLDDEF in OLDMAP."
+  ;; Don't document PREFIX in the doc string because we don't want to
+  ;; advertise it.  It's meant for recursive calls only.  Here's its
+  ;; meaning
+  
+  ;; If optional argument PREFIX is specified, it should be a key
+  ;; prefix, a string.  Redefined bindings will then be bound to the
+  ;; original key, with PREFIX added at the front.
   (or prefix (setq prefix ""))
   (let* ((scan (or oldmap keymap))
         (vec1 (vector nil))
@@ -596,8 +631,8 @@ as returned by the `event-start' and `event-end' functions."
 (defalias 'define-function 'defalias)
 
 (defalias 'sref 'aref)
-(make-obsolete 'sref 'aref)
-(make-obsolete 'char-bytes "Now this function always returns 1")
+(make-obsolete 'sref 'aref "20.4")
+(make-obsolete 'char-bytes "Now this function always returns 1" "20.4")
 
 ;; Some programs still use this as a function.
 (defun baud-rate ()
@@ -623,6 +658,7 @@ Please convert your programs to use the variable `baud-rate' directly."
 (defalias 'search-backward-regexp (symbol-function 're-search-backward))
 (defalias 'int-to-string 'number-to-string)
 (defalias 'store-match-data 'set-match-data)
+;; These are the XEmacs names:
 (defalias 'point-at-eol 'line-end-position)
 (defalias 'point-at-bol 'line-beginning-position)
 
@@ -668,7 +704,7 @@ FUNCTION is added at the end.
 
 The optional fourth argument, LOCAL, if non-nil, says to modify
 the hook's buffer-local value rather than its default value.
-This makes no difference if the hook is not buffer-local.
+This makes the hook buffer-local if needed.
 To make a hook variable buffer-local, always use
 `make-local-hook', not `make-local-variable'.
 
@@ -677,32 +713,23 @@ HOOK is void, it is first set to nil.  If HOOK's value is a single
 function, it is changed to a list of functions."
   (or (boundp hook) (set hook nil))
   (or (default-boundp hook) (set-default hook nil))
-  ;; If the hook value is a single function, turn it into a list.
-  (let ((old (symbol-value hook)))
-    (if (or (not (listp old)) (eq (car old) 'lambda))
-       (set hook (list old))))
-  (if (or local
-         ;; Detect the case where make-local-variable was used on a hook
-         ;; and do what we used to do.
-         (and (local-variable-if-set-p hook)
-              (not (memq t (symbol-value hook)))))
-      ;; Alter the local value only.
-      (or (if (or (consp function) (byte-code-function-p function))
-             (member function (symbol-value hook))
-           (memq function (symbol-value hook)))
-         (set hook 
-              (if append
-                  (append (symbol-value hook) (list function))
-                (cons function (symbol-value hook)))))
-    ;; Alter the global value (which is also the only value,
-    ;; if the hook doesn't have a local value).
-    (or (if (or (consp function) (byte-code-function-p function))
-           (member function (default-value hook))
-         (memq function (default-value hook)))
-       (set-default hook 
-                    (if append
-                        (append (default-value hook) (list function))
-                      (cons function (default-value hook)))))))
+  (if local (make-local-hook hook)
+    ;; Detect the case where make-local-variable was used on a hook
+    ;; and do what we used to do.
+    (unless (and (consp (symbol-value hook)) (memq t (symbol-value hook)))
+      (setq local t)))
+  (let ((hook-value (if local (symbol-value hook) (default-value hook))))
+    ;; If the hook value is a single function, turn it into a list.
+    (when (or (not (listp hook-value)) (eq (car hook-value) 'lambda))
+      (setq hook-value (list hook-value)))
+    ;; Do the actual addition if necessary
+    (unless (member function hook-value)
+      (setq hook-value
+           (if append
+               (append hook-value (list function))
+             (cons function hook-value))))
+    ;; Set the actual variable
+    (if local (set hook hook-value) (set-default hook hook-value))))
 
 (defun remove-hook (hook function &optional local)
   "Remove from the value of HOOK the function FUNCTION.
@@ -712,34 +739,27 @@ list of hooks to run in HOOK, then nothing is done.  See `add-hook'.
 
 The optional third argument, LOCAL, if non-nil, says to modify
 the hook's buffer-local value rather than its default value.
-This makes no difference if the hook is not buffer-local.
+This makes the hook buffer-local if needed.
 To make a hook variable buffer-local, always use
 `make-local-hook', not `make-local-variable'."
-  (if (or (not (boundp hook))          ;unbound symbol, or
-         (not (default-boundp hook))
-         (null (symbol-value hook))    ;value is nil, or
-         (null function))              ;function is nil, then
-      nil                              ;Do nothing.
-    (if (or local
-           ;; Detect the case where make-local-variable was used on a hook
-           ;; and do what we used to do.
-           (and (local-variable-p hook)
-                 (consp (symbol-value hook))
-                 (not (memq t (symbol-value hook)))))
-       (let ((hook-value (symbol-value hook)))
-         (if (consp hook-value)
-             (if (member function hook-value)
-                 (setq hook-value (delete function (copy-sequence hook-value))))
-           (if (equal hook-value function)
-               (setq hook-value nil)))
-         (set hook hook-value))
-      (let ((hook-value (default-value hook)))
-       (if (and (consp hook-value) (not (functionp hook-value)))
-           (if (member function hook-value)
-               (setq hook-value (delete function (copy-sequence hook-value))))
-         (if (equal hook-value function)
-             (setq hook-value nil)))
-       (set-default hook hook-value)))))
+  (or (boundp hook) (set hook nil))
+  (or (default-boundp hook) (set-default hook nil))
+  (if local (make-local-hook hook)
+    ;; Detect the case where make-local-variable was used on a hook
+    ;; and do what we used to do.
+    (unless (and (consp (symbol-value hook)) (memq t (symbol-value hook)))
+      (setq local t)))
+  (let ((hook-value (if local (symbol-value hook) (default-value hook))))
+    ;; Remove the function, for both the list and the non-list cases.
+    (if (or (not (listp hook-value)) (eq (car hook-value) 'lambda))
+       (if (equal hook-value function) (setq hook-value nil))
+      (setq hook-value (delete function (copy-sequence hook-value))))
+    ;; If the function is on the global hook, we need to shadow it locally
+    ;;(when (and local (member function (default-value hook))
+    ;;        (not (member (cons 'not function) hook-value)))
+    ;;  (push (cons 'not function) hook-value))
+    ;; Set the actual variable
+    (if local (set hook hook-value) (set-default hook hook-value))))
 
 (defun add-to-list (list-var element)
   "Add to the value of LIST-VAR the element ELEMENT if it isn't there yet.
@@ -872,7 +892,7 @@ Optional DEFAULT is a default password to use instead of empty input."
       (while (progn (message "%s%s"
                             prompt
                             (make-string (length pass) ?.))
-                   (setq c (read-char nil t))
+                   (setq c (read-char-exclusive nil t))
                    (and (/= c ?\r) (/= c ?\n) (/= c ?\e)))
        (if (= c ?\C-u)
            (setq pass "")
@@ -1089,6 +1109,35 @@ in BODY."
         . ,body)
      (combine-after-change-execute)))
 
+
+(defvar combine-run-hooks t
+  "List of hooks delayed. Or t if we're not delaying hooks.")
+
+(defmacro combine-run-hooks (&rest body)
+  "Execute BODY, but delay any `run-hooks' until the end."
+  (let ((saved-combine-run-hooks (make-symbol "saved-combine-run-hooks"))
+       (saved-run-hooks (make-symbol "saved-run-hooks")))
+    `(let ((,saved-combine-run-hooks combine-run-hooks)
+          (,saved-run-hooks (symbol-function 'run-hooks)))
+       (unwind-protect
+          (progn
+            ;; If we're not delaying hooks yet, setup the delaying mode
+            (unless (listp combine-run-hooks)
+              (setq combine-run-hooks nil)
+              (fset 'run-hooks
+                    ,(lambda (&rest hooks)
+                       (setq combine-run-hooks
+                             (append combine-run-hooks hooks)))))
+            ,@body)
+        ;; If we were not already delaying, then it's now time to set things
+        ;; back to normal and to execute the delayed hooks.
+        (unless (listp ,saved-combine-run-hooks)
+          (setq ,saved-combine-run-hooks combine-run-hooks)
+          (fset 'run-hooks ,saved-run-hooks)
+          (setq combine-run-hooks t)
+          (apply 'run-hooks ,saved-combine-run-hooks))))))
+
+
 (defmacro with-syntax-table (table &rest body)
   "Evaluate BODY with syntax table of current buffer set to a copy of TABLE.
 The syntax table of the current buffer is saved, BODY is evaluated, and the
@@ -1196,8 +1245,8 @@ Unless optional argument INPLACE is non-nil, return a new string."
          (aset newstr i tochar)))
     newstr))
 
-(defun replace-regexps-in-string (regexp rep string &optional
-                                        fixedcase literal subexp start)
+(defun replace-regexp-in-string (regexp rep string &optional
+                                       fixedcase literal subexp start)
   "Replace all matches for REGEXP with REP in STRING.
 
 Return a new string containing the replacements.
@@ -1211,7 +1260,11 @@ function.  If it is a function it is applied to each match to generate
 the replacement passed to `replace-match'; the match-data at this
 point are such that match 0 is the function's argument.
 
-To replace a single match, make REGEXP match up to \\'."
+To replace only the first match (if any), make REGEXP match up to \\'
+and replace a sub-expression, e.g.
+  (replace-regexp-in-string \"\\(foo\\).*\\'\" \"bar\" \" foo foo\" nil nil 1)
+    => \" bar foo\"
+"
 
   ;; To avoid excessive consing from multiple matches in long strings,
   ;; don't just call `replace-match' continually.  Walk down the
@@ -1440,4 +1493,80 @@ If DIR-FLAG is non-nil, create a new empty directory instead of a file."
       nil)
     file))
 
+\f
+(defun add-minor-mode (toggle name &optional keymap after toggle-fun)
+  "Register a new minor mode.
+
+This is an XEmacs-compatibility function.  Use `define-minor-mode' instead.
+
+TOGGLE is a symbol which is the name of a buffer-local variable that
+is toggled on or off to say whether the minor mode is active or not.
+
+NAME specifies what will appear in the mode line when the minor mode
+is active.  NAME should be either a string starting with a space, or a
+symbol whose value is such a string.
+
+Optional KEYMAP is the keymap for the minor mode that will be added
+to `minor-mode-map-alist'.
+
+Optional AFTER specifies that TOGGLE should be added after AFTER
+in `minor-mode-alist'.
+
+Optional TOGGLE-FUN is an interactive function to toggle the mode.
+It defaults to (and should by convention be) TOGGLE.
+
+If TOGGLE has a non-nil `:included' property, an entry for the mode is
+included in the mode-line minor mode menu.
+If TOGGLE has a `:menu-tag', that is used for the menu item's label."
+  (unless toggle-fun (setq toggle-fun toggle))
+  ;; Add the toggle to the minor-modes menu if requested.
+  (when (get toggle :included)
+    (define-key mode-line-mode-menu
+      (vector toggle)
+      (list 'menu-item
+           (or (get toggle :menu-tag)
+               (if (stringp name) name (symbol-name toggle)))
+           toggle-fun
+           :button (cons :toggle toggle))))
+  ;; Add the name to the minor-mode-alist.
+  (when name
+    (let ((existing (assq toggle minor-mode-alist)))
+      (when (and (stringp name) (not (get-text-property 0 'local-map name)))
+       (setq name
+             (apply 'propertize name
+                    'local-map (make-mode-line-mouse2-map toggle-fun)
+                    (unless (get-text-property 0 'help-echo name)
+                      (list 'help-echo
+                            (format "mouse-2: turn off %S" toggle))))))
+      (if existing
+         (setcdr existing (list name))
+       (let ((tail minor-mode-alist) found)
+         (while (and tail (not found))
+           (if (eq after (caar tail))
+               (setq found tail)
+             (setq tail (cdr tail))))
+         (if found
+             (let ((rest (cdr found)))
+               (setcdr found nil)
+               (nconc found (list (list toggle name)) rest))
+           (setq minor-mode-alist (cons (list toggle name)
+                                        minor-mode-alist)))))))
+  ;; Add the map to the minor-mode-map-alist.    
+  (when keymap
+    (let ((existing (assq toggle minor-mode-map-alist)))
+      (if existing
+         (setcdr existing keymap)
+       (let ((tail minor-mode-map-alist) found)
+         (while (and tail (not found))
+           (if (eq after (caar tail))
+               (setq found tail)
+             (setq tail (cdr tail))))
+         (if found
+             (let ((rest (cdr found)))
+               (setcdr found nil)
+               (nconc found (list (cons toggle keymap)) rest))
+           (setq minor-mode-map-alist (cons (cons toggle keymap)
+                                            minor-mode-map-alist))))))))
+
+
 ;;; subr.el ends here