aboutsummaryrefslogtreecommitdiffstats
path: root/src/eval.c
diff options
context:
space:
mode:
authorStefan Monnier2022-04-26 10:36:52 -0400
committerStefan Monnier2022-04-26 10:36:52 -0400
commitbffc4cb39dc7b83fc4a1bffd23eeed2774b79444 (patch)
tree103b22b517aafd70b16fe2d1dea06cb4673668f5 /src/eval.c
parent756b7cf5d9a817503437b3e8a9e8d912b7ee6c75 (diff)
downloademacs-bffc4cb39dc7b83fc4a1bffd23eeed2774b79444.tar.gz
emacs-bffc4cb39dc7b83fc4a1bffd23eeed2774b79444.zip
New generic function `oclosure-interactive-form`
It's used by `interactive-form` when it encounters an OClosure. This lets one compute the `interactive-form` of OClosures dynamically by adding appropriate methods. This does not include support for `command-modes` for Oclosures. * lisp/simple.el (oclosure-interactive-form): New generic function. * src/data.c (Finteractive_form): Delegate to `oclosure-interactive-form` if the arg is an OClosure. (syms_of_data): New symbol `Qoclosure_interactive_form`. * src/eval.c (Fcommandp): Delegate to `interactive-form` if the arg is an OClosure. * src/lisp.h (VALID_DOCSTRING_P): New function, extracted from `store_function_docstring`. * src/doc.c (store_function_docstring): Use it. * lisp/kmacro.el (kmacro): Don't carry any interactive form. (oclosure-interactive-form) <kmacro>: New method, instead. * test/lisp/emacs-lisp/oclosure-tests.el (oclosure-interactive-form) <oclosure-test>: New method. (oclosure-test-interactive-form): New test. * doc/lispref/commands.texi (Using Interactive): Document `oclosure-interactive-form`.
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c94
1 files changed, 65 insertions, 29 deletions
diff --git a/src/eval.c b/src/eval.c
index 37bc03465cc..77ec47e2b79 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2032,8 +2032,7 @@ then strings and vectors are not accepted. */)
2032 (Lisp_Object function, Lisp_Object for_call_interactively) 2032 (Lisp_Object function, Lisp_Object for_call_interactively)
2033{ 2033{
2034 register Lisp_Object fun; 2034 register Lisp_Object fun;
2035 register Lisp_Object funcar; 2035 bool genfun = false; /* If true, we should consult `interactive-form'. */
2036 Lisp_Object if_prop = Qnil;
2037 2036
2038 fun = function; 2037 fun = function;
2039 2038
@@ -2041,52 +2040,89 @@ then strings and vectors are not accepted. */)
2041 if (NILP (fun)) 2040 if (NILP (fun))
2042 return Qnil; 2041 return Qnil;
2043 2042
2044 /* Check an `interactive-form' property if present, analogous to the
2045 function-documentation property. */
2046 fun = function;
2047 while (SYMBOLP (fun))
2048 {
2049 Lisp_Object tmp = Fget (fun, Qinteractive_form);
2050 if (!NILP (tmp))
2051 if_prop = Qt;
2052 fun = Fsymbol_function (fun);
2053 }
2054
2055 /* Emacs primitives are interactive if their DEFUN specifies an 2043 /* Emacs primitives are interactive if their DEFUN specifies an
2056 interactive spec. */ 2044 interactive spec. */
2057 if (SUBRP (fun)) 2045 if (SUBRP (fun))
2058 return XSUBR (fun)->intspec.string ? Qt : if_prop; 2046 {
2059 2047 if (XSUBR (fun)->intspec.string)
2048 return Qt;
2049 }
2060 /* Bytecode objects are interactive if they are long enough to 2050 /* Bytecode objects are interactive if they are long enough to
2061 have an element whose index is COMPILED_INTERACTIVE, which is 2051 have an element whose index is COMPILED_INTERACTIVE, which is
2062 where the interactive spec is stored. */ 2052 where the interactive spec is stored. */
2063 else if (COMPILEDP (fun)) 2053 else if (COMPILEDP (fun))
2064 return (PVSIZE (fun) > COMPILED_INTERACTIVE ? Qt : if_prop); 2054 {
2055 if (PVSIZE (fun) > COMPILED_INTERACTIVE)
2056 return Qt;
2057 else if (PVSIZE (fun) > COMPILED_DOC_STRING)
2058 {
2059 Lisp_Object doc = AREF (fun, COMPILED_DOC_STRING);
2060 /* An invalid "docstring" is a sign that we have an OClosure. */
2061 genfun = !(NILP (doc) || VALID_DOCSTRING_P (doc));
2062 }
2063 }
2065 2064
2066#ifdef HAVE_MODULES 2065#ifdef HAVE_MODULES
2067 /* Module functions are interactive if their `interactive_form' 2066 /* Module functions are interactive if their `interactive_form'
2068 field is non-nil. */ 2067 field is non-nil. */
2069 else if (MODULE_FUNCTIONP (fun)) 2068 else if (MODULE_FUNCTIONP (fun))
2070 return NILP (module_function_interactive_form (XMODULE_FUNCTION (fun))) 2069 {
2071 ? if_prop 2070 if (!NILP (module_function_interactive_form (XMODULE_FUNCTION (fun))))
2072 : Qt; 2071 return Qt;
2072 }
2073#endif 2073#endif
2074 2074
2075 /* Strings and vectors are keyboard macros. */ 2075 /* Strings and vectors are keyboard macros. */
2076 if (STRINGP (fun) || VECTORP (fun)) 2076 else if (STRINGP (fun) || VECTORP (fun))
2077 return (NILP (for_call_interactively) ? Qt : Qnil); 2077 return (NILP (for_call_interactively) ? Qt : Qnil);
2078 2078
2079 /* Lists may represent commands. */ 2079 /* Lists may represent commands. */
2080 if (!CONSP (fun)) 2080 else if (!CONSP (fun))
2081 return Qnil; 2081 return Qnil;
2082 funcar = XCAR (fun); 2082 else
2083 if (EQ (funcar, Qclosure)) 2083 {
2084 return (!NILP (Fassq (Qinteractive, Fcdr (Fcdr (XCDR (fun))))) 2084 Lisp_Object funcar = XCAR (fun);
2085 ? Qt : if_prop); 2085 if (EQ (funcar, Qautoload))
2086 else if (EQ (funcar, Qlambda)) 2086 {
2087 return !NILP (Fassq (Qinteractive, Fcdr (XCDR (fun)))) ? Qt : if_prop; 2087 if (!NILP (Fcar (Fcdr (Fcdr (XCDR (fun))))))
2088 else if (EQ (funcar, Qautoload)) 2088 return Qt;
2089 return !NILP (Fcar (Fcdr (Fcdr (XCDR (fun))))) ? Qt : if_prop; 2089 }
2090 else
2091 {
2092 Lisp_Object body = CDR_SAFE (XCDR (fun));
2093 if (EQ (funcar, Qclosure))
2094 body = CDR_SAFE (body);
2095 else if (!EQ (funcar, Qlambda))
2096 return Qnil;
2097 if (!NILP (Fassq (Qinteractive, body)))
2098 return Qt;
2099 else if (VALID_DOCSTRING_P (CAR_SAFE (body)))
2100 /* A "docstring" is a sign that we may have an OClosure. */
2101 genfun = true;
2102 }
2103 }
2104
2105 /* By now, if it's not a function we already returned nil. */
2106
2107 /* Check an `interactive-form' property if present, analogous to the
2108 function-documentation property. */
2109 fun = function;
2110 while (SYMBOLP (fun))
2111 {
2112 Lisp_Object tmp = Fget (fun, Qinteractive_form);
2113 if (!NILP (tmp))
2114 error ("Found an 'interactive-form' property!");
2115 fun = Fsymbol_function (fun);
2116 }
2117
2118 /* If there's no immediate interactive form but it's an OClosure,
2119 then delegate to the generic-function in case it has
2120 a type-specific interactive-form. */
2121 if (genfun)
2122 {
2123 Lisp_Object iform = call1 (Qinteractive_form, fun);
2124 return NILP (iform) ? Qnil : Qt;
2125 }
2090 else 2126 else
2091 return Qnil; 2127 return Qnil;
2092} 2128}