Вызывать подсказку для функции только при вызове из определенной другой функции
Я пытаюсь обойти ограничение, которое 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
обеспечивает это, и я даже не смотрел на это. Спасибо Стефан.)
Подобный подход к вашему второму варианту (использование дополнительного совета и переменной маркера) состоит в том, чтобы просто включить или отключить внутренний совет на основе внешнего совета. Вот пример: