Différence entre eval-after-load
et add-hook
J’expliquais dans le billet sur le démarrage d’Emacs que
le code de eval-after-load sera exécuté seulement une fois […]
Les nomdumode-mode-hooks, eux, sont exécutés pour chaque buffer dans lequel le mode sera activé.
Pour illustrer mes propos, voici un code à mettre dans un nouveau buffer (C-x b auie) :
(setq auie 0) (setq nrst 0) (eval-after-load "python" ;puisque dans python.el '(progn (setq auie (1+ auie)) )) (add-hook 'python-mode-hook (lambda () (setq nrst (1+ nrst)) )) (progn (python-mode) (message (concat "auie vaut :" (number-to-string auie) ", nrst : " (number-to-string nrst))))
Passez en mode elisp (M-x emacs-lisp-mode), puis évaluez le buffer
(M-x eval-buffer). Un petit message devrait s’afficher. Allez à la
fin du buffer (M->) et évaluez la dernière sexp (C-x C-e). Évaluez
plusieurs fois ; constatez que auie
n’augmente pas, nrst
si.
Autrement dit, si l’on veut exécuter du code lorsque l’on passe dans
le mode foo
, et que l’on ne veut pas charger le fichier foo.el
ni
faire un (require 'foo)
dans son fichier init.el
, on a deux
possibilités :
- Utiliser
eval-after-load
pour exécuter du code une fois. - Utiliser
add-hook
pour exécuter du code plusieurs fois.
En fait, eval-after-load
va exécuter le code à chaque fois que la
bibliothèque est chargée. Mais généralement, on fait un (autoload
'foo-mode "foo" "docstring")
; au premier appel de foo-mode
(avec
un M-x ou avec un add-to-list 'auto-mode-alist
), foo.el
est
chargé et le code du eval-after-load
est exécuté. Aux prochains
appels de foo-mode
, foo.el
est déjà chargé, le code n’est plus
exécuté.
eval-after-load
est donc approprié si l’on veut changer des valeurs
par défaut :
(eval-after-load "ace-jump-mode" '(ace-jump-mode-enable-mark-sync)) ;par défaut, c’est à disable (eval-after-load "foo-mode" '(my-init-foo-mode)) ; on charge des choses en plus (eval-after-load "org" '(require 'ox-md nil t)) ;l’export markdown n’est pas chargé automatiquement (eval-after-load 'foo-mode '(define-key foo-mode-map (kbd "C-à") 'my-useful-fonction)) ; un raccourci utilisé seulement pour ce mode
Le add-hook
lui est utilisé à chaque fois que foo-mode
est lancé
(et non pas à chaque fois que foo.el
est chargé). C’est ce choix que
l’on fera si l’on veut activer un minor mode pour un major mode ou si on
veut changer des valeurs de variables changées par le major mode.
; à chaque fois que l’on passe en elisp mode, on met les parenthèses en couleur (add-hook 'emacs-lisp-mode 'rainbow-delimiters-mode) ;avant de sauver, on lance un nettoyage (add-hook 'before-save-hook 'whitespace-cleanup) ;le mode foo redéfinit à chaque fois C-> et je ne veux pas (add-hook 'foo-mode-hook '(lambda () (define-key foo-mode-map "\C->" 'foobar))) ;on met c-basic-offset à 4 (add-hook 'c-mode-common-hook '(lambda () (setq c-basic-offset 4))) ;si on veut différentes valeurs selon que l’on soit en foo ou en bar (add-hook foo-mode-hook '(lambda () (setq spam 42)) nil t) (add-hook bar-mode-hook '(lambda () (setq spam 3.14)) nil t)
En espérant avoir été clair.