Reputation: 28752
I am trying to work around the restriction that dired-do-shell-command
(bound to !
) cannot be called on current and parent directories .
and ..
'. The stack-trace is pasted at the bottom.
I can define an advice as below to bypass this error:
(defadvice dired-get-filename (before h-no-error-if-not-filep activate)
(ad-set-arg 1 t))
But this affects all calls to the dired-get-filename
. I would like it to trigger only when the stack is dired-do-shell-command -> dired-get-marked-files -> dired-get-filename
.
The only approaches I can think of are as follows
(with-output-to-string (backtrace))
in the advise definitionIs there better way to do it? I guess I am looking for access to the current stack-trace as a data structure instead of the string from (backtrace)
Debugger entered--Lisp error: (error "Cannot operate on `.' or `..'")
signal(error ("Cannot operate on `.' or `..'"))
error("Cannot operate on `.' or `..'")
dired-get-filename(t)
dired-get-marked-files(t nil)
(let ((files (dired-get-marked-files t current-prefix-arg))) (list (dired-read-shell-command (concat "! on " "%s: ") current-prefix-arg files) current-prefix-arg files))
call-interactively(dired-do-shell-command nil nil)
Why can dired-do-shell-command not operate on '.' or '..'?
Upvotes: 3
Views: 422
Reputation: 17707
Definitely file a feature request.
But in the mean you can make your own my:dired-do-shell-command
without
"copying any code" by using flet
to rebind dired-get-filename
only within
your function. This is close to @oleg's solution.
Also discussed in this question:
This code is untested, but you get the idea.
(eval-when-compile (require 'cl))
(defun my:dired-do-shell-command (&rest args)
(interactive)
(let ((old-func (symbol-function 'dired-get-filename)))
(flet ((dired-get-filename (&rest args)
(let ((file (funcall old-func 'verbatim)))
(if (memberq file '("." ".."))
(if (car args)
file
(expand-file-name file default-directory))
(apply old-func args)))))
(apply 'dired-do-shell-command args))))
Emacs hackers abuse defadvice
far too much. It obfuscates things horribly
and should only be reserved as a last resort solution.
Upvotes: 1
Reputation: 17327
Use the this-command
variable:
(defadvice dired-get-filename (before h-no-error-if-not-filep activate)
(when (equal this-command 'dired-do-shell-command)
(ad-set-arg 1 t)))
Upvotes: 1
Reputation: 73246
Accessing the stack as a list would be great, but unfortunately that looks like it's inaccessible from elisp. (Edit: Ah, I'm blind; backtrace-frame
provides this, and I didn't even look at it. Thanks Stefan.)
A similar approach to your second option (of using extra advice and a marker variable) is to just enable or disable the inner advice based on the outer advice. Here's an example:
emacs follow-mode across frames
Upvotes: 1
Reputation: 28531
You can access the stack trace, one layer at a time, via backtrace-frame
. But this is really pushing the hack. I recommend you also M-x report-emacs-bug
requesting for !
to work on .
and ..
.
Upvotes: 3
Reputation: 21162
I would rather copy dired-do-shell-command
to my:dired-do-shell-command
and from there call my:dired-get-marked-files
which would call dired-get-filename
with the third argument t.
This way I copy/paste two functions but I minimize side effects from advising often used functions.
Upvotes: 3