Mercurial > emacs
changeset 66304:f754be327a7e
Much rearrangement of functions and division into pages. No code changes.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Sat, 22 Oct 2005 15:01:08 +0000 |
parents | b3dd2d3cab5d |
children | 3fcb7f692502 |
files | lisp/subr.el |
diffstat | 1 files changed, 595 insertions(+), 559 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/subr.el Sat Oct 22 11:23:54 2005 +0000 +++ b/lisp/subr.el Sat Oct 22 15:01:08 2005 +0000 @@ -37,7 +37,7 @@ (cons arguments custom-declare-variable-list))) -;;;; Lisp language features. +;;;; Basic Lisp macros. (defalias 'not 'null) @@ -144,6 +144,59 @@ Treated as a declaration when used at the right place in a `defmacro' form. \(See Info anchor `(elisp)Definition of declare'.)" nil) + +;;;; Basic Lisp functions. + +(defun ignore (&rest ignore) + "Do nothing and return nil. +This function accepts any number of arguments, but ignores them." + (interactive) + nil) + +(defun error (&rest args) + "Signal an error, making error message by passing all args to `format'. +In Emacs, the convention is that error messages start with a capital +letter but *do not* end with a period. Please follow this convention +for the sake of consistency." + (while t + (signal 'error (list (apply 'format args))))) + +;; We put this here instead of in frame.el so that it's defined even on +;; systems where frame.el isn't loaded. +(defun frame-configuration-p (object) + "Return non-nil if OBJECT seems to be a frame configuration. +Any list whose car is `frame-configuration' is assumed to be a frame +configuration." + (and (consp object) + (eq (car object) 'frame-configuration))) + +(defun functionp (object) + "Non-nil if OBJECT is any kind of function or a special form. +Also non-nil if OBJECT is a symbol and its function definition is +\(recursively) a function or special form. This does not include +macros." + (or (and (symbolp object) (fboundp object) + (condition-case nil + (setq object (indirect-function object)) + (error nil)) + (eq (car-safe object) 'autoload) + (not (car-safe (cdr-safe (cdr-safe (cdr-safe (cdr-safe object))))))) + (subrp object) (byte-code-function-p object) + (eq (car-safe object) 'lambda))) + +;; This should probably be written in C (i.e., without using `walk-windows'). +(defun get-buffer-window-list (buffer &optional minibuf frame) + "Return list of all windows displaying BUFFER, or nil if none. +BUFFER can be a buffer or a buffer name. +See `walk-windows' for the meaning of MINIBUF and FRAME." + (let ((buffer (if (bufferp buffer) buffer (get-buffer buffer))) windows) + (walk-windows (function (lambda (window) + (if (eq (window-buffer window) buffer) + (setq windows (cons window windows))))) + minibuf frame) + windows)) + +;;;; List functions. (defsubst caar (x) "Return the car of the car of X." @@ -240,23 +293,6 @@ next (+ from (* n inc))))) (nreverse seq)))) -(defun remove (elt seq) - "Return a copy of SEQ with all occurrences 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 LIST with all occurrences of ELT removed. -The comparison is done with `eq'. Contrary to `delq', this does not use -side-effects, and the argument LIST is not modified." - (if (memq elt list) - (delq elt (copy-sequence list)) - list)) - (defun copy-tree (tree &optional vecp) "Make a copy of TREE. If TREE is a cons cell, this recursively copies both its car and its cdr. @@ -277,6 +313,8 @@ (aset tree i (copy-tree (aref tree i) vecp))) tree) tree))) + +;;;; Various list-search functions. (defun assoc-default (key alist &optional test default) "Find object KEY in a pseudo-alist ALIST. @@ -321,15 +359,67 @@ (setq list (cdr list))) list) +(defun assq-delete-all (key alist) + "Delete from ALIST all elements whose car is `eq' to KEY. +Return the modified alist. +Elements of ALIST that are not conses are ignored." + (while (and (consp (car alist)) + (eq (car (car alist)) key)) + (setq alist (cdr alist))) + (let ((tail alist) tail-cdr) + (while (setq tail-cdr (cdr tail)) + (if (and (consp (car tail-cdr)) + (eq (car (car tail-cdr)) key)) + (setcdr tail (cdr tail-cdr)) + (setq tail tail-cdr)))) + alist) + +(defun rassq-delete-all (value alist) + "Delete from ALIST all elements whose cdr is `eq' to VALUE. +Return the modified alist. +Elements of ALIST that are not conses are ignored." + (while (and (consp (car alist)) + (eq (cdr (car alist)) value)) + (setq alist (cdr alist))) + (let ((tail alist) tail-cdr) + (while (setq tail-cdr (cdr tail)) + (if (and (consp (car tail-cdr)) + (eq (cdr (car tail-cdr)) value)) + (setcdr tail (cdr tail-cdr)) + (setq tail tail-cdr)))) + alist) + +(defun remove (elt seq) + "Return a copy of SEQ with all occurrences 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 LIST with all occurrences of ELT removed. +The comparison is done with `eq'. Contrary to `delq', this does not use +side-effects, and the argument LIST is not modified." + (if (memq elt list) + (delq elt (copy-sequence list)) + list)) ;;;; Keymap support. +(defmacro kbd (keys) + "Convert KEYS to the internal Emacs key representation. +KEYS should be a string constant in the format used for +saving keyboard macros (see `edmacro-mode')." + (read-kbd-macro keys)) + (defun undefined () (interactive) (ding)) -;Prevent the \{...} documentation construct -;from mentioning keys that run this command. +;; Prevent the \{...} documentation construct +;; from mentioning keys that run this command. (put 'undefined 'suppress-keymap t) (defun suppress-keymap (map &optional nodigits) @@ -346,6 +436,136 @@ (define-key map (char-to-string loop) 'digit-argument) (setq loop (1+ loop)))))) +(defun define-key-after (keymap key definition &optional after) + "Add binding in KEYMAP for KEY => DEFINITION, right after AFTER's binding. +This is like `define-key' except that the binding for KEY is placed +just after the binding for the event AFTER, instead of at the beginning +of the map. Note that AFTER must be an event type (like KEY), NOT a command +\(like DEFINITION). + +If AFTER is t or omitted, the new binding goes at the end of the keymap. +AFTER should be a single event type--a symbol or a character, not a sequence. + +Bindings are always added before any inherited map. + +The order of bindings in a keymap matters when it is used as a menu." + (unless after (setq after t)) + (or (keymapp keymap) + (signal 'wrong-type-argument (list 'keymapp keymap))) + (setq key + (if (<= (length key) 1) (aref key 0) + (setq keymap (lookup-key keymap + (apply 'vector + (butlast (mapcar 'identity key))))) + (aref key (1- (length key))))) + (let ((tail keymap) done inserted) + (while (and (not done) tail) + ;; Delete any earlier bindings for the same key. + (if (eq (car-safe (car (cdr tail))) key) + (setcdr tail (cdr (cdr tail)))) + ;; If we hit an included map, go down that one. + (if (keymapp (car tail)) (setq tail (car tail))) + ;; When we reach AFTER's binding, insert the new binding after. + ;; If we reach an inherited keymap, insert just before that. + ;; If we reach the end of this keymap, insert at the end. + (if (or (and (eq (car-safe (car tail)) after) + (not (eq after t))) + (eq (car (cdr tail)) 'keymap) + (null (cdr tail))) + (progn + ;; Stop the scan only if we find a parent keymap. + ;; Keep going past the inserted element + ;; so we can delete any duplications that come later. + (if (eq (car (cdr tail)) 'keymap) + (setq done t)) + ;; Don't insert more than once. + (or inserted + (setcdr tail (cons (cons key definition) (cdr tail)))) + (setq inserted t))) + (setq tail (cdr tail))))) + +(defun map-keymap-internal (function keymap &optional sort-first) + "Implement `map-keymap' with sorting. +Don't call this function; it is for internal use only." + (if sort-first + (let (list) + (map-keymap (lambda (a b) (push (cons a b) list)) + keymap) + (setq list (sort list + (lambda (a b) + (setq a (car a) b (car b)) + (if (integerp a) + (if (integerp b) (< a b) + t) + (if (integerp b) t + (string< a b)))))) + (dolist (p list) + (funcall function (car p) (cdr p)))) + (map-keymap function keymap))) + +(put 'keyboard-translate-table 'char-table-extra-slots 0) + +(defun keyboard-translate (from to) + "Translate character FROM to TO at a low level. +This function creates a `keyboard-translate-table' if necessary +and then modifies one entry in it." + (or (char-table-p keyboard-translate-table) + (setq keyboard-translate-table + (make-char-table 'keyboard-translate-table nil))) + (aset keyboard-translate-table from to)) + +;;;; Key binding commands. + +(defun global-set-key (key command) + "Give KEY a global binding as COMMAND. +COMMAND is the command definition to use; usually it is +a symbol naming an interactively-callable function. +KEY is a key sequence; noninteractively, it is a string or vector +of characters or event types, and non-ASCII characters with codes +above 127 (such as ISO Latin-1) can be included if you use a vector. + +Note that if KEY has a local binding in the current buffer, +that local binding will continue to shadow any global binding +that you make with this function." + (interactive "KSet key globally: \nCSet key %s to command: ") + (or (vectorp key) (stringp key) + (signal 'wrong-type-argument (list 'arrayp key))) + (define-key (current-global-map) key command)) + +(defun local-set-key (key command) + "Give KEY a local binding as COMMAND. +COMMAND is the command definition to use; usually it is +a symbol naming an interactively-callable function. +KEY is a key sequence; noninteractively, it is a string or vector +of characters or event types, and non-ASCII characters with codes +above 127 (such as ISO Latin-1) can be included if you use a vector. + +The binding goes in the current buffer's local map, +which in most cases is shared with all other buffers in the same major mode." + (interactive "KSet key locally: \nCSet key %s locally to command: ") + (let ((map (current-local-map))) + (or map + (use-local-map (setq map (make-sparse-keymap)))) + (or (vectorp key) (stringp key) + (signal 'wrong-type-argument (list 'arrayp key))) + (define-key map key command))) + +(defun global-unset-key (key) + "Remove global binding of KEY. +KEY is a string or vector representing a sequence of keystrokes." + (interactive "kUnset key globally: ") + (global-set-key key nil)) + +(defun local-unset-key (key) + "Remove local binding of KEY. +KEY is a string or vector representing a sequence of keystrokes." + (interactive "kUnset key locally: ") + (if (current-local-map) + (local-set-key key nil)) + nil) + +;;;; substitute-key-definition and its subroutines. + (defvar key-substitution-in-progress nil "Used internally by `substitute-key-definition'.") @@ -416,90 +636,6 @@ ;; If this one isn't being scanned already, scan it now. (substitute-key-definition olddef newdef keymap inner-def prefix))))) -(defun define-key-after (keymap key definition &optional after) - "Add binding in KEYMAP for KEY => DEFINITION, right after AFTER's binding. -This is like `define-key' except that the binding for KEY is placed -just after the binding for the event AFTER, instead of at the beginning -of the map. Note that AFTER must be an event type (like KEY), NOT a command -\(like DEFINITION). - -If AFTER is t or omitted, the new binding goes at the end of the keymap. -AFTER should be a single event type--a symbol or a character, not a sequence. - -Bindings are always added before any inherited map. - -The order of bindings in a keymap matters when it is used as a menu." - (unless after (setq after t)) - (or (keymapp keymap) - (signal 'wrong-type-argument (list 'keymapp keymap))) - (setq key - (if (<= (length key) 1) (aref key 0) - (setq keymap (lookup-key keymap - (apply 'vector - (butlast (mapcar 'identity key))))) - (aref key (1- (length key))))) - (let ((tail keymap) done inserted) - (while (and (not done) tail) - ;; Delete any earlier bindings for the same key. - (if (eq (car-safe (car (cdr tail))) key) - (setcdr tail (cdr (cdr tail)))) - ;; If we hit an included map, go down that one. - (if (keymapp (car tail)) (setq tail (car tail))) - ;; When we reach AFTER's binding, insert the new binding after. - ;; If we reach an inherited keymap, insert just before that. - ;; If we reach the end of this keymap, insert at the end. - (if (or (and (eq (car-safe (car tail)) after) - (not (eq after t))) - (eq (car (cdr tail)) 'keymap) - (null (cdr tail))) - (progn - ;; Stop the scan only if we find a parent keymap. - ;; Keep going past the inserted element - ;; so we can delete any duplications that come later. - (if (eq (car (cdr tail)) 'keymap) - (setq done t)) - ;; Don't insert more than once. - (or inserted - (setcdr tail (cons (cons key definition) (cdr tail)))) - (setq inserted t))) - (setq tail (cdr tail))))) - -(defun map-keymap-internal (function keymap &optional sort-first) - "Implement `map-keymap' with sorting. -Don't call this function; it is for internal use only." - (if sort-first - (let (list) - (map-keymap (lambda (a b) (push (cons a b) list)) - keymap) - (setq list (sort list - (lambda (a b) - (setq a (car a) b (car b)) - (if (integerp a) - (if (integerp b) (< a b) - t) - (if (integerp b) t - (string< a b)))))) - (dolist (p list) - (funcall function (car p) (cdr p)))) - (map-keymap function keymap))) - -(defmacro kbd (keys) - "Convert KEYS to the internal Emacs key representation. -KEYS should be a string constant in the format used for -saving keyboard macros (see `edmacro-mode')." - (read-kbd-macro keys)) - -(put 'keyboard-translate-table 'char-table-extra-slots 0) - -(defun keyboard-translate (from to) - "Translate character FROM to TO at a low level. -This function creates a `keyboard-translate-table' if necessary -and then modifies one entry in it." - (or (char-table-p keyboard-translate-table) - (setq keyboard-translate-table - (make-char-table 'keyboard-translate-table nil))) - (aset keyboard-translate-table from to)) - ;;;; The global keymap tree. @@ -642,6 +778,8 @@ "Return the multi-click count of EVENT, a click or drag event. The return value is a positive integer." (if (and (consp event) (integerp (nth 2 event))) (nth 2 event) 1)) + +;;;; Extracting fields of the positions in an event. (defsubst posn-window (position) "Return the window in POSITION. @@ -831,6 +969,8 @@ (defalias 'point-at-eol 'line-end-position) (defalias 'point-at-bol 'line-beginning-position) +(defalias 'user-original-login-name 'user-login-name) + ;;;; Hook manipulation functions. @@ -991,7 +1131,143 @@ (if (and oa ob) (< oa ob) oa))))))) - + +;;;; Mode hooks. + +(defvar delay-mode-hooks nil + "If non-nil, `run-mode-hooks' should delay running the hooks.") +(defvar delayed-mode-hooks nil + "List of delayed mode hooks waiting to be run.") +(make-variable-buffer-local 'delayed-mode-hooks) +(put 'delay-mode-hooks 'permanent-local t) + +(defvar after-change-major-mode-hook nil + "Normal hook run at the very end of major mode functions.") + +(defun run-mode-hooks (&rest hooks) + "Run mode hooks `delayed-mode-hooks' and HOOKS, or delay HOOKS. +Execution is delayed if `delay-mode-hooks' is non-nil. +If `delay-mode-hooks' is nil, run `after-change-major-mode-hook' +after running the mode hooks. +Major mode functions should use this." + (if delay-mode-hooks + ;; Delaying case. + (dolist (hook hooks) + (push hook delayed-mode-hooks)) + ;; Normal case, just run the hook as before plus any delayed hooks. + (setq hooks (nconc (nreverse delayed-mode-hooks) hooks)) + (setq delayed-mode-hooks nil) + (apply 'run-hooks hooks) + (run-hooks 'after-change-major-mode-hook))) + +(defmacro delay-mode-hooks (&rest body) + "Execute BODY, but delay any `run-mode-hooks'. +These hooks will be executed by the first following call to +`run-mode-hooks' that occurs outside any `delayed-mode-hooks' form. +Only affects hooks run in the current buffer." + (declare (debug t) (indent 0)) + `(progn + (make-local-variable 'delay-mode-hooks) + (let ((delay-mode-hooks t)) + ,@body))) + +;; PUBLIC: find if the current mode derives from another. + +(defun derived-mode-p (&rest modes) + "Non-nil if the current major mode is derived from one of MODES. +Uses the `derived-mode-parent' property of the symbol to trace backwards." + (let ((parent major-mode)) + (while (and (not (memq parent modes)) + (setq parent (get parent 'derived-mode-parent)))) + parent)) + +;;;; Minor modes. + +;; If a minor mode is not defined with define-minor-mode, +;; add it here explicitly. +;; isearch-mode is deliberately excluded, since you should +;; not call it yourself. +(defvar minor-mode-list '(auto-save-mode auto-fill-mode abbrev-mode + overwrite-mode view-mode + hs-minor-mode) + "List of all minor mode functions.") + +(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 (memq toggle minor-mode-list) + (push toggle minor-mode-list)) + + (unless toggle-fun (setq toggle-fun toggle)) + (unless (eq toggle-fun toggle) + (put toggle :minor-mode-function toggle-fun)) + ;; Add the name to the minor-mode-alist. + (when name + (let ((existing (assq toggle minor-mode-alist))) + (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 toggle to the minor-modes menu if requested. + (when (get toggle :included) + (define-key mode-line-mode-menu + (vector toggle) + (list 'menu-item + (concat + (or (get toggle :menu-tag) + (if (stringp name) name (symbol-name toggle))) + (let ((mode-name (if (symbolp name) (symbol-value name)))) + (if (and (stringp mode-name) (string-match "[^ ]+" mode-name)) + (concat " (" (match-string 0 mode-name) ")")))) + toggle-fun + :button (cons :toggle toggle)))) + + ;; 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)))))))) ;;; Load history @@ -1080,7 +1356,9 @@ FILE should be the name of a library, with no directory name." (eval-after-load file (read))) -;;; open-network-stream is a wrapper around make-network-process. +;;;; Process stuff. + +;; open-network-stream is a wrapper around make-network-process. (when (featurep 'make-network-process) (defun open-network-stream (name buffer host service) @@ -1380,6 +1658,8 @@ ;; Revert the undo info to what it was when we grabbed the state. (setq buffer-undo-list elt))))) +;;;; Display-related functions. + ;; For compatibility. (defalias 'redraw-modeline 'force-mode-line-update) @@ -1517,34 +1797,122 @@ This variable is meaningful on MS-DOG and Windows NT. On those systems, it is automatically local in every buffer. On other systems, this variable is normally always nil.") - -;; This should probably be written in C (i.e., without using `walk-windows'). -(defun get-buffer-window-list (buffer &optional minibuf frame) - "Return list of all windows displaying BUFFER, or nil if none. -BUFFER can be a buffer or a buffer name. -See `walk-windows' for the meaning of MINIBUF and FRAME." - (let ((buffer (if (bufferp buffer) buffer (get-buffer buffer))) windows) - (walk-windows (function (lambda (window) - (if (eq (window-buffer window) buffer) - (setq windows (cons window windows))))) - minibuf frame) - windows)) - -(defun ignore (&rest ignore) - "Do nothing and return nil. -This function accepts any number of arguments, but ignores them." - (interactive) - nil) - -(defun error (&rest args) - "Signal an error, making error message by passing all args to `format'. -In Emacs, the convention is that error messages start with a capital -letter but *do not* end with a period. Please follow this convention -for the sake of consistency." - (while t - (signal 'error (list (apply 'format args))))) - -(defalias 'user-original-login-name 'user-login-name) + +;;;; Misc. useful functions. + +(defun find-tag-default () + "Determine default tag to search for, based on text at point. +If there is no plausible default, return nil." + (save-excursion + (while (looking-at "\\sw\\|\\s_") + (forward-char 1)) + (if (or (re-search-backward "\\sw\\|\\s_" + (save-excursion (beginning-of-line) (point)) + t) + (re-search-forward "\\(\\sw\\|\\s_\\)+" + (save-excursion (end-of-line) (point)) + t)) + (progn + (goto-char (match-end 0)) + (condition-case nil + (buffer-substring-no-properties + (point) + (progn (forward-sexp -1) + (while (looking-at "\\s'") + (forward-char 1)) + (point))) + (error nil))) + nil))) + +(defun play-sound (sound) + "SOUND is a list of the form `(sound KEYWORD VALUE...)'. +The following keywords are recognized: + + :file FILE - read sound data from FILE. If FILE isn't an +absolute file name, it is searched in `data-directory'. + + :data DATA - read sound data from string DATA. + +Exactly one of :file or :data must be present. + + :volume VOL - set volume to VOL. VOL must an integer in the +range 0..100 or a float in the range 0..1.0. If not specified, +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." + (if (fboundp 'play-sound-internal) + (play-sound-internal sound) + (error "This Emacs binary lacks sound support"))) + +(defun make-temp-file (prefix &optional dir-flag suffix) + "Create a temporary file. +The returned file name (created by appending some random characters at the end +of PREFIX, and expanding against `temporary-file-directory' if necessary), +is guaranteed to point to a newly created empty file. +You can then use `write-region' to write new data into the file. + +If DIR-FLAG is non-nil, create a new empty directory instead of a file. + +If SUFFIX is non-nil, add that at the end of the file name." + (let ((umask (default-file-modes)) + file) + (unwind-protect + (progn + ;; Create temp files with strict access rights. It's easy to + ;; loosen them later, whereas it's impossible to close the + ;; time-window of loose permissions otherwise. + (set-default-file-modes ?\700) + (while (condition-case () + (progn + (setq file + (make-temp-name + (expand-file-name prefix temporary-file-directory))) + (if suffix + (setq file (concat file suffix))) + (if dir-flag + (make-directory file) + (write-region "" nil file nil 'silent nil 'excl)) + nil) + (file-already-exists t)) + ;; the file was somehow created by someone else between + ;; `make-temp-name' and `write-region', let's try again. + nil) + file) + ;; Reset the umask. + (set-default-file-modes umask)))) + +(defun shell-quote-argument (argument) + "Quote an argument for passing as argument to an inferior shell." + (if (eq system-type 'ms-dos) + ;; Quote using double quotes, but escape any existing quotes in + ;; the argument with backslashes. + (let ((result "") + (start 0) + end) + (if (or (null (string-match "[^\"]" argument)) + (< (match-end 0) (length argument))) + (while (string-match "[\"]" argument start) + (setq end (match-beginning 0) + result (concat result (substring argument start end) + "\\" (substring argument end (1+ end))) + start (1+ end)))) + (concat "\"" result (substring argument start) "\"")) + (if (eq system-type 'windows-nt) + (concat "\"" argument "\"") + (if (equal argument "") + "''" + ;; Quote everything except POSIX filename characters. + ;; This should be safe enough even for really weird shells. + (let ((result "") (start 0) end) + (while (string-match "[^-0-9a-zA-Z_./]" argument start) + (setq end (match-beginning 0) + result (concat result (substring argument start end) + "\\" (substring argument end (1+ end))) + start (1+ end))) + (concat result (substring argument start))))))) + +;;;; Support for yanking and text properties. (defvar yank-excluded-properties) @@ -1650,7 +2018,7 @@ (remove-yank-excluded-properties opoint (point)))) -;; Synchronous shell commands. +;;;; Synchronous shell commands. (defun start-process-shell-command (name buffer &rest args) "Start a program in a subprocess. Return the process object for it. @@ -1706,6 +2074,8 @@ shell-command-switch (mapconcat 'identity (cons command args) " "))))) +;;;; Lisp macros to do various things temporarily. + (defmacro with-current-buffer (buffer &rest body) "Execute the forms in BODY with BUFFER as the current buffer. The value returned is the value of the last form in BODY. @@ -1858,96 +2228,8 @@ (let ((combine-after-change-calls t)) . ,body) (combine-after-change-execute))) - - -(defvar delay-mode-hooks nil - "If non-nil, `run-mode-hooks' should delay running the hooks.") -(defvar delayed-mode-hooks nil - "List of delayed mode hooks waiting to be run.") -(make-variable-buffer-local 'delayed-mode-hooks) -(put 'delay-mode-hooks 'permanent-local t) - -(defvar after-change-major-mode-hook nil - "Normal hook run at the very end of major mode functions.") - -(defun run-mode-hooks (&rest hooks) - "Run mode hooks `delayed-mode-hooks' and HOOKS, or delay HOOKS. -Execution is delayed if `delay-mode-hooks' is non-nil. -If `delay-mode-hooks' is nil, run `after-change-major-mode-hook' -after running the mode hooks. -Major mode functions should use this." - (if delay-mode-hooks - ;; Delaying case. - (dolist (hook hooks) - (push hook delayed-mode-hooks)) - ;; Normal case, just run the hook as before plus any delayed hooks. - (setq hooks (nconc (nreverse delayed-mode-hooks) hooks)) - (setq delayed-mode-hooks nil) - (apply 'run-hooks hooks) - (run-hooks 'after-change-major-mode-hook))) - -(defmacro delay-mode-hooks (&rest body) - "Execute BODY, but delay any `run-mode-hooks'. -These hooks will be executed by the first following call to -`run-mode-hooks' that occurs outside any `delayed-mode-hooks' form. -Only affects hooks run in the current buffer." - (declare (debug t) (indent 0)) - `(progn - (make-local-variable 'delay-mode-hooks) - (let ((delay-mode-hooks t)) - ,@body))) - -;; PUBLIC: find if the current mode derives from another. - -(defun derived-mode-p (&rest modes) - "Non-nil if the current major mode is derived from one of MODES. -Uses the `derived-mode-parent' property of the symbol to trace backwards." - (let ((parent major-mode)) - (while (and (not (memq parent modes)) - (setq parent (get parent 'derived-mode-parent)))) - parent)) - -(defun find-tag-default () - "Determine default tag to search for, based on text at point. -If there is no plausible default, return nil." - (save-excursion - (while (looking-at "\\sw\\|\\s_") - (forward-char 1)) - (if (or (re-search-backward "\\sw\\|\\s_" - (save-excursion (beginning-of-line) (point)) - t) - (re-search-forward "\\(\\sw\\|\\s_\\)+" - (save-excursion (end-of-line) (point)) - t)) - (progn - (goto-char (match-end 0)) - (condition-case nil - (buffer-substring-no-properties - (point) - (progn (forward-sexp -1) - (while (looking-at "\\s'") - (forward-char 1)) - (point))) - (error nil))) - nil))) - -(defmacro with-syntax-table (table &rest body) - "Evaluate BODY with syntax table of current buffer set to TABLE. -The syntax table of the current buffer is saved, BODY is evaluated, and the -saved table is restored, even in case of an abnormal exit. -Value is what BODY returns." - (declare (debug t)) - (let ((old-table (make-symbol "table")) - (old-buffer (make-symbol "buffer"))) - `(let ((,old-table (syntax-table)) - (,old-buffer (current-buffer))) - (unwind-protect - (progn - (set-syntax-table ,table) - ,@body) - (save-current-buffer - (set-buffer ,old-buffer) - (set-syntax-table ,old-table)))))) + +;;;; Constructing completion tables. (defmacro dynamic-completion-table (fun) "Use function FUN as a dynamic completion table. @@ -2007,7 +2289,7 @@ (or (test-completion string ,a predicate) (test-completion string ,b predicate)))))) -;;; Matching and substitution +;;; Matching and match data. (defvar save-match-data-internal) @@ -2082,6 +2364,47 @@ (looking-at (concat "\\(?:" regexp "\\)\\'"))))) (not (null pos)))) +(defun subregexp-context-p (regexp pos &optional start) + "Return non-nil if POS is in a normal subregexp context in REGEXP. +A subregexp context is one where a sub-regexp can appear. +A non-subregexp context is for example within brackets, or within a +repetition bounds operator `\\=\\{...\\}', or right after a `\\'. +If START is non-nil, it should be a position in REGEXP, smaller +than POS, and known to be in a subregexp context." + ;; Here's one possible implementation, with the great benefit that it + ;; reuses the regexp-matcher's own parser, so it understands all the + ;; details of the syntax. A disadvantage is that it needs to match the + ;; error string. + (condition-case err + (progn + (string-match (substring regexp (or start 0) pos) "") + t) + (invalid-regexp + (not (member (cadr err) '("Unmatched [ or [^" + "Unmatched \\{" + "Trailing backslash"))))) + ;; An alternative implementation: + ;; (defconst re-context-re + ;; (let* ((harmless-ch "[^\\[]") + ;; (harmless-esc "\\\\[^{]") + ;; (class-harmless-ch "[^][]") + ;; (class-lb-harmless "[^]:]") + ;; (class-lb-colon-maybe-charclass ":\\([a-z]+:]\\)?") + ;; (class-lb (concat "\\[\\(" class-lb-harmless + ;; "\\|" class-lb-colon-maybe-charclass "\\)")) + ;; (class + ;; (concat "\\[^?]?" + ;; "\\(" class-harmless-ch + ;; "\\|" class-lb "\\)*" + ;; "\\[?]")) ; special handling for bare [ at end of re + ;; (braces "\\\\{[0-9,]+\\\\}")) + ;; (concat "\\`\\(" harmless-ch "\\|" harmless-esc + ;; "\\|" class "\\|" braces "\\)*\\'")) + ;; "Matches any prefix that corresponds to a normal subregexp context.") + ;; (string-match re-context-re (substring regexp (or start 0) pos)) + ) + +;;;; split-string (defconst split-string-default-separators "[ \f\t\n\r\v]+" "The default value of separators for `split-string'. @@ -2142,6 +2465,8 @@ (cons (substring string start) list))) (nreverse list))) + +;;;; Replacement in strings. (defun subst-char-in-string (fromchar tochar string &optional inplace) "Replace FROMCHAR with TOCHAR in STRING each time it occurs. @@ -2211,76 +2536,42 @@ ;; Reconstruct a string from the pieces. (setq matches (cons (substring string start l) matches)) ; leftover (apply #'concat (nreverse matches))))) - -(defun subregexp-context-p (regexp pos &optional start) - "Return non-nil if POS is in a normal subregexp context in REGEXP. -A subregexp context is one where a sub-regexp can appear. -A non-subregexp context is for example within brackets, or within a -repetition bounds operator `\\=\\{...\\}', or right after a `\\'. -If START is non-nil, it should be a position in REGEXP, smaller -than POS, and known to be in a subregexp context." - ;; Here's one possible implementation, with the great benefit that it - ;; reuses the regexp-matcher's own parser, so it understands all the - ;; details of the syntax. A disadvantage is that it needs to match the - ;; error string. - (condition-case err - (progn - (string-match (substring regexp (or start 0) pos) "") - t) - (invalid-regexp - (not (member (cadr err) '("Unmatched [ or [^" - "Unmatched \\{" - "Trailing backslash"))))) - ;; An alternative implementation: - ;; (defconst re-context-re - ;; (let* ((harmless-ch "[^\\[]") - ;; (harmless-esc "\\\\[^{]") - ;; (class-harmless-ch "[^][]") - ;; (class-lb-harmless "[^]:]") - ;; (class-lb-colon-maybe-charclass ":\\([a-z]+:]\\)?") - ;; (class-lb (concat "\\[\\(" class-lb-harmless - ;; "\\|" class-lb-colon-maybe-charclass "\\)")) - ;; (class - ;; (concat "\\[^?]?" - ;; "\\(" class-harmless-ch - ;; "\\|" class-lb "\\)*" - ;; "\\[?]")) ; special handling for bare [ at end of re - ;; (braces "\\\\{[0-9,]+\\\\}")) - ;; (concat "\\`\\(" harmless-ch "\\|" harmless-esc - ;; "\\|" class "\\|" braces "\\)*\\'")) - ;; "Matches any prefix that corresponds to a normal subregexp context.") - ;; (string-match re-context-re (substring regexp (or start 0) pos)) - ) + +;;;; invisibility specs + +(defun add-to-invisibility-spec (element) + "Add ELEMENT to `buffer-invisibility-spec'. +See documentation for `buffer-invisibility-spec' for the kind of elements +that can be added." + (if (eq buffer-invisibility-spec t) + (setq buffer-invisibility-spec (list t))) + (setq buffer-invisibility-spec + (cons element buffer-invisibility-spec))) + +(defun remove-from-invisibility-spec (element) + "Remove ELEMENT from `buffer-invisibility-spec'." + (if (consp buffer-invisibility-spec) + (setq buffer-invisibility-spec (delete element buffer-invisibility-spec)))) -(defun shell-quote-argument (argument) - "Quote an argument for passing as argument to an inferior shell." - (if (eq system-type 'ms-dos) - ;; Quote using double quotes, but escape any existing quotes in - ;; the argument with backslashes. - (let ((result "") - (start 0) - end) - (if (or (null (string-match "[^\"]" argument)) - (< (match-end 0) (length argument))) - (while (string-match "[\"]" argument start) - (setq end (match-beginning 0) - result (concat result (substring argument start end) - "\\" (substring argument end (1+ end))) - start (1+ end)))) - (concat "\"" result (substring argument start) "\"")) - (if (eq system-type 'windows-nt) - (concat "\"" argument "\"") - (if (equal argument "") - "''" - ;; Quote everything except POSIX filename characters. - ;; This should be safe enough even for really weird shells. - (let ((result "") (start 0) end) - (while (string-match "[^-0-9a-zA-Z_./]" argument start) - (setq end (match-beginning 0) - result (concat result (substring argument start end) - "\\" (substring argument end (1+ end))) - start (1+ end))) - (concat result (substring argument start))))))) +;;;; Syntax tables. + +(defmacro with-syntax-table (table &rest body) + "Evaluate BODY with syntax table of current buffer set to TABLE. +The syntax table of the current buffer is saved, BODY is evaluated, and the +saved table is restored, even in case of an abnormal exit. +Value is what BODY returns." + (declare (debug t)) + (let ((old-table (make-symbol "table")) + (old-buffer (make-symbol "buffer"))) + `(let ((,old-table (syntax-table)) + (,old-buffer (current-buffer))) + (unwind-protect + (progn + (set-syntax-table ,table) + ,@body) + (save-current-buffer + (set-buffer ,old-buffer) + (set-syntax-table ,old-table)))))) (defun make-syntax-table (&optional oldtable) "Return a new syntax table. @@ -2303,247 +2594,8 @@ "Return the syntax class part of the syntax descriptor SYNTAX. If SYNTAX is nil, return nil." (and syntax (logand (car syntax) 65535))) - -(defun add-to-invisibility-spec (element) - "Add ELEMENT to `buffer-invisibility-spec'. -See documentation for `buffer-invisibility-spec' for the kind of elements -that can be added." - (if (eq buffer-invisibility-spec t) - (setq buffer-invisibility-spec (list t))) - (setq buffer-invisibility-spec - (cons element buffer-invisibility-spec))) - -(defun remove-from-invisibility-spec (element) - "Remove ELEMENT from `buffer-invisibility-spec'." - (if (consp buffer-invisibility-spec) - (setq buffer-invisibility-spec (delete element buffer-invisibility-spec)))) -(defun global-set-key (key command) - "Give KEY a global binding as COMMAND. -COMMAND is the command definition to use; usually it is -a symbol naming an interactively-callable function. -KEY is a key sequence; noninteractively, it is a string or vector -of characters or event types, and non-ASCII characters with codes -above 127 (such as ISO Latin-1) can be included if you use a vector. - -Note that if KEY has a local binding in the current buffer, -that local binding will continue to shadow any global binding -that you make with this function." - (interactive "KSet key globally: \nCSet key %s to command: ") - (or (vectorp key) (stringp key) - (signal 'wrong-type-argument (list 'arrayp key))) - (define-key (current-global-map) key command)) - -(defun local-set-key (key command) - "Give KEY a local binding as COMMAND. -COMMAND is the command definition to use; usually it is -a symbol naming an interactively-callable function. -KEY is a key sequence; noninteractively, it is a string or vector -of characters or event types, and non-ASCII characters with codes -above 127 (such as ISO Latin-1) can be included if you use a vector. - -The binding goes in the current buffer's local map, -which in most cases is shared with all other buffers in the same major mode." - (interactive "KSet key locally: \nCSet key %s locally to command: ") - (let ((map (current-local-map))) - (or map - (use-local-map (setq map (make-sparse-keymap)))) - (or (vectorp key) (stringp key) - (signal 'wrong-type-argument (list 'arrayp key))) - (define-key map key command))) - -(defun global-unset-key (key) - "Remove global binding of KEY. -KEY is a string or vector representing a sequence of keystrokes." - (interactive "kUnset key globally: ") - (global-set-key key nil)) - -(defun local-unset-key (key) - "Remove local binding of KEY. -KEY is a string or vector representing a sequence of keystrokes." - (interactive "kUnset key locally: ") - (if (current-local-map) - (local-set-key key nil)) - nil) - -;; We put this here instead of in frame.el so that it's defined even on -;; systems where frame.el isn't loaded. -(defun frame-configuration-p (object) - "Return non-nil if OBJECT seems to be a frame configuration. -Any list whose car is `frame-configuration' is assumed to be a frame -configuration." - (and (consp object) - (eq (car object) 'frame-configuration))) - -(defun functionp (object) - "Non-nil if OBJECT is any kind of function or a special form. -Also non-nil if OBJECT is a symbol and its function definition is -\(recursively) a function or special form. This does not include -macros." - (or (and (symbolp object) (fboundp object) - (condition-case nil - (setq object (indirect-function object)) - (error nil)) - (eq (car-safe object) 'autoload) - (not (car-safe (cdr-safe (cdr-safe (cdr-safe (cdr-safe object))))))) - (subrp object) (byte-code-function-p object) - (eq (car-safe object) 'lambda))) - -(defun assq-delete-all (key alist) - "Delete from ALIST all elements whose car is `eq' to KEY. -Return the modified alist. -Elements of ALIST that are not conses are ignored." - (while (and (consp (car alist)) - (eq (car (car alist)) key)) - (setq alist (cdr alist))) - (let ((tail alist) tail-cdr) - (while (setq tail-cdr (cdr tail)) - (if (and (consp (car tail-cdr)) - (eq (car (car tail-cdr)) key)) - (setcdr tail (cdr tail-cdr)) - (setq tail tail-cdr)))) - alist) - -(defun rassq-delete-all (value alist) - "Delete from ALIST all elements whose cdr is `eq' to VALUE. -Return the modified alist. -Elements of ALIST that are not conses are ignored." - (while (and (consp (car alist)) - (eq (cdr (car alist)) value)) - (setq alist (cdr alist))) - (let ((tail alist) tail-cdr) - (while (setq tail-cdr (cdr tail)) - (if (and (consp (car tail-cdr)) - (eq (cdr (car tail-cdr)) value)) - (setcdr tail (cdr tail-cdr)) - (setq tail tail-cdr)))) - alist) - -(defun make-temp-file (prefix &optional dir-flag suffix) - "Create a temporary file. -The returned file name (created by appending some random characters at the end -of PREFIX, and expanding against `temporary-file-directory' if necessary), -is guaranteed to point to a newly created empty file. -You can then use `write-region' to write new data into the file. - -If DIR-FLAG is non-nil, create a new empty directory instead of a file. - -If SUFFIX is non-nil, add that at the end of the file name." - (let ((umask (default-file-modes)) - file) - (unwind-protect - (progn - ;; Create temp files with strict access rights. It's easy to - ;; loosen them later, whereas it's impossible to close the - ;; time-window of loose permissions otherwise. - (set-default-file-modes ?\700) - (while (condition-case () - (progn - (setq file - (make-temp-name - (expand-file-name prefix temporary-file-directory))) - (if suffix - (setq file (concat file suffix))) - (if dir-flag - (make-directory file) - (write-region "" nil file nil 'silent nil 'excl)) - nil) - (file-already-exists t)) - ;; the file was somehow created by someone else between - ;; `make-temp-name' and `write-region', let's try again. - nil) - file) - ;; Reset the umask. - (set-default-file-modes umask)))) - - -;; If a minor mode is not defined with define-minor-mode, -;; add it here explicitly. -;; isearch-mode is deliberately excluded, since you should -;; not call it yourself. -(defvar minor-mode-list '(auto-save-mode auto-fill-mode abbrev-mode - overwrite-mode view-mode - hs-minor-mode) - "List of all minor mode functions.") - -(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 (memq toggle minor-mode-list) - (push toggle minor-mode-list)) - - (unless toggle-fun (setq toggle-fun toggle)) - (unless (eq toggle-fun toggle) - (put toggle :minor-mode-function toggle-fun)) - ;; Add the name to the minor-mode-alist. - (when name - (let ((existing (assq toggle minor-mode-alist))) - (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 toggle to the minor-modes menu if requested. - (when (get toggle :included) - (define-key mode-line-mode-menu - (vector toggle) - (list 'menu-item - (concat - (or (get toggle :menu-tag) - (if (stringp name) name (symbol-name toggle))) - (let ((mode-name (if (symbolp name) (symbol-value name)))) - (if (and (stringp mode-name) (string-match "[^ ]+" mode-name)) - (concat " (" (match-string 0 mode-name) ")")))) - toggle-fun - :button (cons :toggle toggle)))) - - ;; 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)))))))) - -;; Clones ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Text clones (defun text-clone-maintain (ol1 after beg end &optional len) "Propagate the changes made under the overlay OL1 to the other clones. @@ -2637,27 +2689,11 @@ ;;(overlay-put ol2 'face 'underline) (overlay-put ol2 'evaporate t) (overlay-put ol2 'text-clones dups))) - -(defun play-sound (sound) - "SOUND is a list of the form `(sound KEYWORD VALUE...)'. -The following keywords are recognized: - - :file FILE - read sound data from FILE. If FILE isn't an -absolute file name, it is searched in `data-directory'. - - :data DATA - read sound data from string DATA. - -Exactly one of :file or :data must be present. - - :volume VOL - set volume to VOL. VOL must an integer in the -range 0..100 or a float in the range 0..1.0. If not specified, -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." - (if (fboundp 'play-sound-internal) - (play-sound-internal sound) - (error "This Emacs binary lacks sound support"))) + +;;;; Mail user agents. + +;; Here we include just enough for other packages to be able +;; to define them. (defun define-mail-user-agent (symbol composefunc sendfunc &optional abortfunc hookvar) @@ -2693,8 +2729,8 @@ (put symbol 'sendfunc sendfunc) (put symbol 'abortfunc (or abortfunc 'kill-buffer)) (put symbol 'hookvar (or hookvar 'mail-send-hook))) - -;; Standardized progress reporting + +;;;; Progress reporters. ;; Progress reporter has the following structure: ;; @@ -2851,7 +2887,7 @@ nil ,@(cdr (cdr spec))))) -;;;; Compare Version Strings +;;;; Comparing version strings. (defvar version-separator "." "*Specify the string used to separate the version elements.