diff options
Diffstat (limited to 'lisp/subr.el')
| -rw-r--r-- | lisp/subr.el | 148 |
1 files changed, 146 insertions, 2 deletions
diff --git a/lisp/subr.el b/lisp/subr.el index 8410897fd6f..c0479d35987 100644 --- a/lisp/subr.el +++ b/lisp/subr.el | |||
| @@ -1191,8 +1191,6 @@ is converted into a string by expressing it in decimal." | |||
| 1191 | (make-obsolete 'unfocus-frame "it does nothing." "22.1") | 1191 | (make-obsolete 'unfocus-frame "it does nothing." "22.1") |
| 1192 | (make-obsolete 'make-variable-frame-local | 1192 | (make-obsolete 'make-variable-frame-local |
| 1193 | "explicitly check for a frame-parameter instead." "22.2") | 1193 | "explicitly check for a frame-parameter instead." "22.2") |
| 1194 | (make-obsolete 'interactive-p 'called-interactively-p "23.2") | ||
| 1195 | (set-advertised-calling-convention 'called-interactively-p '(kind) "23.1") | ||
| 1196 | (set-advertised-calling-convention | 1194 | (set-advertised-calling-convention |
| 1197 | 'all-completions '(string collection &optional predicate) "23.1") | 1195 | 'all-completions '(string collection &optional predicate) "23.1") |
| 1198 | (set-advertised-calling-convention 'unintern '(name obarray) "23.3") | 1196 | (set-advertised-calling-convention 'unintern '(name obarray) "23.3") |
| @@ -3963,6 +3961,152 @@ The properties used on SYMBOL are `composefunc', `sendfunc', | |||
| 3963 | (put symbol 'abortfunc (or abortfunc 'kill-buffer)) | 3961 | (put symbol 'abortfunc (or abortfunc 'kill-buffer)) |
| 3964 | (put symbol 'hookvar (or hookvar 'mail-send-hook))) | 3962 | (put symbol 'hookvar (or hookvar 'mail-send-hook))) |
| 3965 | 3963 | ||
| 3964 | (defvar called-interactively-p-functions nil | ||
| 3965 | "Special hook called to skip special frames in `called-interactively-p'. | ||
| 3966 | The functions are called with 3 arguments: (I FRAME1 FRAME2), | ||
| 3967 | where FRAME1 is a \"current frame\", FRAME2 is the next frame, | ||
| 3968 | I is the index of the frame after FRAME2. It should return nil | ||
| 3969 | if those frames don't seem special and otherwise, it should return | ||
| 3970 | the number of frames to skip (minus 1).") | ||
| 3971 | |||
| 3972 | (defmacro internal--called-interactively-p--get-frame (n) | ||
| 3973 | ;; `sym' will hold a global variable, which will be used kind of like C's | ||
| 3974 | ;; "static" variables. | ||
| 3975 | (let ((sym (make-symbol "base-index"))) | ||
| 3976 | `(progn | ||
| 3977 | (defvar ,sym | ||
| 3978 | (let ((i 1)) | ||
| 3979 | (while (not (eq (nth 1 (backtrace-frame i)) | ||
| 3980 | 'called-interactively-p)) | ||
| 3981 | (setq i (1+ i))) | ||
| 3982 | i)) | ||
| 3983 | ;; (unless (eq (nth 1 (backtrace-frame ,sym)) 'called-interactively-p) | ||
| 3984 | ;; (error "called-interactively-p: %s is out-of-sync!" ,sym)) | ||
| 3985 | (backtrace-frame (+ ,sym ,n))))) | ||
| 3986 | |||
| 3987 | (defun called-interactively-p (&optional kind) | ||
| 3988 | "Return t if the containing function was called by `call-interactively'. | ||
| 3989 | If KIND is `interactive', then only return t if the call was made | ||
| 3990 | interactively by the user, i.e. not in `noninteractive' mode nor | ||
| 3991 | when `executing-kbd-macro'. | ||
| 3992 | If KIND is `any', on the other hand, it will return t for any kind of | ||
| 3993 | interactive call, including being called as the binding of a key or | ||
| 3994 | from a keyboard macro, even in `noninteractive' mode. | ||
| 3995 | |||
| 3996 | This function is very brittle, it may fail to return the intended result when | ||
| 3997 | the code is debugged, advised, or instrumented in some form. Some macros and | ||
| 3998 | special forms (such as `condition-case') may also sometimes wrap their bodies | ||
| 3999 | in a `lambda', so any call to `called-interactively-p' from those bodies will | ||
| 4000 | indicate whether that lambda (rather than the surrounding function) was called | ||
| 4001 | interactively. | ||
| 4002 | |||
| 4003 | Instead of using this function, it is cleaner and more reliable to give your | ||
| 4004 | function an extra optional argument whose `interactive' spec specifies | ||
| 4005 | non-nil unconditionally (\"p\" is a good way to do this), or via | ||
| 4006 | \(not (or executing-kbd-macro noninteractive)). | ||
| 4007 | |||
| 4008 | The only known proper use of `interactive' for KIND is in deciding | ||
| 4009 | whether to display a helpful message, or how to display it. If you're | ||
| 4010 | thinking of using it for any other purpose, it is quite likely that | ||
| 4011 | you're making a mistake. Think: what do you want to do when the | ||
| 4012 | command is called from a keyboard macro?" | ||
| 4013 | (declare (advertised-calling-convention (kind) "23.1")) | ||
| 4014 | (when (not (and (eq kind 'interactive) | ||
| 4015 | (or executing-kbd-macro noninteractive))) | ||
| 4016 | (let* ((i 1) ;; 0 is the called-interactively-p frame. | ||
| 4017 | frame nextframe | ||
| 4018 | (get-next-frame | ||
| 4019 | (lambda () | ||
| 4020 | (setq frame nextframe) | ||
| 4021 | (setq nextframe (internal--called-interactively-p--get-frame i)) | ||
| 4022 | ;; (message "Frame %d = %S" i nextframe) | ||
| 4023 | (setq i (1+ i))))) | ||
| 4024 | (funcall get-next-frame) ;; Get the first frame. | ||
| 4025 | (while | ||
| 4026 | ;; FIXME: The edebug and advice handling should be made modular and | ||
| 4027 | ;; provided directly by edebug.el and nadvice.el. | ||
| 4028 | (progn | ||
| 4029 | ;; frame =(backtrace-frame i-2) | ||
| 4030 | ;; nextframe=(backtrace-frame i-1) | ||
| 4031 | (funcall get-next-frame) | ||
| 4032 | ;; `pcase' would be a fairly good fit here, but it sometimes moves | ||
| 4033 | ;; branches within local functions, which then messes up the | ||
| 4034 | ;; `backtrace-frame' data we get, | ||
| 4035 | (or | ||
| 4036 | ;; Skip special forms (from non-compiled code). | ||
| 4037 | (and frame (null (car frame))) | ||
| 4038 | ;; Skip also `interactive-p' (because we don't want to know if | ||
| 4039 | ;; interactive-p was called interactively but if it's caller was) | ||
| 4040 | ;; and `byte-code' (idem; this appears in subexpressions of things | ||
| 4041 | ;; like condition-case, which are wrapped in a separate bytecode | ||
| 4042 | ;; chunk). | ||
| 4043 | ;; FIXME: For lexical-binding code, this is much worse, | ||
| 4044 | ;; because the frames look like "byte-code -> funcall -> #[...]", | ||
| 4045 | ;; which is not a reliable signature. | ||
| 4046 | (memq (nth 1 frame) '(interactive-p 'byte-code)) | ||
| 4047 | ;; Skip package-specific stack-frames. | ||
| 4048 | (let ((skip (run-hook-with-args-until-success | ||
| 4049 | 'called-interactively-p-functions | ||
| 4050 | i frame nextframe))) | ||
| 4051 | (pcase skip | ||
| 4052 | (`nil nil) | ||
| 4053 | (`0 t) | ||
| 4054 | (_ (setq i (+ i skip -1)) (funcall get-next-frame))))))) | ||
| 4055 | ;; Now `frame' should be "the function from which we were called". | ||
| 4056 | (pcase (cons frame nextframe) | ||
| 4057 | ;; No subr calls `interactive-p', so we can rule that out. | ||
| 4058 | (`((,_ ,(pred (lambda (f) (subrp (indirect-function f)))) . ,_) . ,_) nil) | ||
| 4059 | ;; Somehow, I sometimes got `command-execute' rather than | ||
| 4060 | ;; `call-interactively' on my stacktrace !? | ||
| 4061 | ;;(`(,_ . (t command-execute . ,_)) t) | ||
| 4062 | (`(,_ . (t call-interactively . ,_)) t))))) | ||
| 4063 | |||
| 4064 | (defun interactive-p () | ||
| 4065 | "Return t if the containing function was run directly by user input. | ||
| 4066 | This means that the function was called with `call-interactively' | ||
| 4067 | \(which includes being called as the binding of a key) | ||
| 4068 | and input is currently coming from the keyboard (not a keyboard macro), | ||
| 4069 | and Emacs is not running in batch mode (`noninteractive' is nil). | ||
| 4070 | |||
| 4071 | The only known proper use of `interactive-p' is in deciding whether to | ||
| 4072 | display a helpful message, or how to display it. If you're thinking | ||
| 4073 | of using it for any other purpose, it is quite likely that you're | ||
| 4074 | making a mistake. Think: what do you want to do when the command is | ||
| 4075 | called from a keyboard macro or in batch mode? | ||
| 4076 | |||
| 4077 | To test whether your function was called with `call-interactively', | ||
| 4078 | either (i) add an extra optional argument and give it an `interactive' | ||
| 4079 | spec that specifies non-nil unconditionally (such as \"p\"); or (ii) | ||
| 4080 | use `called-interactively-p'." | ||
| 4081 | (declare (obsolete called-interactively-p "23.2")) | ||
| 4082 | (called-interactively-p 'interactive)) | ||
| 4083 | |||
| 4084 | (defun function-arity (f &optional num) | ||
| 4085 | "Return the (MIN . MAX) arity of F. | ||
| 4086 | If the maximum arity is infinite, MAX is `many'. | ||
| 4087 | F can be a function or a macro. | ||
| 4088 | If NUM is non-nil, return non-nil iff F can be called with NUM args." | ||
| 4089 | (if (symbolp f) (setq f (indirect-function f))) | ||
| 4090 | (if (eq (car-safe f) 'macro) (setq f (cdr f))) | ||
| 4091 | (let ((res | ||
| 4092 | (if (subrp f) | ||
| 4093 | (let ((x (subr-arity f))) | ||
| 4094 | (if (eq (cdr x) 'unevalled) (cons (car x) 'many))) | ||
| 4095 | (let* ((args (if (consp f) (cadr f) (aref f 0))) | ||
| 4096 | (max (length args)) | ||
| 4097 | (opt (memq '&optional args)) | ||
| 4098 | (rest (memq '&rest args)) | ||
| 4099 | (min (- max (length opt)))) | ||
| 4100 | (if opt | ||
| 4101 | (cons min (if rest 'many (1- max))) | ||
| 4102 | (if rest | ||
| 4103 | (cons (- max (length rest)) 'many) | ||
| 4104 | (cons min max))))))) | ||
| 4105 | (if (not num) | ||
| 4106 | res | ||
| 4107 | (and (>= num (car res)) | ||
| 4108 | (or (eq 'many (cdr res)) (<= num (cdr res))))))) | ||
| 4109 | |||
| 3966 | (defun set-temporary-overlay-map (map &optional keep-pred) | 4110 | (defun set-temporary-overlay-map (map &optional keep-pred) |
| 3967 | "Set MAP as a temporary keymap taking precedence over most other keymaps. | 4111 | "Set MAP as a temporary keymap taking precedence over most other keymaps. |
| 3968 | Note that this does NOT take precedence over the \"overriding\" maps | 4112 | Note that this does NOT take precedence over the \"overriding\" maps |