¿Cómo reemplazar un elemento de una lista?

36

Tengo esto por defecto en mi auto-mode-alist:

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

(incluso con emacs -Q). Me gustaría sustituir js2-modepor javascript-mode. Por supuesto, podría usar assq-delete-ally luego add-to-listotra vez, pero me pregunto si no hay una mejor manera.

Editar: explícitamente no quiero usar Personalizar, prefiero crear mi propio init.el.

mbork
fuente

Respuestas:

37

Si bien la respuesta de @ Dan es una solución perfectamente buena, es innecesaria. Una de las razones por las que Emacs usa una lista aquí es que con una lista puede simplemente agregar un nuevo elemento al principio de la lista y sombreará las coincidencias más abajo en la lista .

(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
Dibujó
fuente
1
¿Te importaría decir por qué el voto negativo?
Dibujó el
1
Voté tu respuesta: gracias, es bueno saberlo. Supongo que el votante negativo pensó que esta solución no era elegante (tengo que decir que estoy de acuerdo, aunque no lo considero una razón para votar negativamente; después de todo, ¡ambos resuelven mi problema y es una información valiosa!)
mbork
77
Es cierto que no responde a la pregunta de cómo reemplazar . Su punto es que no necesita reemplazar (a menos que tenga otra necesidad que la que describió).
Dibujó el
2
La pregunta no era realmente reemplazar en el sentido técnico, sino cambiar en el sentido de nivel superior.
Erik Kaplun
2
Esto siempre funcionará sin importar si las desventajas están en el espacio puro o se eliminarán en alguna versión futura.
politza
33

Use setfpara cambiar el valor en el lugar:

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

Si desea reemplazar un valor en la lista, entonces setfes la maquinaria generalizada que necesita para hacerlo. Para la forma más idiomática de lidiar con esto auto-mode-alist, vea la respuesta de @ Drew (y su explicación sobre el sombreado)

Dan
fuente
Guau. Me siento estúpido ahora. ¡Gracias! (Y la idea de (casi) todos los lugares para setfpoder realmente debería mostrarse a los chicos de Java.)
mbork 11/11
66
@mbork Podrías disfrutar de esta explicación clásica para los chicos de Perl. lists.warhead.org.uk/pipermail/iwe/2005-July/000130.html
purple_arrows
@mbork: realmente no hay razón para sentirse tonto: setfse usa todo el tiempo en Common Lisp, pero te encuentras con mucha menos frecuencia en elisp.
Dan
@Dan: cierto. Ahora me pregunto por qué Elisp usa setftan raramente, en comparación con CL ...
mbork
19

La forma más rápida de cambiar realmente la celda de contras es probablemente setcdr

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

(setcdr CELL NEWCDR)

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

Vale la pena señalar que setfno está disponible en Emacsen anterior, pero lo setcdrestá.


*** 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
fuente
¿Sabes qué versión de Emacs agregó setf?
dshepherd
1
@dsheperd no fuera de lugar, no. ¿Por qué necesitas saberlo? Diría que cualquier emacs que debería ser el objetivo de un nuevo desarrollo tendrá setf, pero es posible que no se maneje para el tipo de datos que desea establecer. Se llaman variables generalizadas .
Sean Allred
Quería saber si estaba bien usar setf en algún código nuevo, pero como dijiste, no había una variable generalizada para lo que quería hasta una versión demasiado reciente de todos modos.
dshepherd
5

El OP solicita una solución que maneje las listas que tienen claves de cadena. Para manejar eso, vea esta pregunta . Si por casualidad solo necesita manejar listas con teclas de símbolos, entonces a partir de Emacs 25 puede usar:

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

para reemplazar un cdr. Si tiene acceso a Emacs 26, esta técnica funciona con las teclas de cadena, de la siguiente manera:

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

Tenga en cuenta que también hay otras formas en Emacs 26 para manejar claves de cadena; vea esta pregunta como se mencionó anteriormente.

Radon Rosborough
fuente
(setf (alist-get "\\.js\\'" auto-mode-alist nil nil #'equal) 'js2-mode)debería funcionar (aunque requiere Emacs 26).
npostavs
@RadonRosborough: hay una función de edición. Considere arreglar su respuesta.
antonio
Está utilizando alist-getla cadena "\\.js\\'", pero alist-getse basa en ella assq, por lo que no funcionará con una cadena como afirma en su respuesta.
antonio
@antonio Oh sí, tienes toda la razón. No me había dado cuenta de que la pregunta publicada realmente requiere una solución que maneje las claves de cadena. Haré la edición, gracias!
Radon Rosborough
2

Si sabe que no volverá a usar javascript-mode nunca más, deje la lista de modo automático intacta y agregue a su init.el

  (defalias 'javascript-mode 'js2-mode "Some handy explanation goes here.")
Matías
fuente
1
En realidad, no existe javascript-mode, realmente: javascript-modees solo un alias para js-mode(por defecto) y se hizo de esta manera específicamente para que los usuarios puedan hacer lo que usted sugiere si lo prefieren js2-mode(sin perder la capacidad de usar js-modesi lo desean).
Stefan
Derivé mi respuesta del hábito de aliasing para cperl-mode y nxml-mode. Entonces, ¿qué haría el truco aquí? (defalias 'js-mode' js2-mode)?
Matthias
1
Me malentendiste. Estoy diciendo que su respuesta es exactamente correcta y no le impide usar el "modo javascript" ya que lo que llama con ese nombre es realmente js-mode(al contrario de lo que sucede perl-mode, por ejemplo).
Stefan
Lo tengo ... (usuario casual en modo javascript aquí)
Matthias