2011-11-04 2 views
10

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

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

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

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

Но это не так. Любые идеи?

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

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

+0

В чем проблема, которую вы на самом деле пытаетесь решить? Возможно, есть другой подход, который будет работать лучше. Откуда вы знаете, когда хотите «Готово!» и «Не сделано :(»? –

+0

@Trey В режиме справки пакета есть функция навигации (переход к разделам). Он короткий и элегантный. Но для одного очень конкретного типа файла справки мне нужно другое поведение. функция в функции, которую я надеялся переопределить локально. Ответ на этот вопрос делает то, что я хочу на самом деле. – VitoshKa

ответ

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

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

+0

Прохладный трюк. Он рассматривает лучший мой вопрос до сих пор. Хотя это немного длинно для моей цели. Я буду держать это в голове на будущее. – VitoshKa

4

свойства значения и функции данного символа является отдельным, и, предположительно 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) 

EDIT: (относительно дополнительных комментариев ключа-карты)

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

+0

Это для моего пакета, поэтому я могу изменить функцию напрямую, а не консультировать ее. Проблема в том, что для одного * очень конкретный буфер Мне нужна другая функциональность, и я не хочу уклоняться от функции только для этого особого случая. Это интерактивная функция, поэтому изменение локальной карты будет делать, но я не знаю, как это сделать. Отредактировано Q. – VitoshKa

+0

Обновленный ответ – phils

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

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

+0

Это делает трюк, и я пойду за ним, но @desudesudesu ответит на исходный вопрос о создании функций buffer-local, который имеет немного теоретической стороны для Это. Поэтому я принимаю его ответ. – VitoshKa

1

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

Смежные вопросы