Como substituir um elemento de um alist?

36

Eu tenho isso por padrão no meu auto-mode-alist:

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

(mesmo com emacs -Q). Eu gostaria de substituir js2-modepor javascript-mode. Claro, eu poderia usar assq-delete-alle, add-to-listnovamente, mas estou me perguntando se não há uma maneira melhor.

Editar: eu explicitamente não quero usar o Customize, prefiro criar o meu init.el.

mbork
fonte

Respostas:

37

Embora a resposta de @ Dan seja uma solução perfeitamente adequada, ela é desnecessária. Uma das razões pelas quais o Emacs usa uma lista alista aqui é que, com uma lista alista, você pode simplesmente adicionar um novo elemento à frente da lista e ele sombreará as correspondências mais abaixo na lista .

(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
Desenhou
fonte
11
Gostaria de dizer por que o voto negativo?
Tirou
11
Votei na sua resposta - obrigado, é bom saber. Eu acho que o downvoter achou esta solução deselegante (devo dizer que concordo, embora não o considere uma razão para a votação rebaixada - afinal, isso resolve meu problema e é uma informação valiosa!)
mbork
7
É certo que não responde à questão de como substituir . Seu ponto é que você não precisa substituí-lo (a menos que você tenha alguma outra necessidade além da que você descreveu).
Tirou
2
a questão não era realmente sobre substituir no sentido técnico, mas mudar no sentido de nível superior.
precisa
2
Isso sempre funcionará, não importa se os contras estão no espaço puro ou serão removidos em alguma versão futura.
politza 30/11
33

Use setfpara alterar o valor no local:

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

Se você deseja substituir um valor na lista, então setfé o mecanismo generalizado necessário. Para a maneira mais idiomática de lidar com isso auto-mode-alist, consulte a resposta de @ Drew (e sua explicação sobre sombreamento).

Dan
fonte
Uau. Eu me sinto estúpido agora. Obrigado! (E a idéia de (quase) todos os lugares para ser setfcapaz realmente deve ser mostrado para caras Java.)
mbork
6
@mbork Você pode aproveitar esta explicação clássica para os caras do Perl. lists.warhead.org.uk/pipermail/iwe/2005-July/000130.html
purple_arrows
@mbork: realmente não há razão para parecer bobo - setfé usado o tempo todo no Common Lisp, mas você o encontra com muito menos frequência no elisp.
Dan
@ Dan: verdade. Agora eu estou perguntando por que Elisp usa setftão raramente, em comparação com CL ...
mbork
19

A maneira mais rápida de realmente alterar a célula contras é provavelmente 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 a pena notar que setfnão está disponível no Emacsen mais antigo, mas 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
fonte
Você sabe qual versão do Emacs foi adicionada setf?
Dshepherd 6/11/19
11
@dsheperd não de imediato, não. Por que você precisa saber? Eu diria que qualquer emacs que deva ser direcionado para novo desenvolvimento terá setf, mas pode não haver manipulação para o tipo de dados que você deseja definir. Eles são chamados de variáveis ​​generalizadas .
Sean Allred
Eu queria saber se não havia problema em usar o setf em algum código novo, mas como você disse, não havia variável generalizada para o que eu queria até uma versão muito recente.
Dshepherd 7/11
5

O OP solicita uma solução que lida com listas que possuem chaves de string. Para lidar com isso, consulte esta pergunta . Se, por acaso, você só precisar lidar com listas com teclas de símbolos, então a partir do Emacs 25 você poderá usar:

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

para substituir um cdr. Se você tiver acesso ao Emacs 26, essa técnica funcionará com chaves de seqüência de caracteres, da seguinte maneira:

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

Observe que também existem outras maneiras no Emacs 26 de lidar com chaves de string; veja esta pergunta como mencionado acima.

Radon Rosborough
fonte
(setf (alist-get "\\.js\\'" auto-mode-alist nil nil #'equal) 'js2-mode)deve funcionar (requer o Emacs 26 embora).
npostavs
@RadonRosborough: existe um recurso de edição. Considere corrigir sua resposta.
antonio
Você está usando alist-geta string "\\.js\\'", mas ela alist-geté baseada em assq, portanto, ela não funcionará com uma string como você reivindica em sua resposta.
antonio
@antonio Ah, sim, você está totalmente correto. Eu não tinha percebido que a pergunta postada realmente exige uma solução que lida com chaves de string. Eu vou fazer a edição, obrigado!
Radon Rosborough 02/02
2

Se você sabe que nunca mais usará o modo javascript, deixe o modo automático alista intocado e adicione ao seu init.el

  (defalias 'javascript-mode 'js2-mode "Some handy explanation goes here.")
Matthias
fonte
11
Na verdade, não existe javascript-mode, na verdade: javascript-modeé apenas um alias para js-mode(por padrão) e foi feito dessa maneira especificamente para que os usuários possam fazer o que você sugere, se preferirem js2-mode(sem perder a capacidade de usar js-modese quiserem).
Stefan
Eu deduzi minha resposta do hábito de usar alias no modo cperl e no modo nxml. Então, o que faria o truque aqui? (defalias 'js-mode' js2-mode)?
Matthias
11
Você me entendeu mal. Estou dizendo que sua resposta é exatamente correta e não o impede de usar o "modo javascript", pois o que você chama por esse nome é realmente js-mode(ao contrário do que acontece perl-mode, por exemplo).
Stefan
Entendi ... (usuário casual em modo javascript aqui)
Matthias