aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/subr.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/subr.el')
-rw-r--r--lisp/subr.el148
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'.
3966The functions are called with 3 arguments: (I FRAME1 FRAME2),
3967where FRAME1 is a \"current frame\", FRAME2 is the next frame,
3968I is the index of the frame after FRAME2. It should return nil
3969if those frames don't seem special and otherwise, it should return
3970the 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'.
3989If KIND is `interactive', then only return t if the call was made
3990interactively by the user, i.e. not in `noninteractive' mode nor
3991when `executing-kbd-macro'.
3992If KIND is `any', on the other hand, it will return t for any kind of
3993interactive call, including being called as the binding of a key or
3994from a keyboard macro, even in `noninteractive' mode.
3995
3996This function is very brittle, it may fail to return the intended result when
3997the code is debugged, advised, or instrumented in some form. Some macros and
3998special forms (such as `condition-case') may also sometimes wrap their bodies
3999in a `lambda', so any call to `called-interactively-p' from those bodies will
4000indicate whether that lambda (rather than the surrounding function) was called
4001interactively.
4002
4003Instead of using this function, it is cleaner and more reliable to give your
4004function an extra optional argument whose `interactive' spec specifies
4005non-nil unconditionally (\"p\" is a good way to do this), or via
4006\(not (or executing-kbd-macro noninteractive)).
4007
4008The only known proper use of `interactive' for KIND is in deciding
4009whether to display a helpful message, or how to display it. If you're
4010thinking of using it for any other purpose, it is quite likely that
4011you're making a mistake. Think: what do you want to do when the
4012command 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.
4066This means that the function was called with `call-interactively'
4067\(which includes being called as the binding of a key)
4068and input is currently coming from the keyboard (not a keyboard macro),
4069and Emacs is not running in batch mode (`noninteractive' is nil).
4070
4071The only known proper use of `interactive-p' is in deciding whether to
4072display a helpful message, or how to display it. If you're thinking
4073of using it for any other purpose, it is quite likely that you're
4074making a mistake. Think: what do you want to do when the command is
4075called from a keyboard macro or in batch mode?
4076
4077To test whether your function was called with `call-interactively',
4078either (i) add an extra optional argument and give it an `interactive'
4079spec that specifies non-nil unconditionally (such as \"p\"); or (ii)
4080use `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.
4086If the maximum arity is infinite, MAX is `many'.
4087F can be a function or a macro.
4088If 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.
3968Note that this does NOT take precedence over the \"overriding\" maps 4112Note that this does NOT take precedence over the \"overriding\" maps