为什么申请建议的顺序很重要?

时间:2014-04-12 18:03:22

标签: emacs elisp

org-icomplete是一个调用ido-completing-read(icr)的函数。相反,我希望它调用我的函数:ido-completing-path-like-read(icplr)。除了icplr调用icr之外,这很容易实现为建议,因此需要在icplr上调用另一个建议来重新调用icr的原始定义,以防止无限递归。

我以两种方式实现了这一点,其中一种方法有效,其中一种方式没有 - icplr进入无限递归,调用自身而不是icr。为什么一个不工作,不工作?

使用:

(defadvice org-icompleting-read (around ido-path-like-completion activate)
  (let ((sh/orig-ido-completing-read (symbol-function 'ido-completing-read)))
    (unwind-protect
        (progn
          (defadvice ido-completing-path-like-read
            (around save-ido-completing-read activate)
            (setf (symbol-function 'ido-completing-read)
                  sh/orig-ido-completing-read)
            ad-do-it
            )
          (setf (symbol-function 'ido-completing-read)
                (symbol-function 'ido-completing-path-like-read))
          ad-do-it
          )
      (setf (symbol-function 'ido-completing-read)
            sh/orig-ido-completing-read)
      (ad-remove-advice 'ido-completing-path-like-read 'around 'save-ido-completing-read)
      ))
  )

不起作用:

(defadvice org-icompleting-read (around ido-path-like-completion activate)
  (let ((sh/orig-ido-completing-read (symbol-function 'ido-completing-read)))
    (unwind-protect
        (progn
          (setf (symbol-function 'ido-completing-read)
                (symbol-function 'ido-completing-path-like-read))
          (defadvice ido-completing-path-like-read
            (around save-ido-completing-read activate)
            (setf (symbol-function 'ido-completing-read)
                  sh/orig-ido-completing-read)
            ad-do-it
            )
          ad-do-it
          )
      (setf (symbol-function 'ido-completing-read)
            sh/orig-ido-completing-read)
      (ad-remove-advice 'ido-completing-path-like-read 'around 'save-ido-completing-read)
      ))
  )

修改

  1. 我想说清楚所有提到的函数:ido-completed-path-like-read,ido-completed-read和org-icompleting-read将被处理(其中两个在事实是)库函数,我无法控制的定义。

  2. 虽然我在这里对替代模式的建议持开放态度并且会很感激,但我只会接受一个实际回答我的问题的答案:为什么第一个代码有效,第二个代码没有? ?谢谢你的理解。

2 个答案:

答案 0 :(得分:1)

不要添加/删除建议。只需提出有条件的建议:

(defvar my-inhibit-org-advice nil)

(defadvice org-icompleting-read (around ...)
  (if my-inhibit-org-advice ad-do-it
    ...my advice...))

(defun ido-completing-path-like-read (...)
  (let ((my-inhibit-org-advice t))
    ...(org-icompleting-read ...)...))

答案 1 :(得分:1)

任何可能来搜索的人:

第一个起作用而第二个起作用的原因不是应用建议的顺序 - 它是相对于:

应用内部建议的顺序
      (setf (symbol-function 'ido-completing-read)
            (symbol-function 'ido-completing-path-like-read))

重要的是,如果在建议之前执行此声明,则不会建议符号'ido-completing-read,而符号'ido-completing-path-like-read副本将是。但是,如果首先应用建议,则两个符号都将引用建议的版本。

我不确定这完全有道理。我想象(这就是为什么这个难题)函数对象附加了一些附加信息,以及我们通过操纵这些附加信息来应用的建议。

事实证明这是一个更基本的机制 - 函数实际上是ad-hoc ...