Discussion:
bug#17446: 24.4.50; What is the situation around `called-interactively-p'?
(too old to reply)
Thierry Volpiatto
2014-05-09 12:29:45 UTC
Permalink
Hi,

I recently had to use `called-interactively-p-functions' to fix a
command similar to `repeat-complex-command'.
I used similar hack than the one found in `repeat-complex-command',
but as mentionned in `called-interactively-p' this is not working with
code compiled (I use lexical-binding), thus `dont-compile' have been
made obsolete.

So what to do actually to fix such issues ?

Do you plan to make something better around the terrible
`called-interactively-p' ?

What about a special var to force `called-interactively-p' to return
true when it find this var (Actually this is crashing emacs) ?

It seems the only reason `dont-compile' have been made obsolete is
to force people fixing their code to make it working compiled;
That's ok, but what to do when nothing else is possible ?
IOW why is this obsolete ?


Ref: https://github.com/emacs-helm/helm/issues/489

Thanks.




In GNU Emacs 24.4.50.1 (x86_64-unknown-linux-gnu, GTK+ Version 3.10.8)
of 2014-05-04 on dell-14z
Windowing system distributor `The X.Org Foundation', version 11.0.11501000
System Description: Ubuntu 14.04 LTS

Configured features:
XPM JPEG TIFF GIF PNG RSVG IMAGEMAGICK SOUND GPM DBUS GCONF GSETTINGS
NOTIFY LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT LIBOTF XFT ZLIB

Important settings:
value of $LANG: fr_FR.UTF-8
locale-coding-system: utf-8-unix

Major mode: Emacs-Lisp

Minor modes in effect:
diff-auto-refine-mode: t
git-gutter-mode: t
psession-mode: t
golden-ratio-mode: t
global-semanticdb-minor-mode: t
global-semantic-idle-scheduler-mode: t
semantic-idle-scheduler-mode: t
semantic-mode: t
winner-mode: t
global-undo-tree-mode: t
undo-tree-mode: t
auto-image-file-mode: t
eldoc-in-minibuffer-mode: t
show-paren-mode: t
display-time-mode: t
recentf-mode: t
savehist-mode: t
eldoc-mode: t
minibuffer-depth-indicate-mode: t
helm-mode: t
helm-descbinds-mode: t
shell-dirtrack-mode: t
helm-adaptative-mode: t
helm-match-plugin-mode: t
helm-occur-match-plugin-mode: t
tooltip-mode: t
file-name-shadow-mode: t
global-font-lock-mode: t
font-lock-mode: t
auto-composition-mode: t
auto-encryption-mode: t
auto-compression-mode: t
column-number-mode: t
line-number-mode: t
transient-mark-mode: t

Recent input:
C-x C-b e l i s <down> <return> C-x C-d C-e b v <down>
<return> m m <down> <down> <down> <return> C-c C-c
q P P q <down> <down> <down> <down> <down> <down> <down>
<down> <down> <down> <down> <down> <down> <down> <down>
<down> <down> <down> <down> <down> <down> <down> <down>
<down> <up> <up> <up> <up> <up> <up> <up> <up> <up>
<up> <up> <up> <up> <up> <up> <up> <up> <right> <right>
<right> <right> <right> <right> <right> <right> <right>
<right> <right> <right> <right> <right> <right> <right>
<right> <right> <right> <right> <right> <right> C-M-SPC
M-w C-x C-f <left> <left> e m a <left> l s p C-u C-s
<return> M-n <down> <up> <return> C-x C-f C-g M-> C-c
SPC <return> M-x r e p o r t <return>

Recent messages:
Parsing helm-elisp.el (LL)...done
Parsing helm.el (LL)...done
Type a prefix key to toggle it. Run 'actions' with their prefixes. '?' for more help.
Type C-c C-c to commit (C-c C-k to cancel).
Parsing helm.el (LL)...done
git finished.
Type a prefix key to toggle it. Run 'actions' with their prefixes. '?' for more help.
Running git push -v origin complex-command-history:refs/heads/complex-command-history
git finished.
Mark set [2 times]

Load-path shadows:
~/elisp/auctex/lpath hides ~/elisp/emacs-wget/lpath
/usr/local/share/emacs/24.4.50/lisp/emacs-lisp/tq hides ~/elisp/emms/lisp/tq

Features:
(shadow epa-mail mule-util emacsbug helm-command helm-ring
semantic/tag-write magit-cherry magit-bisect magit-log-edit log-edit
add-log magit-key-mode magit magit-version view ediff-merg ediff-wind
ediff-diff ediff-mult ediff-help ediff-init ediff-util ediff diff-mode
magit-compat semantic/decorate/mode semantic/decorate pulse nxml-uchnm
rng-xsd xsd-regexp rng-cmpct rng-nxml rng-valid rng-loc rng-uri
rng-parse nxml-parse rng-match rng-dt rng-util rng-pttrn nxml-ns
nxml-mode nxml-outln nxml-rap nxml-util nxml-glyph nxml-enc xmltok
semantic/wisent/javascript-jv semantic/wisent/js-wy semantic/wisent
semantic/wisent/wisent semantic/java semantic/doc js json moz imenu
cc-mode cc-fonts cc-guess cc-menus cc-cmds cc-styles cc-align cc-engine
cc-vars cc-defs vc-rcs conf-mode sh-script smie executable vc-git
semantic/db-find naquadah-theme em-unix em-script em-prompt em-ls
em-hist em-pred em-glob em-dirs em-cmpl em-basic em-banner em-alias
semantic/db-ref semantic/db-file data-debug cedet-files align-let
git-gutter server psession golden-ratio semantic/bovine/el
semantic/db-el eieio-opt help-mode semantic/bovine semantic/db-mode
semantic/db eieio-base semantic/idle semantic/format semantic/tag-ls
semantic/find semantic/ctxt semantic/util-modes semantic/util semantic
semantic/tag semantic/lex semantic/fw mode-local cedet winner undo-tree
diff image-file newsticker newst-treeview newst-plainview newst-reader
newst-ticker newst-backend xdvi-search preview-latex tex-site auto-loads
pcomplete-extension em-term term disp-table ehelp helm-ipython
helm-elisp helm-eval python eldoc-eval warnings whitespace paren time
avoid recentf tree-widget savehist mu4e-config org-mu4e helm-mu
mu4e-contrib mu4e mu4e-speedbar speedbar sb-image ezimage dframe
mu4e-main mu4e-view mu4e-headers mu4e-compose mu4e-draft mu4e-actions
ido rfc2368 mu4e-mark mu4e-message html2text mu4e-proc mu4e-utils
mu4e-lists mu4e-about mu4e-vars mu4e-meta gnus-dired nnir gnus-sum
gnus-group gnus-undo gnus-start gnus-cloud nnimap nnmail mail-source tls
utf7 netrc parse-time gnus-spec gnus-int gnus-range gnus-win nnoo
config-w3m w3m-search w3m timezone w3m-hist w3m-fb bookmark-w3m w3m-ems
w3m-ccl ccl w3m-favicon w3m-image w3m-proc w3m-util w3m-load
smtpmail-async smtpmail sendmail dired-async iterator simple-call-tree
iedit-rect iedit iedit-lib smallurl mm-url gnus gnus-ems nnheader
wid-edit rectangle-utils rect ledger-config ledger esh-var esh-io
esh-cmd esh-opt esh-ext esh-proc eldoc esh-groups eshell esh-module
esh-mode esh-arg esh-util tv-utils async pcvs vc-cvs pcvs-parse
pcvs-info pcvs-defs pcvs-util ewoc mb-depth cl-info slime-autoloads
esh-toggle flymake no-word htmlize cl dired-extension emms-mpd-config
emms-playlist-limit emms-volume emms-volume-amixer emms-i18n
emms-history emms-score emms-stream-info emms-metaplaylist-mode
emms-bookmarks emms-cue emms-mode-line-icon emms-browser sort
emms-playlist-sort emms-last-played emms-player-xine emms-player-mpd tq
emms-playing-time emms-lyrics emms-url hl-line emms-tag-editor emms-mark
emms-mode-line emms-cache emms-info-ogginfo emms-info-mp3info
emms-playlist-mode emms-player-vlc emms-player-mplayer emms-info
emms-streams later-do emms-source-playlist emms-source-file
emms-player-simple emms-setup emms emms-compat org-config-thierry ob-sh
org-crypt cal-china lunar solar cal-dst cal-bahai cal-islam cal-hebrew
holidays hol-loaddefs appt diary-lib diary-loaddefs org-element
org-rmail org-mhe org-irc org-info org-gnus org-docview doc-view
jka-compr image-mode org-bibtex bibtex org-bbdb org-w3m org-agenda
org-annotation-helper addressbook-bookmark message rfc822 mml mml-sec
mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047 rfc2045
ietf-drums mailabbrev mail-utils gmm-utils mailheader firefox-protocol
bookmark-firefox-handler bookmark-extensions org org-macro org-footnote
org-pcomplete org-list org-faces org-entities noutline outline
easy-mmode org-version ob-emacs-lisp ob ob-tangle org-src ob-ref ob-lob
ob-table ob-keys ob-exp ob-comint ob-core ob-eval org-compat org-macs
org-loaddefs find-func cal-menu calendar cal-loaddefs init-helm-thierry
helm-mode helm-dictionary helm-ls-git helm-descbinds helm-ls-hg
helm-files image-dired tramp tramp-compat tramp-loaddefs trampver shell
pcomplete format-spec dired-x dired-aux ffap thingatpt helm-buffers
helm-elscreen helm-tags helm-bookmark helm-adaptative helm-info helm-net
browse-url xml url url-proxy url-privacy url-expand url-methods
url-history url-cookie url-domsuf url-util url-parse url-vars mailcap
helm-plugin bookmark pp helm-help helm-match-plugin helm-grep wgrep-helm
wgrep helm-regexp grep helm-external helm-utils dired compile comint
ansi-color ring helm-locate helm vc vc-dispatcher helm-config
helm-aliases epa-file epa derived epg epg-config auth-source eieio
byte-opt bytecomp byte-compile cconv eieio-core gnus-util time-date
mm-util mail-prsvr password-cache package info easymenu cl-macs gv
edmacro kmacro advice help-fns net-utils cl-loaddefs cl-lib tooltip
electric uniquify ediff-hook vc-hooks lisp-float-type mwheel x-win x-dnd
tool-bar dnd fontset image regexp-opt fringe tabulated-list newcomment
lisp-mode prog-mode register page menu-bar rfn-eshadow timer select
scroll-bar mouse jit-lock font-lock syntax facemenu font-core frame cham
georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
korean japanese hebrew greek romanian slovak czech european ethiopic
indian cyrillic chinese case-table epa-hook jka-cmpr-hook help simple
abbrev minibuffer nadvice loaddefs button faces cus-face macroexp files
text-properties overlay sha1 md5 base64 format env code-pages mule
custom widget hashtable-print-readable backquote make-network-process
dbusbind gfilenotify dynamic-setting system-font-setting
font-render-setting move-toolbar gtk x-toolkit x multi-tty emacs)

Memory information:
((conses 16 638475 69033)
(symbols 48 61289 0)
(miscs 40 18406 905)
(strings 32 169566 15566)
(string-bytes 1 5184981)
(vectors 16 59750)
(vector-slots 8 972179 36494)
(floats 8 2237 544)
(intervals 56 3036 23)
(buffers 960 108)
(heap 1024 62643 2998))
--
Thierry
Get my Gnupg key:
gpg --keyserver pgp.mit.edu --recv-keys 59F29997
Drew Adams
2014-05-09 13:39:06 UTC
Permalink
Post by Thierry Volpiatto
I recently had to use `called-interactively-p-functions' to fix a
command similar to `repeat-complex-command'.
I used similar hack than the one found in `repeat-complex-command',
but as mentionned in `called-interactively-p' this is not working with
code compiled (I use lexical-binding), thus `dont-compile' have been
made obsolete.
So what to do actually to fix such issues ?
Do you plan to make something better around the terrible
`called-interactively-p' ?
What about a special var to force `called-interactively-p' to return
true when it find this var (Actually this is crashing emacs) ?
It seems the only reason `dont-compile' have been made obsolete is
to force people fixing their code to make it working compiled;
That's ok, but what to do when nothing else is possible ?
IOW why is this obsolete ?
Ref: https://github.com/emacs-helm/helm/issues/489
FWIW (I think this is related; apologies if not), this is what
I did:

;; Same as `repeat-complex-command--called-interactively-skip'
;; in `simple.el', but tests for `icicle-repeat-complex-command',
;; not `repeat-complex-command'.
(when (> emacs-major-version 23)

(defun icicle-repeat-complex-command--called-interactively-skip
(i _frame1 frame2)
"If currently `icicle-repeat-complex-command', return 1 to skip over it."
(and (eq 'eval (cadr frame2))
(eq 'icicle-repeat-complex-command
(cadr (backtrace-frame i #'called-interactively-p)))
1))

(byte-compile 'icicle-repeat-complex-command))

The reason for the `byte-compile' is that I found that it does
not work when interpreted. (That seems opposite to what you are
saying (?). I do not have non-nil `lexical-binding', however.)

I agree that this all seems complicated & fragile. Dunno what
the solution is.
Michael Heerdegen
2014-05-09 14:11:25 UTC
Permalink
Post by Drew Adams
I agree that this all seems complicated & fragile. Dunno what
the solution is.
Useful for packages like Icicles and Helm would be a build in

(defun fake-interactive-call (command &rest args) ...)

factored out of what is now hidden inside `repeat-complex-command'.

Michael.
Drew Adams
2014-05-09 14:47:23 UTC
Permalink
Post by Michael Heerdegen
Post by Drew Adams
I agree that this all seems complicated & fragile. Dunno what
the solution is.
Useful for packages like Icicles and Helm would be a build in
(defun fake-interactive-call (command &rest args) ...)
factored out of what is now hidden inside `repeat-complex-command'.
Yes. Or even a standard helper command, a la
`repeat-complex-command--called-interactively-skip', which
provides a way (e.g. a variable) to specify the replacement for `repeat-complex-command'.

IOW, it's a bit silly for libraries to essentially duplicate the
ugly hack used in `repeat-complex-command', specifying their own
command in place of it.

If this hack is the best Emacs can do then we should do it just
once and let other commands that are similar to
`repeat-complex-command' make use of it without just duplicating it.
Drew Adams
2014-05-09 14:17:03 UTC
Permalink
Post by Drew Adams
(defun icicle-repeat-complex-command--called-interactively-skip
...

Plus this code in `icicle-repeat-complex-command':
(if (> emacs-major-version 23)
(unwind-protect
(progn
(add-hook
'called-interactively-p-functions
#'icicle-repeat-complex-command--called-interactively-skip)
(eval newcmd))
(remove-hook
'called-interactively-p-functions
#'icicle-repeat-complex-command--called-interactively-skip))
(eval newcmd))
Stefan Monnier
2014-05-09 14:15:01 UTC
Permalink
Post by Thierry Volpiatto
but as mentionned in `called-interactively-p' this is not working with
code compiled (I use lexical-binding),
I don't know which "mention" you're thinking of here.
`called-interactively-p' is supposed to work (more or less as
well/poorly) in compiled code.
Post by Thierry Volpiatto
thus `dont-compile' have been made obsolete.
It's not related.
Post by Thierry Volpiatto
So what to do actually to fix such issues ?
Use an additional argument (you can call it `interactive'), provided by
the `interactive' spec?
Post by Thierry Volpiatto
Do you plan to make something better around the terrible
`called-interactively-p' ?
We have that already: the extra arg, as suggested in C-h
f called-interactively-p.
Post by Thierry Volpiatto
It seems the only reason `dont-compile' have been made obsolete is
to force people fixing their code to make it working compiled;
It's obsolete for the following reasons:
- I don't know of any use for it.
- I haven't seen a use of it yet.
- It seems to only make sense for ugly hacks.
Post by Thierry Volpiatto
That's ok, but what to do when nothing else is possible ?
AFAIK something else is always possible and preferable. But I don't
know enough about your problem to know that it's indeed also the case in
your situation.


Stefan
Drew Adams
2014-05-09 14:28:13 UTC
Permalink
Post by Stefan Monnier
Post by Thierry Volpiatto
So what to do actually to fix such issues ?
Use an additional argument (you can call it `interactive'),
provided by the `interactive' spec?
Post by Thierry Volpiatto
Do you plan to make something better around the terrible
`called-interactively-p' ?
We have that already: the extra arg, as suggested in C-h
f called-interactively-p.
Sure, we already do that. But that doesn't help when you define
a "command similar to `repeat-complex-command'", as Thierry says,
and as I have done too. Such a command has little control over
the definition of the command that it invokes.
Post by Stefan Monnier
Post by Thierry Volpiatto
That's ok, but what to do when nothing else is possible ?
AFAIK something else is always possible and preferable. But I don't
know enough about your problem to know that it's indeed also the case in
your situation.
I thought he described it pretty well. Write a command that is
similar to `repeat-complex-command'. Now make it work-around Emacs
bug #14136.

You end up doing for your new command something like what Emacs
does for `repeat-complex-command'. And AFAICT, that works only
when the helper function (similar to vanilla Emacs function
`repeat-complex-command--called-interactively-skip') is
byte-compiled.
Stefan Monnier
2014-05-09 14:50:49 UTC
Permalink
Post by Drew Adams
You end up doing for your new command something like what Emacs
does for `repeat-complex-command'.
Yes.
Post by Drew Adams
And AFAICT, that works only
when the helper function (similar to vanilla Emacs function
`repeat-complex-command--called-interactively-skip') is
byte-compiled.
Ah, now I understand the "byte-compiled" part (I kept thinking it was
about whether the command (i.e. callee) is byte-compiled).
Post by Drew Adams
Useful for packages like Icicles and Helm would be a build in
(defun fake-interactive-call (command &rest args) ...)
factored out of what is now hidden inside `repeat-complex-command'.
Yes, that makes a lot of sense now.

Before we go about doing that, I'd want to know one more thing: how did
icicles and helm does with it, in previous versions of Emacs?


Stefan
Drew Adams
2014-05-09 14:55:03 UTC
Permalink
Post by Stefan Monnier
Before we go about doing that, I'd want to know one more thing: how did
icicles and helm does with it, in previous versions of Emacs?
Icicles did nothing - the bug existed, just as in vanilla Emacs.
Michael Heerdegen
2014-05-09 15:15:02 UTC
Permalink
Post by Drew Adams
Post by Stefan Monnier
Before we go about doing that, I'd want to know one more thing: how did
icicles and helm does with it, in previous versions of Emacs?
Icicles did nothing - the bug existed, just as in vanilla Emacs.
It was the same with helm.

Michael.
Stefan Monnier
2014-05-09 17:53:27 UTC
Permalink
Post by Michael Heerdegen
Post by Drew Adams
Post by Stefan Monnier
Before we go about doing that, I'd want to know one more thing: how did
icicles and helm does with it, in previous versions of Emacs?
Icicles did nothing - the bug existed, just as in vanilla Emacs.
In which sense did it exist in vanilla Emacs?
Post by Michael Heerdegen
It was the same with helm.
IOW, this is a long standing problem, for which
called-interactively-p-functions provides a limited workaround?


Stefan
Thierry Volpiatto
2014-05-09 18:47:04 UTC
Permalink
Post by Stefan Monnier
Post by Michael Heerdegen
Post by Drew Adams
Post by Stefan Monnier
Before we go about doing that, I'd want to know one more thing: how did
icicles and helm does with it, in previous versions of Emacs?
Icicles did nothing - the bug existed, just as in vanilla Emacs.
In which sense did it exist in vanilla Emacs?
(eval (count-words nil nil))
=> eval: Wrong type argument: integer-or-marker-p, nil

We were using a condition-case returning an error message in such cases.

See

https://lists.gnu.org/archive/html/emacs-bug-tracker/2013-08/msg00161.html
Post by Stefan Monnier
Post by Michael Heerdegen
It was the same with helm.
IOW, this is a long standing problem, for which
called-interactively-p-functions provides a limited workaround?
Yes, seems fragile too.

Another approch would be to allow more args to `call-interactively',
this would allow one to use:

(apply 'call-interactively '(sexp arg1 arg2 arg...))

But not sure this would cover all use cases.
--
Thierry
Get my Gnupg key:
gpg --keyserver pgp.mit.edu --recv-keys 59F29997
Stefan Monnier
2014-05-09 19:50:03 UTC
Permalink
Post by Thierry Volpiatto
Another approch would be to allow more args to `call-interactively',
(apply 'call-interactively '(sexp arg1 arg2 arg...))
But not sure this would cover all use cases.
Right, I'm thinking of introducing a new `funcall-interactively' which
is just like `funcall' except that the called function will see its
`called-interactively-p' returning non-nil.

But I think this will have to wait for 24.5.


Stefan
Stefan Monnier
2014-05-09 21:02:20 UTC
Permalink
Post by Stefan Monnier
Right, I'm thinking of introducing a new `funcall-interactively' which
is just like `funcall' except that the called function will see its
`called-interactively-p' returning non-nil.
How 'bout the patch below,


Stefan


=== modified file 'lisp/simple.el'
--- lisp/simple.el 2014-05-01 23:25:28 +0000
+++ lisp/simple.el 2014-05-09 20:42:04 +0000
@@ -1503,24 +1503,13 @@
;; add it to the history.
(or (equal newcmd (car command-history))
(setq command-history (cons newcmd command-history)))
- (unwind-protect
- (progn
- ;; Trick called-interactively-p into thinking that `newcmd' is
- ;; an interactive call (bug#14136).
- (add-hook 'called-interactively-p-functions
- #'repeat-complex-command--called-interactively-skip)
- (eval newcmd))
- (remove-hook 'called-interactively-p-functions
- #'repeat-complex-command--called-interactively-skip)))
+ (apply #'funcall-interactively
+ (car newcmd)
+ (mapcar (lambda (e) (eval e t)) (cdr newcmd))))
(if command-history
(error "Argument %d is beyond length of command history" arg)
(error "There are no previous complex commands to repeat")))))

-(defun repeat-complex-command--called-interactively-skip (i _frame1 frame2)
- (and (eq 'eval (cadr frame2))
- (eq 'repeat-complex-command
- (cadr (backtrace-frame i #'called-interactively-p)))
- 1))

(defvar extended-command-history nil)


=== modified file 'lisp/subr.el'
--- lisp/subr.el 2014-04-09 01:48:07 +0000
+++ lisp/subr.el 2014-05-09 20:24:34 +0000
@@ -3832,7 +3832,8 @@
(byte-compile-log-warning msg))
(run-with-timer 0 nil
(lambda (msg)
- (message "%s" msg)) msg))))
+ (message "%s" msg))
+ msg))))

;; Finally, run any other hook.
(run-hook-with-args 'after-load-functions abs-file))
@@ -4149,7 +4150,8 @@
if those frames don't seem special and otherwise, it should return
the number of frames to skip (minus 1).")

-(defconst internal--call-interactively (symbol-function 'call-interactively))
+(defconst internal--funcall-interactively
+ (symbol-function 'funcall-interactively))

(defun called-interactively-p (&optional kind)
"Return t if the containing function was called by `call-interactively'.
@@ -4225,8 +4227,8 @@
(`((,_ ,(pred (lambda (f) (subrp (indirect-function f)))) . ,_) . ,_) nil)
;; In case #<subr call-interactively> without going through the
;; `call-interactively' symbol (bug#3984).
- (`(,_ . (t ,(pred (eq internal--call-interactively)) . ,_)) t)
- (`(,_ . (t call-interactively . ,_)) t)))))
+ (`(,_ . (t ,(pred (eq internal--funcall-interactively)) . ,_)) t)
+ (`(,_ . (t funcall-interactively . ,_)) t)))))

(defun interactive-p ()
"Return t if the containing function was run directly by user input.

=== modified file 'src/callint.c'
--- src/callint.c 2014-04-22 07:04:34 +0000
+++ src/callint.c 2014-05-09 20:47:17 +0000
@@ -29,7 +29,7 @@
#include "keymap.h"

Lisp_Object Qminus, Qplus;
-static Lisp_Object Qcall_interactively;
+static Lisp_Object Qfuncall_interactively;
static Lisp_Object Qcommand_debug_status;
static Lisp_Object Qenable_recursive_minibuffers;

@@ -233,6 +233,22 @@
}
}

+/* BEWARE: Calling this directly from C would defeat the purpose! */
+DEFUN ("funcall-interactively", Ffuncall_interactively, Sfuncall_interactively,
+ 1, MANY, 0, doc: /* Like `funcall' but marks the call as interactive.
+I.e. arrange that within the called function `called-interactively-p' will
+return non-nil. */)
+ (ptrdiff_t nargs, Lisp_Object *args)
+{
+ ptrdiff_t speccount = SPECPDL_INDEX ();
+ temporarily_switch_to_single_kboard (NULL);
+
+ /* Nothing special to do here, all the work is inside
+ `called-interactively-p'. Which will look for us as a marker in the
+ backtrace. */
+ return unbind_to (speccount, Ffuncall (nargs, args));
+}
+
DEFUN ("call-interactively", Fcall_interactively, Scall_interactively, 1, 3, 0,
doc: /* Call FUNCTION, providing args according to its interactive calling specs.
Return the value FUNCTION returns.
@@ -374,8 +390,13 @@
Vreal_this_command = save_real_this_command;
kset_last_command (current_kboard, save_last_command);

- temporarily_switch_to_single_kboard (NULL);
- return unbind_to (speccount, apply1 (function, specs));
+ {
+ Lisp_Object args[3];
+ args[0] = Qfuncall_interactively;
+ args[1] = function;
+ args[2] = specs;
+ return unbind_to (speccount, Fapply (3, args));
+ }
}

/* Here if function specifies a string to control parsing the defaults. */
@@ -446,10 +467,11 @@
else break;
}

- /* Count the number of arguments, which is one plus the number of arguments
- the interactive spec would have us give to the function. */
+ /* Count the number of arguments, which is two (the function itself and
+ `funcall-interactively') plus the number of arguments the interactive spec
+ would have us give to the function. */
tem = string;
- for (nargs = 1; *tem; )
+ for (nargs = 2; *tem; )
{
/* 'r' specifications ("point and mark as 2 numeric args")
produce *two* arguments. */
@@ -488,13 +510,13 @@
specbind (Qenable_recursive_minibuffers, Qt);

tem = string;
- for (i = 1; *tem; i++)
+ for (i = 2; *tem; i++)
{
- visargs[0] = make_string (tem + 1, strcspn (tem + 1, "\n"));
- if (strchr (SSDATA (visargs[0]), '%'))
+ visargs[1] = make_string (tem + 1, strcspn (tem + 1, "\n"));
+ if (strchr (SSDATA (visargs[1]), '%'))
callint_message = Fformat (i, visargs);
else
- callint_message = visargs[0];
+ callint_message = visargs[1];

switch (*tem)
{
@@ -789,21 +811,22 @@

QUIT;

- args[0] = function;
+ args[0] = Qfuncall_interactively;
+ args[1] = function;

if (arg_from_tty || !NILP (record_flag))
{
/* We don't need `visargs' any more, so let's recycle it since we need
an array of just the same size. */
- visargs[0] = function;
- for (i = 1; i < nargs; i++)
+ visargs[1] = function;
+ for (i = 2; i < nargs; i++)
{
if (varies[i] > 0)
visargs[i] = list1 (intern (callint_argfuns[varies[i]]));
else
visargs[i] = quotify_arg (args[i]);
}
- Vcommand_history = Fcons (Flist (nargs, visargs),
+ Vcommand_history = Fcons (Flist (nargs - 1, visargs + 1),
Vcommand_history);
/* Don't keep command history around forever. */
if (INTEGERP (Vhistory_length) && XINT (Vhistory_length) > 0)
@@ -816,7 +839,7 @@

/* If we used a marker to hold point, mark, or an end of the region,
temporarily, convert it to an integer now. */
- for (i = 1; i < nargs; i++)
+ for (i = 2; i < nargs; i++)
if (varies[i] >= 1 && varies[i] <= 4)
XSETINT (args[i], marker_position (args[i]));

@@ -829,11 +852,7 @@
kset_last_command (current_kboard, save_last_command);

{
- Lisp_Object val;
- specbind (Qcommand_debug_status, Qnil);
-
- temporarily_switch_to_single_kboard (NULL);
- val = Ffuncall (nargs, args);
+ Lisp_Object val = Ffuncall (nargs, args);
UNGCPRO;
return unbind_to (speccount, val);
}
@@ -888,7 +907,7 @@
DEFSYM (Qplus, "+");
DEFSYM (Qhandle_shift_selection, "handle-shift-selection");
DEFSYM (Qread_number, "read-number");
- DEFSYM (Qcall_interactively, "call-interactively");
+ DEFSYM (Qfuncall_interactively, "funcall-interactively");
DEFSYM (Qcommand_debug_status, "command-debug-status");
DEFSYM (Qenable_recursive_minibuffers, "enable-recursive-minibuffers");
DEFSYM (Qmouse_leave_buffer_hook, "mouse-leave-buffer-hook");
@@ -946,5 +965,6 @@

defsubr (&Sinteractive);
defsubr (&Scall_interactively);
+ defsubr (&Sfuncall_interactively);
defsubr (&Sprefix_numeric_value);
}
Stefan Monnier
2014-05-09 22:39:05 UTC
Permalink
Post by Stefan Monnier
How 'bout the patch below,
BTW, for older Emacsen, you can probably use a hack along the lines of
the guaranteed 100% untested code below:

(defun funcall-interactively (fun &rest args)
(call-interactively
(cond
((consp fun)
(mapcar (lambda (x)
(if (eq (car-safe x) 'interactive))
`(interactive ',args) x)
fun))
((byte-code-function-p)
(apply #'make-byte-code
(aref 0 fun)
(aref 1 fun)
(aref 2 fun)
(aref 3 fun)
(aref 4 fun)
`',args)))))

-- Stefan
Drew Adams
2014-05-09 23:34:31 UTC
Permalink
Post by Stefan Monnier
Post by Stefan Monnier
How 'bout the patch below,
BTW, for older Emacsen, you can probably use a hack along the lines of
Not sure I understand how any of this will help the use cases we
mentioned. Is the idea that `repeat-complex-command' will, instead
of doing (eval newcmd), do something like this?

(eval `(funcall-interactively ,(car newcmd) ,@(cdr newcmd)))

For the case in bug #14136, where NEWCMD is (count-words nil nil),
this would mean (funcall-interactively 'count-words nil nil).

(Maybe an `apply-interactively' would be handier here?)

In any case, I will wait to see how this changes the
`repeat-complex-command' code and then do likewise for my code,
which is similar.
Stefan Monnier
2014-05-10 02:13:09 UTC
Permalink
Post by Drew Adams
In any case, I will wait to see how this changes the
`repeat-complex-command' code and then do likewise for my code,
which is similar.
Go back 2 steps.


Stefan
Thierry Volpiatto
2014-05-10 09:10:28 UTC
Permalink
Post by Drew Adams
In any case, I will wait to see how this changes the
`repeat-complex-command' code and then do likewise for my code,
which is similar.
Probably I will inline the funcall-interactively version Stefan and
Michael sent and use something like this in helm:

(defun helm-sexp-eval (cand)
(let ((sexp (read cand)))
(condition-case err
(apply #'funcall-interactively (car sexp)
(mapcar (lambda (e) (eval e t)) (cdr sexp)))
(error (message "Evaluating gave an error: %S" err)
nil))))

Probably you can do something similar in icicles.
--
Thierry
Get my Gnupg key:
gpg --keyserver pgp.mit.edu --recv-keys 59F29997
Thierry Volpiatto
2014-05-10 06:12:28 UTC
Permalink
Post by Stefan Monnier
Post by Stefan Monnier
How 'bout the patch below,
BTW, for older Emacsen, you can probably use a hack along the lines of
(defun funcall-interactively (fun &rest args)
(call-interactively
(cond
((consp fun)
(mapcar (lambda (x)
(if (eq (car-safe x) 'interactive))
^
Post by Stefan Monnier
`(interactive ',args) x)
fun))
((byte-code-function-p)
^ missing arg ?
Post by Stefan Monnier
(apply #'make-byte-code
(aref 0 fun)
(aref 1 fun)
(aref 2 fun)
(aref 3 fun)
(aref 4 fun)
`',args)))))
This won't work IMO, why fun would be a cons or a byte-code-function ?
--
Thierry
Get my Gnupg key:
gpg --keyserver pgp.mit.edu --recv-keys 59F29997
Michael Heerdegen
2014-05-10 07:40:18 UTC
Permalink
Post by Stefan Monnier
BTW, for older Emacsen, you can probably use a hack along the lines of
I tried to make it work:

(defun funcall-interactively (fun &rest args)
(setq fun (indirect-function fun))
(call-interactively
(cond
((consp fun)
(mapcar (lambda (x)
(if (eq (car-safe x) 'interactive)
`(interactive ',args) x))
fun))
((byte-code-function-p fun)
(apply #'make-byte-code
(aref fun 0)
(aref fun 1)
(aref fun 2)
(aref fun 3)
(aref fun 4)
(aref fun 5)
args)))))

Works at least with the count-words case:

(funcall-interactively 'count-words nil nil) ==> something useful

Michael.
Thierry Volpiatto
2014-05-10 08:41:53 UTC
Permalink
Post by Stefan Monnier
Post by Stefan Monnier
BTW, for older Emacsen, you can probably use a hack along the lines of
(defun funcall-interactively (fun &rest args)
(setq fun (indirect-function fun))
(call-interactively
(cond
((consp fun)
(mapcar (lambda (x)
(if (eq (car-safe x) 'interactive)
`(interactive ',args) x))
fun))
((byte-code-function-p fun)
(apply #'make-byte-code
(aref fun 0)
(aref fun 1)
(aref fun 2)
(aref fun 3)
(aref fun 4)
(aref fun 5)
args)))))
(funcall-interactively 'count-words nil nil) ==> something useful
Great, works also with `count-words-region'.
--
Thierry
Get my Gnupg key:
gpg --keyserver pgp.mit.edu --recv-keys 59F29997
Thierry Volpiatto
2014-05-10 05:51:30 UTC
Permalink
Post by Stefan Monnier
Post by Stefan Monnier
Right, I'm thinking of introducing a new `funcall-interactively' which
is just like `funcall' except that the called function will see its
`called-interactively-p' returning non-nil.
How 'bout the patch below,
Just applied and tried, it is working fine, thanks.
Post by Stefan Monnier
+ (apply #'funcall-interactively
+ (car newcmd)
+ (mapcar (lambda (e) (eval e t)) (cdr newcmd))))
Is this needed ?

Looks like

(apply #'funcall-interactively (car newcmd) (cdr newcmd))

is enough no ?
--
Thierry
Get my Gnupg key:
gpg --keyserver pgp.mit.edu --recv-keys 59F29997
Stefan Monnier
2014-05-10 06:45:42 UTC
Permalink
Post by Thierry Volpiatto
(apply #'funcall-interactively (car newcmd) (cdr newcmd))
No, `newcmd' is an expression, so (cdr newcommand) contains arguments
that need to be evaluated. In some/many cases this evaluation is
trivial (the args are self-quoting, like nil or integers), but sometimes
the args can be things like (region-beginning).
Post by Thierry Volpiatto
Post by Stefan Monnier
(defun funcall-interactively (fun &rest args)
[sample hack to define funcall-interactively in terms of call-interactively]
Post by Thierry Volpiatto
This won't work IMO, why fun would be a cons or a byte-code-function ?
These are the only interesting cases. The other cases (subrp and
symbolp, AFAICT) are trivial.


Stefan
Thierry Volpiatto
2014-05-10 08:06:36 UTC
Permalink
Post by Stefan Monnier
Post by Thierry Volpiatto
(apply #'funcall-interactively (car newcmd) (cdr newcmd))
No, `newcmd' is an expression, so (cdr newcommand) contains arguments
that need to be evaluated. In some/many cases this evaluation is
trivial (the args are self-quoting, like nil or integers), but sometimes
the args can be things like (region-beginning).
Hmm, not sure of this, at least for `repeat-complex-command' something
like (region-beginning) is already evaluated and recorded as an integer
no ?
Oh! ok I see, something like M-: (region-beginning)
will be recorded as something like

(pp-eval-expression (quote (region-beginning)))
Post by Stefan Monnier
Post by Thierry Volpiatto
Post by Stefan Monnier
(defun funcall-interactively (fun &rest args)
[sample hack to define funcall-interactively in terms of call-interactively]
Post by Thierry Volpiatto
This won't work IMO, why fun would be a cons or a byte-code-function ?
These are the only interesting cases. The other cases (subrp and
symbolp, AFAICT) are trivial.
I still don't understand how this would be able to call interactively
something like:

(count-words-region 234 567 nil)
--
Thierry
Get my Gnupg key:
gpg --keyserver pgp.mit.edu --recv-keys 59F29997
Stefan Monnier
2014-05-10 20:15:42 UTC
Permalink
Post by Thierry Volpiatto
I still don't understand how this would be able to call interactively
(count-words-region 234 567 nil)
The code I showed takes an interactive function with some args, rips the
function apart to rebuild a new one whose interactive spec just returns
those args.
If the function is a symbol, then recurse on (symbol-function fun).


Stefan
Michael Heerdegen
2014-05-11 04:24:19 UTC
Permalink
Post by Stefan Monnier
The code I showed takes an interactive function with some args, rips
the function apart to rebuild a new one whose interactive spec just
returns those args. If the function is a symbol, then recurse on
(symbol-function fun).
Yes, it's a funny idea.

Stefan, what's the right approach to make commands that refer to
this-command or last-command work correctly when called with your code?
Should we add something like

(when (symbolp fun) (setq this-command fun)) ?

Does your patch planned for later inclusion care about updating
this-command and last-command appropriately?


Thanks,

Michael.
Michael Heerdegen
2014-05-11 05:58:08 UTC
Permalink
Post by Michael Heerdegen
(when (symbolp fun) (setq this-command fun)) ?
call-interactively doesn't set `this-command'. Nor does
`repeat-complex-command'. Should one of them set it?

Example:

--8<---------------cut here---------------start------------->8---
(defvar the-string nil)

(defun test (string)
(interactive (list (if (eq this-command last-command)
the-string
(setq the-string (read-string "Enter string: ")))))
(message (concat "You "
(if (eq this-command last-command) "had" "have")
" entered "
the-string)))

(global-set-key [f12] #'test)
--8<---------------cut here---------------end--------------->8---

If you repeat `test' via repeat-complex-command and hit f12 after that,
it doesn't behave as expected (i.e., message "You had entered ...").
Should it?

Michael.
Michael Heerdegen
2014-05-17 18:01:20 UTC
Permalink
Hi,

my last question was: should `repeat-complex-command' set
`this-command'? See my example. If the answer is "yes" - shall I
create a separate bug report?


Thanks,

Michael.
Post by Michael Heerdegen
(defvar the-string nil)
(defun test (string)
(interactive (list (if (eq this-command last-command)
the-string
(setq the-string (read-string "Enter string: ")))))
(message (concat "You "
(if (eq this-command last-command) "had" "have")
" entered "
the-string)))
(global-set-key [f12] #'test)
If you repeat `test' via repeat-complex-command and hit f12 after that,
it doesn't behave as expected (i.e., message "You had entered ...").
Should it?
Stefan Monnier
2014-05-18 01:56:43 UTC
Permalink
Post by Michael Heerdegen
my last question was: should `repeat-complex-command' set
`this-command'? See my example. If the answer is "yes" - shall I
create a separate bug report?
It probably should, yes. Just like execute-extended-command does.


Stefan
Stefan Monnier
2014-05-11 06:02:36 UTC
Permalink
Post by Michael Heerdegen
Stefan, what's the right approach to make commands that refer to
this-command or last-command work correctly when called with your code?
`this/last-command' are not directly related to call-interactively.
Instead they're handled by the top-level command loop.
Post by Michael Heerdegen
Does your patch planned for later inclusion care about updating
this-command and last-command appropriately?
No.


Stefan
Thierry Volpiatto
2014-05-11 04:31:44 UTC
Permalink
Post by Stefan Monnier
Post by Thierry Volpiatto
I still don't understand how this would be able to call interactively
(count-words-region 234 567 nil)
The code I showed takes an interactive function with some args, rips the
function apart to rebuild a new one whose interactive spec just returns
those args.
If the function is a symbol, then recurse on (symbol-function fun).
I got it now, thanks for explanations and your work on this.
--
Thierry
Get my Gnupg key:
gpg --keyserver pgp.mit.edu --recv-keys 59F29997
Andreas Röhler
2014-05-10 10:22:17 UTC
Permalink
Post by Stefan Monnier
Post by Thierry Volpiatto
(apply #'funcall-interactively (car newcmd) (cdr newcmd))
No, `newcmd' is an expression, so (cdr newcommand) contains arguments
that need to be evaluated. In some/many cases this evaluation is
trivial (the args are self-quoting, like nil or integers), but sometimes
the args can be things like (region-beginning).
Post by Thierry Volpiatto
Post by Stefan Monnier
(defun funcall-interactively (fun &rest args)
[sample hack to define funcall-interactively in terms of call-interactively]
Post by Thierry Volpiatto
This won't work IMO, why fun would be a cons or a byte-code-function ?
These are the only interesting cases. The other cases (subrp and
symbolp, AFAICT) are trivial.
Stefan
So maybe the good old and simple (interactive-p) needs no longer being obsolete?

Andreas
Stefan Monnier
2014-05-10 20:19:15 UTC
Permalink
Post by Andreas Röhler
So maybe the good old and simple (interactive-p) needs no longer being obsolete?
Unrelated. It's obsolete because it's replaced by called-interactively-p.
The discussion here applies just as much about interactive-p as about
called-interactively-p.

And using/introducing funcall-interactively doesn't solve all the other
problems with interactive-p/called-interactively-p, such as the fact
that they may (depending on the position of the sun) return nil rather
than t if called within an `unwind-protect'.


Stefan
Andreas Röhler
2014-05-11 07:47:29 UTC
Permalink
Post by Stefan Monnier
Post by Andreas Röhler
So maybe the good old and simple (interactive-p) needs no longer being obsolete?
Unrelated. It's obsolete because it's replaced by called-interactively-p.
The discussion here applies just as much about interactive-p as about
called-interactively-p.
[ ... ]

Okay, thanks.

Andredas
Thierry Volpiatto
2014-05-10 03:43:58 UTC
Permalink
Post by Stefan Monnier
Right, I'm thinking of introducing a new `funcall-interactively' which
is just like `funcall' except that the called function will see its
`called-interactively-p' returning non-nil.
That's good news, great, thanks.
--
Thierry
Get my Gnupg key:
gpg --keyserver pgp.mit.edu --recv-keys 59F29997
n***@users.sourceforge.net
2017-03-25 06:23:32 UTC
Permalink
close 17446 25.1
quit
Post by Stefan Monnier
Post by Thierry Volpiatto
Another approch would be to allow more args to `call-interactively',
(apply 'call-interactively '(sexp arg1 arg2 arg...))
But not sure this would cover all use cases.
Right, I'm thinking of introducing a new `funcall-interactively' which
is just like `funcall' except that the called function will see its
`called-interactively-p' returning non-nil.
But I think this will have to wait for 24.5.
Seems to have been done in 25.1

Drew Adams
2014-05-09 19:16:16 UTC
Permalink
Post by Stefan Monnier
Post by Drew Adams
the bug existed, just as in vanilla Emacs.
In which sense did it exist in vanilla Emacs?
I assume Michael was referring to Emacs bug #14136.
Loading...