diff options
Diffstat (limited to 'lisp/subr.el')
-rw-r--r-- | lisp/subr.el | 306 |
1 files changed, 194 insertions, 112 deletions
diff --git a/lisp/subr.el b/lisp/subr.el index efea412af0e..89ceb9ba55f 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -22,20 +22,18 @@ ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. -;;; Commentary: - -;;; Code: - ;; Beware: while this file has tag `utf-8', before it's compiled, it gets ;; loaded as "raw-text", so non-ASCII chars won't work right during bootstrap. -(defmacro declare-function (_fn _file &optional _arglist _fileonly) + +;; declare-function's args use &rest, not &optional, for compatibility +;; with byte-compile-macroexpand-declare-function. + +(defmacro declare-function (_fn _file &rest _args) "Tell the byte-compiler that function FN is defined, in FILE. -Optional ARGLIST is the argument list used by the function. The FILE argument is not used by the byte-compiler, but by the `check-declare' package, which checks that FILE contains a -definition for FN. ARGLIST is used by both the byte-compiler -and `check-declare' to check for consistency. +definition for FN. FILE can be either a Lisp file (in which case the \".el\" extension is optional), or a C file. C files are expanded @@ -46,19 +44,22 @@ declaration. A FILE with an \"ext:\" prefix is an external file. `check-declare' will check such files if they are found, and skip them without error if they are not. -FILEONLY non-nil means that `check-declare' will only check that -FILE exists, not that it defines FN. This is intended for -function-definitions that `check-declare' does not recognize, e.g. -`defstruct'. +Optional ARGLIST specifies FN's arguments, or is t to not specify +FN's arguments. An omitted ARGLIST defaults to t, not nil: a nil +ARGLIST specifies an empty argument list, and an explicit t +ARGLIST is a placeholder that allows supplying a later arg. -To specify a value for FILEONLY without passing an argument list, -set ARGLIST to t. This is necessary because nil means an -empty argument list, rather than an unspecified one. +Optional FILEONLY non-nil means that `check-declare' will check +only that FILE exists, not that it defines FN. This is intended +for function definitions that `check-declare' does not recognize, +e.g., `defstruct'. Note that for the purposes of `check-declare', this statement must be the first non-whitespace on a line. For more information, see Info node `(elisp)Declaring Functions'." + (declare (advertised-calling-convention + (fn file &optional arglist fileonly) nil)) ;; Does nothing - byte-compile-declare-function does the work. nil) @@ -66,6 +67,7 @@ For more information, see Info node `(elisp)Declaring Functions'." ;;;; Basic Lisp macros. (defalias 'not 'null) +(defalias 'sxhash 'sxhash-equal) (defmacro noreturn (form) "Evaluate FORM, expecting it not to return. @@ -512,7 +514,8 @@ argument VECP, this copies vectors as well as conses." (setq newcar (copy-tree (car tree) vecp))) (push newcar result)) (setq tree (cdr tree))) - (nconc (nreverse result) tree)) + (nconc (nreverse result) + (if (and vecp (vectorp tree)) (copy-tree tree vecp) tree))) (if (and vecp (vectorp tree)) (let ((i (length (setq tree (copy-sequence tree))))) (while (>= (setq i (1- i)) 0) @@ -859,7 +862,12 @@ 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: ") + (interactive + (let* ((menu-prompting nil) + (key (read-key-sequence "Set key globally: "))) + (list key + (read-command (format "Set key %s to command: " + (key-description key)))))) (or (vectorp key) (stringp key) (signal 'wrong-type-argument (list 'arrayp key))) (define-key (current-global-map) key command)) @@ -1283,27 +1291,14 @@ be a list of the form returned by `event-start' and `event-end'." ;;;; Obsolescent names for functions. -(define-obsolete-function-alias 'window-dot 'window-point "22.1") -(define-obsolete-function-alias 'set-window-dot 'set-window-point "22.1") -(define-obsolete-function-alias 'read-input 'read-string "22.1") -(define-obsolete-function-alias 'show-buffer 'set-window-buffer "22.1") -(define-obsolete-function-alias 'eval-current-buffer 'eval-buffer "22.1") -(define-obsolete-function-alias 'string-to-int 'string-to-number "22.1") - (make-obsolete 'forward-point "use (+ (point) N) instead." "23.1") (make-obsolete 'buffer-has-markers-at nil "24.3") -(defun insert-string (&rest args) - "Mocklisp-compatibility insert function. -Like the function `insert' except that any argument that is a number -is converted into a string by expressing it in decimal." - (declare (obsolete insert "22.1")) - (dolist (el args) - (insert (if (integerp el) (number-to-string el) el)))) - -(defun makehash (&optional test) - (declare (obsolete make-hash-table "22.1")) - (make-hash-table :test (or test 'eql))) +;; bug#23850 +(make-obsolete 'string-to-unibyte "use `encode-coding-string'." "26.1") +(make-obsolete 'string-as-unibyte "use `encode-coding-string'." "26.1") +(make-obsolete 'string-to-multibyte "use `decode-coding-string'." "26.1") +(make-obsolete 'string-as-multibyte "use `decode-coding-string'." "26.1") (defun log10 (x) "Return (log X 10), the log base 10 of X." @@ -1315,57 +1310,15 @@ is converted into a string by expressing it in decimal." (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 - "explicitly check for a frame-parameter instead." "22.2") + (set-advertised-calling-convention 'all-completions '(string collection &optional predicate) "23.1") (set-advertised-calling-convention 'unintern '(name obarray) "23.3") (set-advertised-calling-convention 'indirect-function '(object) "25.1") (set-advertised-calling-convention 'redirect-frame-focus '(frame focus-frame) "24.3") -(set-advertised-calling-convention 'decode-char '(ch charset) "21.4") -(set-advertised-calling-convention 'encode-char '(ch charset) "21.4") ;;;; Obsolescence declarations for variables, and aliases. -;; Special "default-FOO" variables which contain the default value of -;; the "FOO" variable are nasty. Their implementation is brittle, and -;; slows down several unrelated variable operations; furthermore, they -;; can lead to really odd behavior if you decide to make them -;; buffer-local. - -;; Not used at all in Emacs, last time I checked: -(make-obsolete-variable 'default-mode-line-format - "use (setq-default mode-line-format) or (default-value mode-line-format) instead" - "23.2") -(make-obsolete-variable 'default-header-line-format 'header-line-format "23.2") -(make-obsolete-variable 'default-line-spacing 'line-spacing "23.2") -(make-obsolete-variable 'default-abbrev-mode 'abbrev-mode "23.2") -(make-obsolete-variable 'default-ctl-arrow 'ctl-arrow "23.2") -(make-obsolete-variable 'default-truncate-lines 'truncate-lines "23.2") -(make-obsolete-variable 'default-left-margin 'left-margin "23.2") -(make-obsolete-variable 'default-tab-width 'tab-width "23.2") -(make-obsolete-variable 'default-case-fold-search 'case-fold-search "23.2") -(make-obsolete-variable 'default-left-margin-width 'left-margin-width "23.2") -(make-obsolete-variable 'default-right-margin-width 'right-margin-width "23.2") -(make-obsolete-variable 'default-left-fringe-width 'left-fringe-width "23.2") -(make-obsolete-variable 'default-right-fringe-width 'right-fringe-width "23.2") -(make-obsolete-variable 'default-fringes-outside-margins 'fringes-outside-margins "23.2") -(make-obsolete-variable 'default-scroll-bar-width 'scroll-bar-width "23.2") -(make-obsolete-variable 'default-vertical-scroll-bar 'vertical-scroll-bar "23.2") -(make-obsolete-variable 'default-indicate-empty-lines 'indicate-empty-lines "23.2") -(make-obsolete-variable 'default-indicate-buffer-boundaries 'indicate-buffer-boundaries "23.2") -(make-obsolete-variable 'default-fringe-indicator-alist 'fringe-indicator-alist "23.2") -(make-obsolete-variable 'default-fringe-cursor-alist 'fringe-cursor-alist "23.2") -(make-obsolete-variable 'default-scroll-up-aggressively 'scroll-up-aggressively "23.2") -(make-obsolete-variable 'default-scroll-down-aggressively 'scroll-down-aggressively "23.2") -(make-obsolete-variable 'default-fill-column 'fill-column "23.2") -(make-obsolete-variable 'default-cursor-type 'cursor-type "23.2") -(make-obsolete-variable 'default-cursor-in-non-selected-windows 'cursor-in-non-selected-windows "23.2") -(make-obsolete-variable 'default-buffer-file-coding-system 'buffer-file-coding-system "23.2") -(make-obsolete-variable 'default-major-mode 'major-mode "23.2") -(make-obsolete-variable 'default-enable-multibyte-characters - "use enable-multibyte-characters or set-buffer-multibyte instead" "23.2") - (make-obsolete-variable 'define-key-rebound-commands nil "23.2") (make-obsolete-variable 'redisplay-end-trigger-functions 'jit-lock-register "23.1") (make-obsolete-variable 'deferred-action-list 'post-command-hook "24.1") @@ -1548,6 +1501,10 @@ FUN is then called once." (declare (indent 2) (debug (form sexp body)) (obsolete "use a <foo>-function variable modified by `add-function'." "24.4")) + `(subr--with-wrapper-hook-no-warnings ,hook ,args ,@body)) + +(defmacro subr--with-wrapper-hook-no-warnings (hook args &rest body) + "Like (with-wrapper-hook HOOK ARGS BODY), but without warnings." ;; We need those two gensyms because CL's lexical scoping is not available ;; for function arguments :-( (let ((funs (make-symbol "funs")) @@ -1623,7 +1580,7 @@ can do the job." ;; FIXME: We should also emit a warning for let-bound ;; variables with dynamic binding. (when (assq sym byte-compile--lexical-environment) - (byte-compile-log-warning msg t :error)))) + (byte-compile-report-error msg :fill)))) (code (macroexp-let2 macroexp-copyable-p x element `(if ,(if compare-fn @@ -1738,6 +1695,11 @@ if it is empty or a duplicate." (make-variable-buffer-local 'delayed-mode-hooks) (put 'delay-mode-hooks 'permanent-local t) +(defvar delayed-after-hook-forms nil + "List of delayed :after-hook forms waiting to be run. +These forms come from `define-derived-mode'.") +(make-variable-buffer-local 'delayed-after-hook-forms) + (defvar change-major-mode-after-body-hook nil "Normal hook run in major mode functions, before the mode hooks.") @@ -1746,12 +1708,19 @@ if it is empty or a duplicate." (defun run-mode-hooks (&rest hooks) "Run mode hooks `delayed-mode-hooks' and HOOKS, or delay HOOKS. -If the variable `delay-mode-hooks' is non-nil, does not run any hooks, +Call `hack-local-variables' to set up file local and directory local +variables. + +If the variable `delay-mode-hooks' is non-nil, does not do anything, just adds the HOOKS to the list `delayed-mode-hooks'. Otherwise, runs hooks in the sequence: `change-major-mode-after-body-hook', -`delayed-mode-hooks' (in reverse order), HOOKS, and finally -`after-change-major-mode-hook'. Major mode functions should use -this instead of `run-hooks' when running their FOO-mode-hook." +`delayed-mode-hooks' (in reverse order), HOOKS, then runs +`hack-local-variables', runs the hook `after-change-major-mode-hook', and +finally evaluates the forms in `delayed-after-hook-forms' (see +`define-derived-mode'). + +Major mode functions should use this instead of `run-hooks' when +running their FOO-mode-hook." (if delay-mode-hooks ;; Delaying case. (dolist (hook hooks) @@ -1760,7 +1729,13 @@ this instead of `run-hooks' when running their FOO-mode-hook." (setq hooks (nconc (nreverse delayed-mode-hooks) hooks)) (setq delayed-mode-hooks nil) (apply 'run-hooks (cons 'change-major-mode-after-body-hook hooks)) - (run-hooks 'after-change-major-mode-hook))) + (if (buffer-file-name) + (with-demoted-errors "File local-variables error: %s" + (hack-local-variables 'no-mode))) + (run-hooks 'after-change-major-mode-hook) + (dolist (form (nreverse delayed-after-hook-forms)) + (eval form)) + (setq delayed-after-hook-forms nil))) (defmacro delay-mode-hooks (&rest body) "Execute BODY, but delay any `run-mode-hooks'. @@ -1903,7 +1878,7 @@ definition, variable definition, or face definition only." (autoloadp (symbol-function symbol))) (nth 1 (symbol-function symbol)) (let ((files load-history) - file) + file match) (while files (if (if type (if (eq type 'defvar) @@ -1914,7 +1889,8 @@ definition, variable definition, or face definition only." ;; We accept all types, so look for variable def ;; and then for any other kind. (or (member symbol (cdr (car files))) - (rassq symbol (cdr (car files))))) + (and (setq match (rassq symbol (cdr (car files)))) + (not (eq 'require (car match)))))) (setq file (car (car files)) files nil)) (setq files (cdr files))) file))) @@ -2505,26 +2481,27 @@ This finishes the change group by reverting all of its changes." ;; 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)))))) + (let ((old-car (car-safe elt)) + (old-cdr (cdr-safe elt))) + (unwind-protect + (progn + ;; 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))) + ;; Revert the undo info to what it was when we grabbed + ;; the state. + (setq buffer-undo-list elt)) + ;; Reset the modified cons cell ELT to its original content. + (when (consp elt) + (setcar elt old-car) + (setcdr elt old-cdr)))))))) ;;;; Display-related functions. @@ -3025,6 +3002,28 @@ Similar to `call-process-shell-command', but calls `process-file'." infile buffer display (if (file-remote-p default-directory) "-c" shell-command-switch) (mapconcat 'identity (cons command args) " "))) + +(defun call-shell-region (start end command &optional delete buffer) + "Send text from START to END as input to an inferior shell running COMMAND. +Delete the text if fourth arg DELETE is non-nil. + +Insert output in BUFFER before point; t means current buffer; nil for + BUFFER means discard it; 0 means discard and don't wait; and `(:file + FILE)', where FILE is a file name string, means that it should be + written to that file (if the file already exists it is overwritten). +BUFFER can also have the form (REAL-BUFFER STDERR-FILE); in that case, +REAL-BUFFER says what to do with standard output, as above, +while STDERR-FILE says what to do with standard error in the child. +STDERR-FILE may be nil (discard standard error output), +t (mix it with ordinary output), or a file name string. + +If BUFFER is 0, `call-shell-region' returns immediately with value nil. +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." + (call-process-region start end + shell-file-name delete buffer nil + shell-command-switch command)) ;;;; Lisp macros to do various things temporarily. @@ -3336,6 +3335,11 @@ is allowed once again. (Immediately, if `inhibit-quit' is nil.)" ;; that intends to handle the quit signal next time. (eval '(ignore nil))))) +;; Don't throw `throw-on-input' on those events by default. +(setq while-no-input-ignore-events + '(focus-in focus-out help-echo iconify-frame + make-frame-visible selection-request)) + (defmacro while-no-input (&rest body) "Execute BODY only as long as there's no pending input. If input arrives, that ends the execution of BODY, @@ -3983,7 +3987,7 @@ This function is called directly from the C code." (expand-file-name byte-compile-current-file byte-compile-root-dir))) - (byte-compile-log-warning msg)) + (byte-compile-warn "%s" msg)) (run-with-timer 0 nil (lambda (msg) (message "%s" msg)) @@ -4120,8 +4124,7 @@ and the function returns nil. Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil. This function is like `forward-word', but it is not affected -by `find-word-boundary-function-table' (as set up by -e.g. `subword-mode'). It is also not interactive." +by `find-word-boundary-function-table'. It is also not interactive." (let ((find-word-boundary-function-table (if (char-table-p word-move-empty-char-table) word-move-empty-char-table @@ -4134,8 +4137,7 @@ With argument ARG, do this that many times. If ARG is omitted or nil, move point backward one word. This function is like `forward-word', but it is not affected -by `find-word-boundary-function-table' (as set up by -e.g. `subword-mode'). It is also not interactive." +by `find-word-boundary-function-table'. It is also not interactive." (let ((find-word-boundary-function-table (if (char-table-p word-move-empty-char-table) word-move-empty-char-table @@ -4331,6 +4333,51 @@ The properties used on SYMBOL are `composefunc', `sendfunc', (put symbol 'sendfunc sendfunc) (put symbol 'abortfunc (or abortfunc 'kill-buffer)) (put symbol 'hookvar (or hookvar 'mail-send-hook))) + + +(defun backtrace--print-frame (evald func args flags) + "Print a trace of a single stack frame to `standard-output'. +EVALD, FUNC, ARGS, FLAGS are as in `mapbacktrace'." + (princ (if (plist-get flags :debug-on-exit) "* " " ")) + (cond + ((and evald (not debugger-stack-frame-as-list)) + (prin1 func) + (if args (prin1 args) (princ "()"))) + (t + (prin1 (cons func args)))) + (princ "\n")) + +(defun backtrace () + "Print a trace of Lisp function calls currently active. +Output stream used is value of `standard-output'." + (let ((print-level (or print-level 8))) + (mapbacktrace #'backtrace--print-frame 'backtrace))) + +(defun backtrace-frames (&optional base) + "Collect all frames of current backtrace into a list. +If non-nil, BASE should be a function, and frames before its +nearest activation frames are discarded." + (let ((frames nil)) + (mapbacktrace (lambda (&rest frame) (push frame frames)) + (or base 'backtrace-frames)) + (nreverse frames))) + +(defun backtrace-frame (nframes &optional base) + "Return the function and arguments NFRAMES up from current execution point. +If non-nil, BASE should be a function, and NFRAMES counts from its +nearest activation frame. +If the frame has not evaluated the arguments yet (or is a special form), +the value is (nil FUNCTION ARG-FORMS...). +If the frame has evaluated its arguments and called its function already, +the value is (t FUNCTION ARG-VALUES...). +A &rest arg is represented as the tail of the list ARG-VALUES. +FUNCTION is whatever was supplied as car of evaluated list, +or a lambda expression for macro calls. +If NFRAMES is more than the number of frames, the value is nil." + (backtrace-frame--internal + (lambda (evald func args _) `(,evald ,func ,@args)) + nframes (or base 'backtrace-frame))) + (defvar called-interactively-p-functions nil "Special hook called to skip special frames in `called-interactively-p'. @@ -4494,7 +4541,8 @@ to deactivate this transient map, regardless of KEEP-PRED." (with-demoted-errors "set-transient-map PCH: %S" (unless (cond ((null keep-pred) nil) - ((not (eq map (cadr overriding-terminal-local-map))) + ((and (not (eq map (cadr overriding-terminal-local-map))) + (memq map (cddr overriding-terminal-local-map))) ;; There's presumably some other transient-map in ;; effect. Wait for that one to terminate before we ;; remove ourselves. @@ -4949,7 +4997,41 @@ as a list.") "-pkg.el")) +;;; Thread support. + +(defmacro with-mutex (mutex &rest body) + "Invoke BODY with MUTEX held, releasing MUTEX when done. +This is the simplest safe way to acquire and release a mutex." + (declare (indent 1) (debug t)) + (let ((sym (make-symbol "mutex"))) + `(let ((,sym ,mutex)) + (mutex-lock ,sym) + (unwind-protect + (progn ,@body) + (mutex-unlock ,sym))))) + + ;;; Misc. + +(defvar definition-prefixes (make-hash-table :test 'equal) + "Hash table mapping prefixes to the files in which they're used. +This can be used to automatically fetch not-yet-loaded definitions. +More specifically, if there is a value of the form (FILES...) for a string PREFIX +it means that the FILES define variables or functions with names that start +with PREFIX. + +Note that it does not imply that all definitions starting with PREFIX can +be found in those files. E.g. if prefix is \"gnus-article-\" there might +still be definitions of the form \"gnus-article-toto-titi\" in other files, which would +presumably appear in this table under another prefix such as \"gnus-\" +or \"gnus-article-toto-\".") + +(defun register-definition-prefixes (file prefixes) + "Register that FILE uses PREFIXES." + (dolist (prefix prefixes) + (puthash prefix (cons file (gethash prefix definition-prefixes)) + definition-prefixes))) + (defconst menu-bar-separator '("--") "Separator for menus.") |