【问题标题】:buffer-local function in elispelisp 中的缓冲区局部函数
【发布时间】:2011-11-04 10:58:00
【问题描述】:

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

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

我希望这样可以:

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

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

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

我能想到的唯一丑陋的解决方案是为整个缓冲区设置一个键映射文本属性。这是唯一的方法吗?]

【问题讨论】:

  • 您真正想要解决的问题是什么?也许有一种不同的方法会更好。你怎么知道你什么时候想要“完成!”和“未完成:(”?
  • @Trey 包的帮助模式具有导航功能(跳转到部分)。它简短而优雅。但是对于一种非常特定类型的帮助文件,我需要不同的行为。我没有将功能构建到函数中,而是希望能够在本地重新定义它。您的回答实际上符合我的要求。

标签: function emacs elisp buffer local


【解决方案1】:

您可以创建一个为您执行覆盖的函数,类似于以下内容:

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

显然要适当地自定义键绑定。这仅对当前缓冲区有效。

【讨论】:

  • 这可以解决问题,我会去做,但@desudesudesu 的回答解决了使函数成为缓冲区本地的原始问题,这有一点理论方面。因此我接受了他的回答。
【解决方案2】:

给定符号的值和函数属性是分开的,因此推测make-local-variable 只会影响,而fset 作用于函数 属性.

您可能最好更详细地描述您想要做什么,但一种通用的解决方案是使用“环绕建议”将原始函数与您自己的代码一起包装。

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

编辑:(关于额外的键映射 cmets)

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

【讨论】:

  • 这是我的包,所以我可以直接修改函数而不是建议它。问题是,对于一个 very 特定的缓冲区,我需要不同的功能,并且不想仅仅为了这个非常特殊的情况而混淆该功能。这是一个交互式功能,因此可以在本地修改地图。但我也不知道该怎么做。编辑了 Q。
【解决方案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 应该是顶级调用。

顺便说一句,你可以用相同的名字命名函数和值。

【讨论】:

  • 很酷的把戏。它解决了我迄今为止最好的问题。虽然对于我的目的来说有点冗长。我会牢记这一点,以备将来使用。
【解决方案4】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-05
    相关资源
    最近更新 更多