;;; subr.el --- basic lisp subroutines for Emacs
;; Copyright (C) 1985, 1986, 1992, 1994, 1995, 1999, 2000, 2001, 2002, 2003,
-;; 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;; 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
;; Maintainer: FSF
;; Keywords: internal
;;; Commentary:
;;; Code:
+
(defvar custom-declare-variable-list nil
"Record `defcustom' calls made before `custom.el' is loaded to handle them.
Each element of this list holds the arguments to one call to `defcustom'.")
\(declare-function c-end-of-defun \"progmodes/cc-cmds.el\"
\(&optional arg))
-For more information, see Info node `elisp(Declaring Functions)'."
+For more information, see Info node `(elisp)Declaring Functions'."
;; Does nothing - byte-compile-declare-function does the work.
nil)
+
\f
;;;; Basic Lisp macros.
(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,
-if it is a cons) is compared with KEY by evaluating (TEST (car elt) KEY).
-If that is non-nil, the element matches;
-then `assoc-default' returns the element's cdr, if it is a cons,
-or DEFAULT if the element is not a cons.
+ALIST is a list of conses or objects. Each element
+ (or the element's car, if it is a cons) is compared with KEY by
+ calling TEST, with two arguments: (i) the element or its car,
+ and (ii) KEY.
+If that is non-nil, the element matches; then `assoc-default'
+ returns the element's cdr, if it is a cons, or DEFAULT if the
+ element is not a cons.
If no element matches, the value is nil.
If TEST is omitted or nil, `equal' is used."
(defun keymap-canonicalize (map)
"Return an equivalent keymap, without inheritance."
(let ((bindings ())
- (ranges ()))
+ (ranges ())
+ (prompt (keymap-prompt map)))
(while (keymapp map)
(setq map (map-keymap-internal
(lambda (key item)
(push (cons key item) ranges)
(push (cons key item) bindings)))
map)))
- (setq map (funcall (if ranges 'make-keymap 'make-sparse-keymap)
- (keymap-prompt map)))
+ (setq map (funcall (if ranges 'make-keymap 'make-sparse-keymap) prompt))
(dolist (binding ranges)
;; Treat char-ranges specially.
(define-key map (vector (car binding)) (cdr binding)))
(cons (scroll-bar-scale pair (window-width window)) 0))
(t
(let* ((frame (if (framep window) window (window-frame window)))
- (x (/ (car pair) (frame-char-width frame)))
- (y (/ (cdr pair) (+ (frame-char-height frame)
- (or (frame-parameter frame 'line-spacing)
- ;; FIXME: Why the `default'?
- (default-value 'line-spacing)
- 0)))))
- (cons x y))))))
+ ;; FIXME: This should take line-spacing properties on
+ ;; newlines into account.
+ (spacing (when (display-graphic-p frame)
+ (or (with-current-buffer (window-buffer window)
+ line-spacing)
+ (frame-parameter frame 'line-spacing)))))
+ (cond ((floatp spacing)
+ (setq spacing (truncate (* spacing
+ (frame-char-height frame)))))
+ ((null spacing)
+ (setq spacing 0)))
+ (cons (/ (car pair) (frame-char-width frame))
+ (/ (cdr pair) (+ (frame-char-height frame) spacing))))))))
(defun posn-actual-col-row (position)
"Return the actual column and row in POSITION, measured in characters.
(define-obsolete-function-alias 'string-to-int 'string-to-number "22.1")
(make-obsolete 'char-bytes "now always returns 1." "20.4")
+(make-obsolete 'forward-point "use (+ (point) N) instead." "23.1")
(defun insert-string (&rest args)
"Mocklisp-compatibility insert function.
(make-obsolete 'focus-frame "it does nothing." "22.1")
(defalias 'unfocus-frame 'ignore "")
(make-obsolete 'unfocus-frame "it does nothing." "22.1")
-(make-obsolete 'make-variable-frame-local "use a frame-parameter instead." "22.2")
+(make-obsolete 'make-variable-frame-local
+ "explicitly check for a frame-parameter instead." "22.2")
\f
;;;; Obsolescence declarations for variables, and aliases.
(defvaralias 'x-sent-selection-hooks 'x-sent-selection-functions)
(make-obsolete-variable 'x-sent-selection-hooks
'x-sent-selection-functions "22.1")
-;; This was introduced in 21.4 for pre-unicode unification and was rendered
-;; obsolete by the use of Unicode internally in 23.1.
+
+;; This was introduced in 21.4 for pre-unicode unification. That
+;; usage was rendered obsolete in 23.1 which uses Unicode internally.
+;; Other uses are possible, so this variable is not _really_ obsolete,
+;; but Stefan insists to mark it so.
(make-obsolete-variable 'translation-table-for-input nil "23.1")
(defvaralias 'messages-buffer-max-lines 'message-log-max)
+
+;; These aliases exist in Emacs 19.34, and probably before, but were
+;; only marked as obsolete in 23.1.
+;; The lisp manual (since at least Emacs 21) describes them as
+;; existing "for compatibility with Emacs version 18".
+(define-obsolete-variable-alias 'last-input-char 'last-input-event
+ "at least 19.34")
+(define-obsolete-variable-alias 'last-command-char 'last-command-event
+ "at least 19.34")
+
\f
;;;; Alternate names for functions - these are not being phased out.
(defalias 'search-backward-regexp (symbol-function 're-search-backward))
(defalias 'int-to-string 'number-to-string)
(defalias 'store-match-data 'set-match-data)
+(defalias 'chmod 'set-file-modes)
+(defalias 'mkdir 'make-directory)
;; These are the XEmacs names:
(defalias 'point-at-eol 'line-end-position)
(defalias 'point-at-bol 'line-beginning-position)
;; (setq symbol-file-load-history-loaded t)))
(defun symbol-file (symbol &optional type)
- "Return the input source in which SYMBOL was defined.
-The value is an absolute file name.
-It can also be nil, if the definition is not associated with any file.
-
-If TYPE is nil, then any kind of definition is acceptable.
-If TYPE is `defun' or `defvar', that specifies function
-definition only or variable definition only.
-`defface' specifies a face definition only."
+ "Return the name of the file that defined SYMBOL.
+The value is normally an absolute file name. It can also be nil,
+if the definition is not associated with any file. If SYMBOL
+specifies an autoloaded function, the value can be a relative
+file name without extension.
+
+If TYPE is nil, then any kind of definition is acceptable. If
+TYPE is `defun', `defvar', or `defface', that specifies function
+definition, variable definition, or face definition only."
(if (and (or (null type) (eq type 'defun))
(symbolp symbol) (fboundp symbol)
(eq 'autoload (car-safe (symbol-function symbol))))
(defun locate-library (library &optional nosuffix path interactive-call)
"Show the precise file name of Emacs library LIBRARY.
+LIBRARY should be a relative file name of the library, a string.
+It can omit the suffix (a.k.a. file-name extension) if NOSUFFIX is
+nil (which is the default, see below).
This command searches the directories in `load-path' like `\\[load-library]'
to find the file that `\\[load-library] RET LIBRARY RET' would load.
Optional second arg NOSUFFIX non-nil means don't add suffixes `load-suffixes'
;; bound to some prefix in function-key-map or key-translation-map.
(setq translated
(if (integerp char)
- (char-resolve-modifers char)
+ (char-resolve-modifiers char)
char))
(let ((translation (lookup-key local-function-key-map (vector char))))
(if (arrayp translation)
Optional DEFAULT is a default password to use instead of empty input.
This function echoes `.' for each character that the user types.
-The user ends with RET, LFD, or ESC. DEL or C-h rubs out. C-u kills line.
+
+The user ends with RET, LFD, or ESC. DEL or C-h rubs out.
+C-y yanks the current kill. C-u kills line.
C-g quits; if `inhibit-quit' was non-nil around this function,
then it returns nil if the user types C-g, but quit-flag remains set.
(c 0)
(echo-keystrokes 0)
(cursor-in-echo-area t)
- (message-log-max nil))
+ (message-log-max nil)
+ (stop-keys (list 'return ?\r ?\n ?\e))
+ (rubout-keys (list 'backspace ?\b ?\177)))
(add-text-properties 0 (length prompt)
minibuffer-prompt-properties prompt)
(while (progn (message "%s%s"
prompt
(make-string (length pass) ?.))
- (setq c (read-char-exclusive nil t))
- (and (/= c ?\r) (/= c ?\n) (/= c ?\e)))
+ ;; We used to use read-char-exclusive, but that
+ ;; gives funny behavior when the user presses,
+ ;; e.g., the arrow keys.
+ (setq c (read-event nil t))
+ (not (memq c stop-keys)))
(clear-this-command-keys)
- (if (= c ?\C-u)
- (progn
- (and (arrayp pass) (clear-string pass))
- (setq pass ""))
- (if (and (/= c ?\b) (/= c ?\177))
- (let* ((new-char (char-to-string c))
- (new-pass (concat pass new-char)))
- (and (arrayp pass) (clear-string pass))
- (clear-string new-char)
- (setq c ?\0)
- (setq pass new-pass))
- (if (> (length pass) 0)
- (let ((new-pass (substring pass 0 -1)))
- (and (arrayp pass) (clear-string pass))
- (setq pass new-pass))))))
+ (cond ((memq c rubout-keys) ; rubout
+ (when (> (length pass) 0)
+ (let ((new-pass (substring pass 0 -1)))
+ (and (arrayp pass) (clear-string pass))
+ (setq pass new-pass))))
+ ((not (numberp c)))
+ ((= c ?\C-u) ; kill line
+ (and (arrayp pass) (clear-string pass))
+ (setq pass ""))
+ ((= c ?\C-y) ; yank
+ (let* ((str (condition-case nil
+ (current-kill 0)
+ (error nil)))
+ new-pass)
+ (when str
+ (setq new-pass
+ (concat pass
+ (substring-no-properties str)))
+ (and (arrayp pass) (clear-string pass))
+ (setq c ?\0)
+ (setq pass new-pass))))
+ ((characterp c) ; insert char
+ (let* ((new-char (char-to-string c))
+ (new-pass (concat pass new-char)))
+ (and (arrayp pass) (clear-string pass))
+ (clear-string new-char)
+ (setq c ?\0)
+ (setq pass new-pass)))))
(message nil)
(or pass default "")))))
(dolist (elt handle)
(with-current-buffer (car elt)
(setq elt (cdr elt))
- (let ((old-car
- (if (consp elt) (car elt)))
- (old-cdr
- (if (consp elt) (cdr elt))))
- ;; Temporarily truncate the undo log at ELT.
- (when (consp elt)
- (setcar elt nil) (setcdr elt nil))
- (unless (eq last-command 'undo) (undo-start))
- ;; Make sure there's no confusion.
- (when (and (consp elt) (not (eq elt (last pending-undo-list))))
- (error "Undoing to some unrelated state"))
- ;; Undo it all.
- (save-excursion
- (while (listp pending-undo-list) (undo-more 1)))
- ;; Reset the modified cons cell ELT to its original content.
- (when (consp elt)
- (setcar elt old-car)
- (setcdr elt old-cdr))
- ;; Revert the undo info to what it was when we grabbed the state.
- (setq buffer-undo-list elt)))))
+ (save-restriction
+ ;; Widen buffer temporarily so if the buffer was narrowed within
+ ;; the body of `atomic-change-group' all changes can be undone.
+ (widen)
+ (let ((old-car
+ (if (consp elt) (car elt)))
+ (old-cdr
+ (if (consp elt) (cdr elt))))
+ ;; Temporarily truncate the undo log at ELT.
+ (when (consp elt)
+ (setcar elt nil) (setcdr elt nil))
+ (unless (eq last-command 'undo) (undo-start))
+ ;; Make sure there's no confusion.
+ (when (and (consp elt) (not (eq elt (last pending-undo-list))))
+ (error "Undoing to some unrelated state"))
+ ;; Undo it all.
+ (save-excursion
+ (while (listp pending-undo-list) (undo-more 1)))
+ ;; Reset the modified cons cell ELT to its original content.
+ (when (consp elt)
+ (setcar elt old-car)
+ (setcdr elt old-cdr))
+ ;; Revert the undo info to what it was when we grabbed the state.
+ (setq buffer-undo-list elt))))))
\f
;;;; Display-related functions.
(defvar temp-buffer-show-hook nil
"Normal hook run by `with-output-to-temp-buffer' after displaying the buffer.
When the hook runs, the temporary buffer is current, and the window it
-was displayed in is selected. This hook is normally set up with a
-function to make the buffer read only, and find function names and
-variable names in it, provided the major mode is still Help mode.")
+was displayed in is selected.")
(defvar temp-buffer-setup-hook nil
"Normal hook run by `with-output-to-temp-buffer' at the start.
"~/.emacs.d/")
"Directory beneath which additional per-user Emacs-specific files are placed.
Various programs in Emacs store information in this directory.
-Note that this should end with a directory separator.")
+Note that this should end with a directory separator.
+See also `locate-user-emacs-file'.")
+
+(defun locate-user-emacs-file (new-name &optional old-name)
+ "Return an absolute per-user Emacs-specific file name.
+If OLD-NAME is non-nil and ~/OLD-NAME exists, return ~/OLD-NAME.
+Else return NEW-NAME in `user-emacs-directory', creating the
+directory if it does not exist."
+ (convert-standard-filename
+ (let* ((home (concat "~" (or init-file-user "")))
+ (at-home (and old-name (expand-file-name old-name home))))
+ (if (and at-home (file-readable-p at-home))
+ at-home
+ ;; Make sure `user-emacs-directory' exists,
+ ;; unless we're in batch mode or dumping Emacs
+ (or noninteractive
+ purify-flag
+ (file-accessible-directory-p (directory-file-name user-emacs-directory))
+ (make-directory user-emacs-directory))
+ (expand-file-name new-name user-emacs-directory)))))
\f
;;;; Misc. useful functions.
don't change the volume setting of the sound device.
:device DEVICE - play sound on DEVICE. If not specified,
-a system-dependent default device name is used."
+a system-dependent default device name is used.
+
+Note: :data and :device are currently not supported on Windows."
(if (fboundp 'play-sound-internal)
(play-sound-internal sound)
(error "This Emacs binary lacks sound support")))
(declare-function w32-shell-dos-semantics "w32-fns" nil)
(defun shell-quote-argument (argument)
- "Quote an argument for passing as argument to an inferior shell."
+ "Quote ARGUMENT for passing as argument to an inferior shell."
(if (or (eq system-type 'ms-dos)
(and (eq system-type 'windows-nt) (w32-shell-dos-semantics)))
;; Quote using double quotes, but escape any existing quotes in
(memq object '(nil t)))
(defun field-at-pos (pos)
- "Return the field at position POS, taking stickiness etc into account"
+ "Return the field at position POS, taking stickiness etc into account."
(let ((raw-field (get-char-property (field-beginning pos) 'field)))
(if (eq raw-field 'boundary)
(get-char-property (1- (field-end pos)) 'field)
Wildcards and redirection are handled as usual in the shell.
\(fn NAME BUFFER COMMAND &rest COMMAND-ARGS)"
- (cond
- ((eq system-type 'vax-vms)
- (apply 'start-process name buffer args))
;; We used to use `exec' to replace the shell with the command,
;; but that failed to handle (...) and semicolon, etc.
- (t
- (start-process name buffer shell-file-name shell-command-switch
- (mapconcat 'identity args " ")))))
+ (start-process name buffer shell-file-name shell-command-switch
+ (mapconcat 'identity args " ")))
(defun start-file-process-shell-command (name buffer &rest args)
"Start a program in a subprocess. Return the process object for it.
Otherwise it waits for COMMAND to terminate and returns a numeric exit
status or a signal description string.
If you quit, the process is killed with SIGINT, or SIGKILL if you quit again."
- (cond
- ((eq system-type 'vax-vms)
- (apply 'call-process command infile buffer display args))
- ;; We used to use `exec' to replace the shell with the command,
- ;; but that failed to handle (...) and semicolon, etc.
- (t
- (call-process shell-file-name
- infile buffer display
- shell-command-switch
- (mapconcat 'identity (cons command args) " ")))))
+ ;; We used to use `exec' to replace the shell with the command,
+ ;; but that failed to handle (...) and semicolon, etc.
+ (call-process shell-file-name
+ infile buffer display
+ shell-command-switch
+ (mapconcat 'identity (cons command args) " ")))
(defun process-file-shell-command (command &optional infile buffer display
&rest args)
\f
;;;; Lisp macros to do various things temporarily.
-(defmacro with-current-buffer (buffer &rest body)
- "Execute the forms in BODY with BUFFER temporarily current.
-BUFFER can be a buffer or a buffer name.
-The value returned is the value of the last form in BODY.
-See also `with-temp-buffer'."
+(defmacro with-current-buffer (buffer-or-name &rest body)
+ "Execute the forms in BODY with BUFFER-OR-NAME temporarily current.
+BUFFER-OR-NAME must be a buffer or the name of an existing buffer.
+The value returned is the value of the last form in BODY. See
+also `with-temp-buffer'."
(declare (indent 1) (debug t))
`(save-current-buffer
- (set-buffer ,buffer)
+ (set-buffer ,buffer-or-name)
,@body))
(defmacro with-selected-window (window &rest body)
"Execute the forms in BODY with WINDOW as the selected window.
The value returned is the value of the last form in BODY.
-This macro saves and restores the current buffer, since otherwise
-its normal operation could potentially make a different
-buffer current. It does not alter the buffer list ordering.
-
-This macro saves and restores the selected window, as well as
-the selected window in each frame. If the previously selected
-window of some frame is no longer live at the end of BODY, that
-frame's selected window is left alone. If the selected window is
-no longer live, then whatever window is selected at the end of
-BODY remains selected.
-See also `with-temp-buffer'."
+This macro saves and restores the selected window, as well as the
+selected window of each frame. It does not change the order of
+recently selected windows. If the previously selected window of
+some frame is no longer live at the end of BODY, that frame's
+selected window is left alone. If the selected window is no
+longer live, then whatever window is selected at the end of BODY
+remains selected.
+
+This macro uses `save-current-buffer' to save and restore the
+current buffer, since otherwise its normal operation could
+potentially make a different buffer current. It does not alter
+the buffer list ordering."
(declare (indent 1) (debug t))
;; Most of this code is a copy of save-selected-window.
`(let ((save-selected-window-window (selected-window))
(dolist (elt save-selected-window-alist)
(and (frame-live-p (car elt))
(window-live-p (cadr elt))
- (set-frame-selected-window (car elt) (cadr elt))))
- (if (window-live-p save-selected-window-window)
- (select-window save-selected-window-window 'norecord))))))
+ (set-frame-selected-window (car elt) (cadr elt) 'norecord)))
+ (when (window-live-p save-selected-window-window)
+ (select-window save-selected-window-window 'norecord))))))
(defmacro with-selected-frame (frame &rest body)
"Execute the forms in BODY with FRAME as the selected frame.
The value returned is the value of the last form in BODY.
-See also `with-temp-buffer'."
+
+This macro neither changes the order of recently selected windows
+nor the buffer list."
(declare (indent 1) (debug t))
(let ((old-frame (make-symbol "old-frame"))
(old-buffer (make-symbol "old-buffer")))
`(let ((,old-frame (selected-frame))
(,old-buffer (current-buffer)))
(unwind-protect
- (progn (select-frame ,frame)
+ (progn (select-frame ,frame 'norecord)
,@body)
- (if (frame-live-p ,old-frame)
- (select-frame ,old-frame))
- (if (buffer-live-p ,old-buffer)
- (set-buffer ,old-buffer))))))
+ (when (frame-live-p ,old-frame)
+ (select-frame ,old-frame 'norecord))
+ (when (buffer-live-p ,old-buffer)
+ (set-buffer ,old-buffer))))))
(defmacro with-temp-file (file &rest body)
"Create a new buffer, evaluate BODY there, and write the buffer to FILE.
(declare (indent 0) (debug t))
`(let ((standard-output
(get-buffer-create (generate-new-buffer-name " *string-output*"))))
- (let ((standard-output standard-output))
- ,@body)
- (with-current-buffer standard-output
- (prog1
- (buffer-string)
- (kill-buffer nil)))))
+ (unwind-protect
+ (progn
+ (let ((standard-output standard-output))
+ ,@body)
+ (with-current-buffer standard-output
+ (buffer-string)))
+ (kill-buffer standard-output))))
(defmacro with-local-quit (&rest body)
"Execute BODY, allowing quits to terminate BODY but not escape further.
starting position, to avoid checking matches that would start
before LIMIT.
-If GREEDY is non-nil, extend the match backwards as far as possible,
-stopping when a single additional previous character cannot be part
-of a match for REGEXP."
+If GREEDY is non-nil, extend the match backwards as far as
+possible, stopping when a single additional previous character
+cannot be part of a match for REGEXP. When the match is
+extended, its starting position is allowed to occur before
+LIMIT."
(let ((start (point))
(pos
(save-excursion
(split-string-and-unquote (combine-and-quote-strings strs)) == strs
The SEPARATOR regexp defaults to \"\\s-+\"."
(let ((sep (or separator "\\s-+"))
- (i (string-match "[\"]" string)))
+ (i (string-match "\"" string)))
(if (null i)
(split-string string sep t) ; no quoting: easy
(append (unless (eq i 0) (split-string (substring string 0 i) sep t))
\"1alpha\"."
(version-list-= (version-to-list v1) (version-to-list v2)))
-
-
;; arch-tag: f7e0e6e5-70aa-4897-ae72-7a3511ec40bc
;;; subr.el ends here