emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Feature request: permanent-local values in hooks buffer local values


From: Lennart Borgman (gmail)
Subject: Re: Feature request: permanent-local values in hooks buffer local values
Date: Fri, 07 Dec 2007 01:25:51 +0100
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.9) Gecko/20071031 Thunderbird/2.0.0.9 Mnenhy/0.7.5.666

Richard Stallman wrote:
In a way, yes. But remember the goal. It is to let a minor mode that is turned on in the buffer survive changing major mode.

    There are two kind of things to survive:

1) buffer local variable values, which are survived by using (put 'VARIABLE 'permanent-local t)

    2) buffer local entries in hooks. Those are what I am asking about here.

I see.  I did not understand your aim before.
Here's a possible implementation.

1. Put a property on hook variables to identify them for this
special processing.

2. Put another property (as you suggested) on hook functions
to indicate they should be preserved.

3. Now it is possible for kill-all-local-variables
to identify hook variables, scan their local values,
and preserve specific hooks.


I have tested another solution, defining a macro instead for minor mode authors to use if they want their minor mode to survive changes in major mode. The advantage of that is that it makes it very clear what is needed. And I do not think there is any big performance penalty. A disadvantage is however that the minor mode initialization will be a bit different whether this macro is available or not. Therefore it would be good if the macro were added to Emacs.

Here is the macro:


(defmacro mumamo-make-change-major-survivor (name hook-fun-list var-list)
  "Define functions for major mode change survival.
Minor mode authors that want their buffer local
minor mode to survive when the major mode in the buffer is
changed can use this macro.

An example of such a minor mode may be flymake minor mode. For
flymake this call can be used:

  (eval-after-load 'mumamo
    (mumamo-make-change-major-survivor
     flymake
     '((after-change-functions flymake-after-change-function)
       (after-save-hook flymake-after-save-hook)
       (kill-buffer-hook flymake-kill-buffer-hook))
     '(flymake-mode
       flymake-is-running
       flymake-timer
       flymake-last-change-time
       flymake-check-start-time
       flymake-check-was-interrupted
       flymake-err-info
       flymake-new-err-info
       flymake-output-residual
       flymake-mode-line
       flymake-mode-line-e-w
       flymake-mode-line-status
       flymake-temp-source-file-name
       flymake-master-file-name
       flymake-temp-master-file-name
       flymake-base-dir
       )))

Then in `flymake-mode' a call to the functions
`flymake-add-survivor' and `flymake-remove-survivor \(which was defined by the macro called above) must be done.

The macro defines two functions for the user of this macro to
call, NAME-add-survivor and NAME-remove-survivor. A typical use
is for a minor mode to use the first when turning on and the
second when turning off.

NAME-add-survivor will add to local hooks according to the list
HOOK-FUN-LIST and arrange so that those additions to the local
hooks will be setup again after a major mode change. Also make
sure that the local values of the variables in VAR-LIST survives
a major mode change.

NAME-remove-survivor does the opposite of this.

NAME should be a symbol. HOOK-FUN-LIST should be a list where
each record has the format

  \(HOOK-NAME HOOK-FUNCTION)

where HOOK-NAME is the name of the hook to which HOOK-FUNCTION
should be added locally.

VAR-LIST should be a list of variable symbols."
  (let* ((sname (symbol-name name))
         (NAME-add-survivor    (intern (concat sname "-add-survivor")))
         (NAME-remove-survivor (intern (concat sname "-remove-survivor")))
         (NAME-acmmh-f         (intern (concat sname "-acmmh-f")))
         (NAME-cmmh-f          (intern (concat sname "-cmmh-f"))))

    `(progn

       (defun ,NAME-add-survivor ()
         "Add major mode change surviving.
This function should be called by the code that calls the macro
`make-change-major-survivor'."
         (dolist (rec ,hook-fun-list)
           (let ((hook (nth 0 rec))
                 (func (nth 1 rec)))
             (add-hook hook func nil t)))
         ;; Set up to survive major mode change
         (add-hook 'change-major-mode-hook ',NAME-cmmh-f nil t)
;;(lwarn t :warning "add survivor, cmmh=%S" change-major-mode-hook)
         )

       (defun ,NAME-remove-survivor ()
         "Remove major mode change surviving.
This function should be called by the code that calls the macro
`make-change-major-survivor'."
         (dolist (rec ,hook-fun-list)
           (let ((hook (nth 0 rec))
                 (func (nth 1 rec)))
             (remove-hook hook func t)))
         ;; Set up to survive major mode change
         (remove-hook 'change-major-mode-hook ',NAME-cmmh-f t)
;;(lwarn t :warning "rem survivor, cmmh=%S" change-major-mode-hook)
         )

       (defun ,NAME-acmmh-f ()
         "Restore after changing major mode.
This function is added locally to `after-change-major-mode-hook'."
         ;;(remove-hook 'after-change-major-mode-hook ',NAME-acmmh-f t)
         (,NAME-add-survivor)
         ;; Remove 'permanent-local t
         (dolist (sym ,var-list)
           (put sym 'permanent-local nil)))

       (defun ,NAME-cmmh-f ()
         "Set up to restore after changing major mode.
This function is added locally to `change-major-mode-hook'."
         (add-hook 'after-change-major-mode-hook ',NAME-acmmh-f nil t)
;;(lwarn t :warning "cmmh-f, acmmh=%S" after-change-major-mode-hook)
         (put 'after-change-major-mode-hook 'permanent-local t)
         ;; Note: I can see no way to later remove the
         ;; 'permanent-local property that is set here without
         ;; getting potential problems.
         ;;
         ;; Add 'permanent-local t
         (dolist (sym ,var-list)
           (put sym 'permanent-local t))))))




reply via email to

[Prev in Thread] Current Thread [Next in Thread]