Вызывать подсказку для функции только при вызове из определенной другой функции

Я пытаюсь обойти ограничение, которое dired-do-shell-command (связан с !) не может быть вызван на текущий и родительский каталог . а также .. ". Трассировка стека вставляется внизу.

Я могу определить совет, как показано ниже, чтобы обойти эту ошибку:

(defadvice dired-get-filename (before h-no-error-if-not-filep activate)
  (ad-set-arg 1 t))

Но это влияет на все звонки на dired-get-filename , Я хотел бы, чтобы он срабатывал только когда стек dired-do-shell-command -> dired-get-marked-files -> dired-get-filename,

Единственные подходы, о которых я могу думать, следующие

  • Поиск совпадений в (with-output-to-string (backtrace)) в определении совета
  • Добавьте вокруг рекомендации к другим методам, чтобы установить некоторую переменную, которая может быть проверена в определении рекомендации.

Есть ли лучший способ сделать это? Я думаю, что я ищу доступ к текущей трассировке стека в виде структуры данных вместо строки из (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)

Почему команда dired-do-shell-command не может работать с '.' или же '..'?

5 ответов

Решение

Вы можете получить доступ к трассировке стека, один слой за один раз, через backtrace-frame, Но это действительно толкает взломать. Я рекомендую вам также M-x report-emacs-bug запрашивая ! работать на . а также ..,

Я бы лучше скопировал dired-do-shell-command в my:dired-do-shell-command и оттуда позвоните my:dired-get-marked-files который бы назвал dired-get-filename с третьим аргументом т.

Таким образом я копирую / вставляю две функции, но я минимизирую побочные эффекты от советов часто используемых функций.

Использовать this-command переменная:

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

Обязательно подайте запрос функции.

Но в среднем вы можете сделать свой собственный my:dired-do-shell-command без "копирования любого кода" с помощью flet перепривязать dired-get-filename только в пределах вашей функции. Это близко к решению @oleg.

Также обсуждается в этом вопросе:

Этот код не проверен, но вы поняли идею.

(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 хакеры злоупотребляют defadvice слишком много. Это ужасно запутывает вещи и должно быть зарезервировано только как последнее средство.

Было бы здорово получить доступ к стеку в виде списка, но, к сожалению, похоже, что он недоступен из elisp. (Правка: Ах, я слепой; backtrace-frame обеспечивает это, и я даже не смотрел на это. Спасибо Стефан.)

Подобный подход к вашему второму варианту (использование дополнительного совета и переменной маркера) состоит в том, чтобы просто включить или отключить внутренний совет на основе внешнего совета. Вот пример:

Emacs Follow-Mode через кадры

Другие вопросы по тегам