Frage

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

  • Search for matches in (with-output-to-string (backtrace)) in the advise definition
  • Add around advises to the other methods to set some variable which can be tested in the advise definition.

Is 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 '..'?

War es hilfreich?

Lösung

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 ...

Andere Tipps

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.

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

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)))

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top