elisp中的缓冲区本地函数

时间:2011-11-04 10:58:01

标签: function emacs elisp buffer local

我想重新定义现有函数foo,但仅限于特定缓冲区。

(defun foo ()
  (message "Not done:("))

我正在跳这样做:

(make-local-variable 'foo)
(fset 'foo #'(lambda () (message "Done!")))

但事实并非如此。 有什么想法吗?

[编辑: 或者,因为函数被绑定到一个键,所以只修改当前缓冲区的绑定就足够了。但我不明白该怎么做。本地键映射由主模式中的所有缓冲区共享。修改它会修改所有缓冲区中使用此主要模式的绑定。

我能想到的唯一丑陋的解决方案是为整个缓冲区设置keymap text-property。这是继续进行的唯一途径吗?]

4 个答案:

答案 0 :(得分:5)

你可以创建一个能够覆盖你的功能,其中包括:

(defun override-the-keymap ()
  (let ((my-overriding-keymap (make-sparse-keymap)))
(set-keymap-parent my-overriding-keymap (current-local-map))
(use-local-map my-overriding-keymap)
(define-key my-overriding-keymap (kbd "C-M-x") 
      '(lambda () (interactive) (message "Done!")))))

显然可以适当地自定义键绑定。这仅在当前缓冲区中起作用。

答案 1 :(得分:4)

给定符号的值和函数属性是分开的,因此大概make-local-variable只会影响,而fset会对函数进行操作< / em> property。

你可能最好更详细地描述你想要做什么,但一个通用的解决方案是使用“around advice”用你自己的代码包装原始函数。

(defadvice foo (around my-foo-wrapper)
  (if (not (and (boundp 'use-my-foo) 'use-my-foo))
      ad-do-it
    (message "Not done:(")))
(ad-activate 'foo)

;; in special buffer
(set (make-local-variable 'use-my-foo) t)

编辑:(关于其他键映射注释)

也许你想要在你的特殊缓冲区中定义一个次要模式。次模式键映射优先于主模式键映射,因此您只需在次模式映射中定义相同的绑定。请参阅define-minor-mode

答案 2 :(得分:3)

如何将符号函数写入符号值,然后通过其他函数进行评估?

(defvar my-buffer-local-function
  (lambda ()
    (interactive)
    (message "Default message"))
  "This variable contains buffer local function")

(make-variable-buffer-local 'my-buffer-local-function)

(defun run-my-buffer-local-function (&rest args)
  "This function run buffer-local function"
  (interactive)
  (if (called-interactively-p 'any)   ;To call interactively AND to
                                      ;be able to have elisp-calls
    (call-interactively my-buffer-local-function)
    (apply my-buffer-local-function args)))

(setq my-buffer-local-function
  (lambda (&optional arg)
    (interactive "sinsert message: ")
    (message (concat "Not so default message: " arg))))

明显不好的一面是,如果my-buffer-local-function是互动的,那么效果很好。如果没有,run-my-buffer-local-function仍然是互动的,并且在M-x列表中可见。我认为你不能制作有时候互动的功能,因为interactive应该是顶级电话。

顺便说一句,您可以使用相同的名称命名功能和值。

答案 3 :(得分:1)

如果函数定义是特定于缓冲区的,那通常表明它是主要模式特定的。如果事实上就是这种情况,那么处理它的正确方法是使用适合于特定缓冲区/模式的不同功能。如果问题是键绑定,那么只需将键绑定到主模式键映射中的专用函数。