Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

actions automatiques à l'ouverture d'un fichier

3 réponses
Avatar
Stéphane Dutailly
Bonjour,

Je me demandais s'il est possible de demander à Emacs d'effectuer
automatiquement certaines actions à l'ouverture d'un fichier.
Concrètement, j'utilise Emacs essentiellement pour écrire des fichiers
tex. Une fois un fichier .tex ouvert, j'ai souvent besoin de réaliser
les 2 actions suivantes:
- passer en mode majeur org-mode (M-x org-mode)
- revenir tout de suite en mode majeur latex-mode (M-x latex-mode)

Autre exemple, la plupart de mes fichiers .tex sont en latin1 et je les
aurais bien converti en utf8 (ce que je fais avec C-x RET f, soit la
commande set-buffer-file-coding-system). Si Emacs le faisait
automatiquement à l'ouverture du fichier sans que j'ai à faire la
manipulation, ce serait pratique.

Je me dis qu'Emacs doit pouvoir réaliser automatiquement ces actions à
l'ouverture du fichier. La seule piste que j'ai trouvé, c'est de rajouter:

(setq auto-mode-alist (cons '("\\.tex" . org-mode) auto-mode-alist))

dans mon .emacs, mais cela ne réalise que la première action et je ne
vois pas comment modifier la commande précédente pour obtenir ce que je
veux.

Merci d'avance pour toute piste.

Stéphane

3 réponses

Avatar
Pascal J. Bourguignon
Stéphane Dutailly writes:

Bonjour,

Je me demandais s'il est possible de demander à Emacs d'effectuer
automatiquement certaines actions à l'ouverture d'un fichier.



Bien sur.


Concrètement, j'utilise Emacs essentiellement pour écrire des fichiers
tex. Une fois un fichier .tex ouvert, j'ai souvent besoin de réaliser
les 2 actions suivantes:
- passer en mode majeur org-mode (M-x org-mode)
- revenir tout de suite en mode majeur latex-mode (M-x latex-mode)



C'est bizarre. Quel effet de bord en attends tu ?
Peut être veux tu en fait latex-mode et le mode mineur orgstruct-mode ?


Autre exemple, la plupart de mes fichiers .tex sont en latin1 et je
les aurais bien converti en utf8 (ce que je fais avec C-x RET f, soit
la commande set-buffer-file-coding-system). Si Emacs le faisait
automatiquement à l'ouverture du fichier sans que j'ai à faire la
manipulation, ce serait pratique.



Oui.


Je me dis qu'Emacs doit pouvoir réaliser automatiquement ces actions à
l'ouverture du fichier. La seule piste que j'ai trouvé, c'est de
rajouter:

(setq auto-mode-alist (cons '(".tex" . org-mode) auto-mode-alist))

dans mon .emacs, mais cela ne réalise que la première action et je ne
vois pas comment modifier la commande précédente pour obtenir ce que
je veux.



M-x apropos RET auto alist RET révèle déjà auto-coding-alist, mais comme
auto-mode-alist, c'est fait pour imposer un encodage spécifique
préalable. Dans ton cas, tu veux probablement une règle plus
sophistiquée, comme si l'encodage du fichier est latin1, le transformer
en utf-8.

Je pense que le plus simple sera de mettre une fonction dans
find-file-hook. Note qu'il y a souvent déjà plusieurs fonctions dans
cette liste, et que leur ordre d'exécution peut être important, dans la
mesure où elles ont des effets de bord comme celle que tu veux.

(require 'cl)

(defun sd--mode-name (mode-symbol)
(let ((name (symbol-name mode-symbol)))
(if (string-match "-mode$" name)
(intern (substring name 0 (- (length name) 5)))
mode-symbol)))


(defun sd--ensure-coding (wanted-coding)
(unless (eql buffer-file-coding-system wanted-coding)
(set-buffer-file-coding-system wanted-coding)
(add-file-local-variable 'coding wanted-coding)))


(defun sd--ensure-modes (wanted-major wanted-minors)
;; Bug: this doesn't remove the old major mode local variable line.
(let ((missing-major-p (not (eql major-mode wanted-major)))
(missing-minors (mapcan
(lambda (mm)
(unless (and (boundp mm)
(symbol-value mm))
(list mm)))
wanted-minors)))
;; set the right major mode:
(when missing-major-p
(funcall wanted-major))
;; set the missing minor modes:
(dolist (mm missing-minors)
(funcall mm 1))
;; save them:
(dolist (mm (reverse missing-minors))
(add-file-local-variable 'mode (sd--mode-name mm)))
(when missing-major-p
(add-file-local-variable 'mode (sd--mode-name wanted-major)))))

(defvar *tex-file-regexp* "^/home/sd/.*.tex$")

(defun sd--tex-file-meat ()
(interactive) ; so you may have fun calling it interactively too.
(when (string-match *tex-file-regexp* buffer-file-name)
(sd--ensure-modes 'latex-mode '(orgstruct-mode))
(sd--ensure-coding 'utf-8-unix)))


(pushnew sd--text-file-meat 'find-file-hook)



--
__Pascal Bourguignon__
http://www.informatimago.com/
"Le mercure monte ? C'est le moment d'acheter !"
Avatar
Stéphane Dutailly
Whaou!! Impressionnant!! Merci beaucoup Pascal, à ce point là c'est bien
plus qu'une piste!

Concrètement, j'utilise Emacs essentiellement pour écrire des fichiers
tex. Une fois un fichier .tex ouvert, j'ai souvent besoin de réaliser
les 2 actions suivantes:
- passer en mode majeur org-mode (M-x org-mode)
- revenir tout de suite en mode majeur latex-mode (M-x latex-mode)



C'est bizarre. Quel effet de bord en attends tu ?
Peut être veux tu en fait latex-mode et le mode mineur orgstruct-mode ?




Alors en fait, quand je travaille dans mon fichier tex, j'active
successivement org-mode puis latex-mode car si je n'active pas org-mode
au préalable je ne peux pas activer le mode mineur orgtbl-mode. Dans une
réponse à mon précédent message, Jean-Jacques signalait qu'il n'a pas ce
problème chez lui (avec pourtant la même version d'Emacs 24.3.1).

Je n'utilise pas orgstruct-mode. J'ai fait un test rapide, je me suis
aperçu qu'après avoir ouvert un fichier tex, je pouvais activer
orgstruct-mode mais pas orgtbl-mode (quand je fais M-x org TAB, j'ai
orgstruct-mode comme complétion possible mais pas orgtbl-mode). J'ai pu
m'apercevoir qu'il y a une commande org-reload et lorsque je l'active,
j'ai ensuite beaucoup plus de commandes proposées (toujours en faisant
M-x org TAB) dont orgtbl-mode. Du coup, j'ai rajouté (org-reload) dans
mon LaTeX-mode-hook perso et... ça marche! (dès que j'ouvre un fichier
tex, je peux tout de suite activer orgtbl-mode. Ça résout de façon
simple mon premier problème.


Autre exemple, la plupart de mes fichiers .tex sont en latin1 et je
les aurais bien converti en utf8 (ce que je fais avec C-x RET f, soit
la commande set-buffer-file-coding-system). Si Emacs le faisait
automatiquement à l'ouverture du fichier sans que j'ai à faire la
manipulation, ce serait pratique.





Je pense que le plus simple sera de mettre une fonction dans
find-file-hook. Note qu'il y a souvent déjà plusieurs fonctions dans
cette liste, et que leur ordre d'exécution peut être important, dans la
mesure où elles ont des effets de bord comme celle que tu veux.




Je vais tâcher de tester tout cela rapidement mais avant tout, encore un
grand merci pour ces exemples!
Je crois que je comprends à peu près sd--ensure-coding; sd--ensure-modes
est plus compliquée pour moi (même s'il me semble tout de même
comprendre les grandes lignes) mais je ne comprends pas sd--mode-name
utilisé par sd--ensure-modes.


(require 'cl)

(defun sd--mode-name (mode-symbol)
(let ((name (symbol-name mode-symbol)))
(if (string-match "-mode$" name)
(intern (substring name 0 (- (length name) 5)))
mode-symbol)))


(defun sd--ensure-coding (wanted-coding)
(unless (eql buffer-file-coding-system wanted-coding)
(set-buffer-file-coding-system wanted-coding)
(add-file-local-variable 'coding wanted-coding)))


(defun sd--ensure-modes (wanted-major wanted-minors)
;; Bug: this doesn't remove the old major mode local variable line.
(let ((missing-major-p (not (eql major-mode wanted-major)))
(missing-minors (mapcan
(lambda (mm)
(unless (and (boundp mm)
(symbol-value mm))
(list mm)))
wanted-minors)))
;; set the right major mode:
(when missing-major-p
(funcall wanted-major))
;; set the missing minor modes:
(dolist (mm missing-minors)
(funcall mm 1))
;; save them:
(dolist (mm (reverse missing-minors))
(add-file-local-variable 'mode (sd--mode-name mm)))
(when missing-major-p
(add-file-local-variable 'mode (sd--mode-name wanted-major)))))

(defvar *tex-file-regexp* "^/home/sd/.*.tex$")

(defun sd--tex-file-meat ()
(interactive) ; so you may have fun calling it interactively too.
(when (string-match *tex-file-regexp* buffer-file-name)
(sd--ensure-modes 'latex-mode '(orgstruct-mode))
(sd--ensure-coding 'utf-8-unix)))


(pushnew sd--text-file-meat 'find-file-hook)




Donc sd--tex-file-meat permet de réaliser les différentes actions et
avec (pushnew sd--text-file-meat 'find-file-hook), cette fonction est
«lancée par find-file» uniquement sur les fichiers tex grâce à
when (string-match *tex-file-regexp* buffer-file-name), c'est çà?


Stéphane
Avatar
Pascal J. Bourguignon
Stéphane Dutailly writes:

Je crois que je comprends à peu près sd--ensure-coding;
sd--ensure-modes est plus compliquée pour moi (même s'il me semble
tout de même comprendre les grandes lignes) mais je ne comprends pas
sd--mode-name utilisé par sd--ensure-modes.



Désolé, j'ai oublié les chaînes de documentation :


(require 'cl)

(defun sd--mode-name (mode-symbol)





"Remove the -mode suffix of the given symbol.
Example: (sd--mode-name 'orgtbl-mode) -> orgtbl
"

(let ((name (symbol-name mode-symbol)))
(if (string-match "-mode$" name)
(intern (substring name 0 (- (length name) 5)))
mode-symbol)))


(defun sd--ensure-coding (wanted-coding)





"If `wanted-coding' is not the current buffer-file-coding-system,
then changes to it, and add a file-local variable to remember the choice."


(unless (eql buffer-file-coding-system wanted-coding)
(set-buffer-file-coding-system wanted-coding)
(add-file-local-variable 'coding wanted-coding)))


(defun sd--ensure-modes (wanted-major wanted-minors)





"If `wanted-major` and the list `wanted-minors` are not the
current major and minor modes, then change to them, and add them
as file-local variables to remember the choice."

;; Bug: this doesn't remove the old major mode local variable line.
(let ((missing-major-p (not (eql major-mode wanted-major)))
(missing-minors (mapcan
(lambda (mm)
(unless (and (boundp mm)
(symbol-value mm))
(list mm)))
wanted-minors)))
;; set the right major mode:
(when missing-major-p
(funcall wanted-major))
;; set the missing minor modes:
(dolist (mm missing-minors)
(funcall mm 1))
;; save them:
(dolist (mm (reverse missing-minors))
(add-file-local-variable 'mode (sd--mode-name mm)))
(when missing-major-p
(add-file-local-variable 'mode (sd--mode-name wanted-major)))))





La seule difficulté ici, c'est que:

1- quand on change le mode majeur, l'ensemble des modes mineurs
configuré change,

2- il faut changer le mode majeur avant de mettre à jour les variables
locales du fichiers, car le mode majeur détermine la syntaxe des
lignes de commentaire utilisées

3- quand on change les modes mineurs, on les change, et comme on veut
les insérer dans les variables locales du fichier dans l'ordre
inverse, il faut donc se souvenir de ceux qu'il faut configurer.

D'où l'ordre des deux variables et des quatre opérations, qui doit en
fait être (désolé, j'ai copié collé une étape intermédiaire dans mon
message précédent) :

(defun sd--ensure-modes (wanted-major wanted-minors)
"If `wanted-major` and the list `wanted-minors` are not the
current major and minor modes, then change to them, and add them
as file-local variables to remember the choice."
;; Bug: this doesn't remove the old major mode local variable line.
(let ((missing-major-p (not (eql major-mode wanted-major))))
;; set the right major mode:
(when missing-major-p
(funcall wanted-major))
(let ((missing-minors (mapcan
(lambda (mm)
(unless (and (boundp mm)
(symbol-value mm))
(list mm)))
wanted-minors)))
;; set the missing minor modes:
(dolist (mm missing-minors)
(funcall mm 1))
;; save them:
(dolist (mm (reverse missing-minors))
(add-file-local-variable 'mode (sd--mode-name mm)))
(when missing-major-p
(add-file-local-variable 'mode (sd--mode-name wanted-major))))))


(defvar *tex-file-regexp* "^/home/sd/.*.tex$")

(defun sd--tex-file-meat ()
(interactive) ; so you may have fun calling it interactively too.
(when (string-match *tex-file-regexp* buffer-file-name)
(sd--ensure-modes 'latex-mode '(orgstruct-mode))
(sd--ensure-coding 'utf-8-unix)))


(pushnew sd--text-file-meat 'find-file-hook)





Désolé, ça devrait être:

(pushnew 'sd--text-file-meat find-file-hook)


Donc sd--tex-file-meat permet de réaliser les différentes actions et
avec (pushnew sd--text-file-meat 'find-file-hook), cette fonction est
«lancée par find-file» uniquement sur les fichiers tex grâce à
when (string-match *tex-file-regexp* buffer-file-name), c'est çà?



Find-file appelle toutes les fonctions qui sont dans la liste
find-file-hook après avoir ouvert le fichier. Alors, la fonction
sd--text-file-meat teste si c'est un fichier .tex dans le répertoire
/home/sd/, et si c'est le cas, change les modes et encodage.


--
__Pascal Bourguignon__
http://www.informatimago.com/
"Le mercure monte ? C'est le moment d'acheter !"