Comment remplacer un élément d'une liste?

36

J'ai ceci par défaut dans mon auto-mode-alist:

("\\.js\\'" . javascript-mode)

(même avec emacs -Q). Je voudrais remplacer js2-modepar javascript-mode. Bien sûr, je pourrais utiliser encore assq-delete-allet add-to-listencore, mais je me demande s'il n'y a pas de meilleur moyen.

Edit: je ne veux pas explicitement utiliser Customize, je préfère créer moi- init.elmême.

Mbork
la source

Réponses:

37

Bien que la réponse de @ Dan soit une solution parfaite, elle n’est pas nécessaire. L' une des raisons pour lesquelles Emacs utilise un alist ici est que avec un alist vous pouvez simplement ajouter un nouvel élément à l'avant de la liste et il ombre matchs plus bas dans la liste .

(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
A dessiné
la source
1
Attention à dire pourquoi le vote négatif?
Drew
1
J'ai voté votre réponse - merci, c'est bon à savoir. Je suppose que le votant inférieur a trouvé cette solution inélégante (je dois dire que je suis d’accord, mais ne le considérez pas comme une raison de voter négativement - après tout, cela résout mon problème et constitue un élément d’information précieux!)
mbork
7
Certes, cela ne répond pas à la question de savoir comment remplacer . Son objectif est que vous n'avez pas besoin de remplacer (sauf si vous avez un autre besoin que celui que vous avez décrit).
Drew
2
la question ne concernait pas vraiment le remplacement au sens technique, mais plutôt le changement au sens le plus élevé.
Erik Kaplun
2
Cela fonctionnera toujours, que les inconvénients soient dans l’espace pur ou soient supprimés dans une version ultérieure.
Politza
33

Utilisez setfpour changer la valeur en place:

(setf (cdr (rassoc 'javascript-mode auto-mode-alist)) 'js2-mode)

Si vous souhaitez remplacer une valeur dans la liste, setfvous devez utiliser le mécanisme généralisé. Pour la manière plus idiomatique de traiter le auto-mode-alist, voir la réponse de @ Drew (et son explication de l'observation).

Dan
la source
Sensationnel. Je me sens stupide maintenant. Merci! (Et l'idée de (presque) tous les endroits où il est setfpossible de le savoir devrait vraiment être montrée aux gars de Java.)
mbork
6
@mbork Vous pourriez apprécier cette explication classique des gars de Perl. lists.warhead.org.uk/pipermail/iwe/2005-July/000130.html
purple_arrows
@mbork: vraiment aucune raison de se sentir bête - setfon l'utilise tout le temps dans Common Lisp, mais on le croise beaucoup moins souvent dans elisp.
Dan
@Dan: vrai. Maintenant, je me demande pourquoi Elisp utilise setfsi rarement, comparé à CL ...
mbork
19

Le moyen le plus rapide de changer réellement la cellule contre est probablement setcdr

setcdr is a built-in function in `C source code'.

(setcdr CELL NEWCDR)

Set the cdr of CELL to be NEWCDR.  Returns NEWCDR.

Il est à noter que ce setfn’est pas disponible dans les versions précédentes d’Emacsen setcdr.


*** Welcome to IELM ***  Type (describe-mode) for help.
ELISP> (setq tmp '((one . 1) (two . 2) (three . 4)))
((one . 1)
 (two . 2)
 (three . 4))

ELISP> (setcdr (assq 'three tmp) 3)
3 (#o3, #x3, ?\C-c)
ELISP> tmp
((one . 1)
 (two . 2)
 (three . 3))
Sean Allred
la source
Savez-vous quelle version d'Emacs a été ajoutée setf?
dshepherd
1
@dsheperd pas désinvolte, non. Pourquoi avez-vous besoin de savoir? Je dirais que tous les emacs devant faire l’objet d’un nouveau développement auront été configurés, mais qu’ils ne seront peut-être pas gérés pour le type de données que vous souhaitez définir. On les appelle variables généralisées .
Sean Allred
Je voulais savoir s'il était possible d'utiliser setf dans un nouveau code, mais comme vous l'avez dit, il s'avère qu'il n'y avait pas de variable généralisée pour ce que je voulais jusqu'à une version trop récente de toute façon.
dshepherd
5

L'OP demande une solution qui gère les listes contenant des clés de chaîne. Pour gérer cela, voir cette question . Si, par hasard, vous n’avez besoin que de gérer les listes avec des clés de symbole, à partir d’Emacs 25, vous pouvez utiliser:

(setf (alist-get <key> <alist>) <value>)

pour remplacer un cdr. Si vous avez accès à Emacs 26, cette technique fonctionne avec les clés de chaîne, comme suit:

(setf (alist-get "\\.js\\'" auto-mode-alist nil nil #'equal) 'js2-mode)

Notez qu'il existe également dans Emacs 26 d'autres moyens de gérer les clés de chaîne; voir cette question comme mentionné ci-dessus.

Radon Rosborough
la source
(setf (alist-get "\\.js\\'" auto-mode-alist nil nil #'equal) 'js2-mode)devrait fonctionner (nécessite Emacs 26 cependant).
npostavs
@RadonRosborough: il existe une fonctionnalité d'édition. Pensez à réparer votre réponse.
antonio
Vous utilisez alist-getavec la chaîne "\\.js\\'", mais alist-getest basé sur assq, donc cela ne fonctionnera pas avec une chaîne comme vous le prétendez dans votre réponse.
Antonio
@antonio Oh oui, vous avez tout à fait raison. Je n'avais pas réalisé que la question telle que postée nécessite une solution qui gère les clés de chaîne. Je vais faire le montage, merci!
Radon Rosborough
2

Si vous savez que vous n'utiliserez plus le mode javascript, laissez la fonction auto-mode-alist intacte et ajoutez-la à votre fichier init.el.

  (defalias 'javascript-mode 'js2-mode "Some handy explanation goes here.")
Matthias
la source
1
En fait, il n’existe pas javascript-modevraiment, javascript-modec’est uniquement un alias pour js-mode(par défaut) et cela a été fait spécifiquement pour que les utilisateurs puissent faire ce que vous suggérez s’ils le préfèrent js2-mode(sans perdre la possibilité d’utiliser js-modes’ils le souhaitent).
Stefan
J'ai trouvé ma réponse dans l'habitude de créer des alias pour cperl-mode et nxml-mode. Alors, que ferait le tour ici? (defalias 'js-mode' js2-mode)?
Matthias
1
Tu m'as mal compris. Je dis que votre réponse est tout à fait juste et ne vous empêche pas d'utiliser le "mode javascript" puisque ce que vous appelez par ce nom l'est vraiment js-mode(contrairement à ce qui se passe perl-modepar exemple).
Stefan
Je l'ai ... (utilisateur occasionnel en mode javascript ici)
Matthias