буферная локальная функция в elisp - PullRequest
12 голосов
/ 04 ноября 2011

Я хотел бы переопределить существующую функцию foo, но только для определенного буфера.

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

Я прыгал это будет делать:

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

Но это не так. Есть идеи?

[EDIT: В качестве альтернативы, поскольку функция привязана к ключу, достаточно изменить привязку только для текущего буфера. Но я не вижу, как это сделать. Локальная таблица ключей используется всеми буферами в основном режиме. Модификация его изменяет привязки во всех буферах в этом основном режиме.

Единственное уродливое решение, о котором я могу подумать, - это установить текстовое свойство keymap для всего буфера. Это единственный способ продолжить?]

Ответы [ 4 ]

5 голосов
/ 04 ноября 2011

Вы можете создать функцию, которая заменит вас, что-то вроде этого:

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

Очевидно, настроить привязку ключа соответствующим образом. Это действует только в текущем буфере.

4 голосов
/ 04 ноября 2011

Значение и функциональные свойства данного символа являются отдельными, и поэтому предположительно make-local-variable будет влиять только на значение , тогда как fset работает со свойством function .

Вероятно, вам лучше описать более подробно, что именно вы хотите сделать, но одно общее решение состояло бы в том, чтобы использовать "совет по принципу", чтобы обернуть оригинальную функцию своим собственным кодом.

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

3 голосов
/ 05 ноября 2011

Как насчет записи ваших символьных функций в символьные значения, а затем их оценки какой-нибудь другой функцией?

(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 должен быть вызовом верхнего уровня.

Кстати, вы можете называть функцию и значение с тем же именем.

1 голос
/ 05 ноября 2011

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

...