Bagaimana cara mengganti elemen alist?

36

Saya memiliki ini secara default di auto-mode-alist:

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

(bahkan dengan emacs -Q). Saya ingin mengganti js2-modeuntuk javascript-mode. Tentu saja, saya bisa menggunakan assq-delete-alldan sekali add-to-listlagi, tetapi saya bertanya-tanya apakah tidak ada cara yang lebih baik.

Sunting: Saya secara eksplisit tidak ingin menggunakan Sesuaikan, saya lebih suka membuat init.elsendiri.

mbork
sumber

Jawaban:

37

Sementara jawaban Dan adalah solusi yang sangat bagus, itu tidak perlu. Salah satu alasan Emacs menggunakan alist di sini adalah bahwa dengan alist Anda cukup menambahkan elemen baru ke bagian depan daftar dan itu akan membayangi kecocokan lebih jauh ke bawah daftar .

(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
Drew
sumber
1
Mau bilang kenapa downvote?
Drew
1
Saya mengubah jawaban Anda - terima kasih, itu baik untuk diketahui. Saya kira downvoter menganggap solusi ini tidak bagus (saya harus mengatakan bahwa saya setuju, meskipun tidak menganggapnya sebagai alasan untuk downvoting - bagaimanapun juga, keduanya memecahkan masalah saya dan merupakan informasi yang berharga!)
mbork
7
Memang, itu tidak menjawab pertanyaan tentang bagaimana cara mengganti . Intinya adalah Anda tidak perlu mengganti (kecuali jika Anda memiliki kebutuhan lain selain yang Anda jelaskan).
Drew
2
pertanyaannya bukan benar - benar tentang penggantian dalam arti teknis tetapi lebih pada perubahan dalam arti tingkat yang lebih tinggi.
Erik Allik
2
Ini akan selalu berfungsi tidak masalah jika kontra ada di ruang murni atau akan dihapus dalam beberapa versi masa depan.
politza
33

Gunakan setfuntuk mengubah nilai di tempat:

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

Jika Anda ingin mengganti nilai dalam daftar, maka setfadalah mesin umum yang perlu Anda lakukan. Untuk cara yang lebih idiomatis untuk menghadapinya auto-mode-alist, lihat jawaban @ Drew (dan penjelasannya tentang membayangi).

Dan
sumber
Wow. Saya merasa bodoh sekarang. Terima kasih! (Dan gagasan (hampir) setiap tempat untuk setfdapat benar-benar ditunjukkan kepada orang-orang Jawa.)
mbork
6
@mbork Anda mungkin menikmati penjelasan klasik ini untuk para Perl. lists.warhead.org.uk/pipermail/iwe/2005-July/000130.html
purple_arrows
@ mbork: benar-benar tidak ada alasan untuk merasa konyol - setfdigunakan sepanjang waktu di Common Lisp, tetapi Anda sering berlari melewatinya di elisp.
Dan
@Dan: benar. Sekarang saya bertanya-tanya mengapa Elisp setfjarang menggunakan , dibandingkan dengan CL ...
mbork
19

Cara tercepat untuk benar-benar mengubah sel kontra mungkin setcdr

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

(setcdr CELL NEWCDR)

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

Perlu dicatat bahwa setftidak tersedia di Emacsen yang lebih tua, tetapi setcdrmemang demikian.


*** 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
sumber
Apakah Anda tahu versi Emacs yang ditambahkan setf?
dshepherd
1
@dsheperd tidak begitu saja, tidak. Mengapa Anda perlu tahu? Saya akan mengatakan emacs apa pun yang harus ditargetkan untuk pengembangan baru akan memiliki setf, tetapi mungkin tidak ada penanganan untuk itu untuk jenis data yang ingin Anda atur. Mereka disebut variabel umum .
Sean Allred
Saya ingin tahu apakah boleh menggunakan setf dalam beberapa kode baru, tetapi seperti yang Anda katakan ternyata tidak ada variabel umum untuk apa yang saya inginkan sampai versi yang terlalu baru.
dshepherd
5

OP meminta solusi yang menangani alists yang memiliki kunci string. Untuk mengatasinya, lihat pertanyaan ini . Jika kebetulan Anda hanya perlu menangani alists dengan tombol simbol, maka pada Emacs 25 Anda dapat menggunakan:

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

untuk mengganti cdr. Jika Anda memiliki akses ke Emacs 26, teknik ini berfungsi dengan kunci string, sebagai berikut:

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

Perhatikan bahwa ada juga cara lain dalam Emacs 26 untuk menangani kunci string; lihat pertanyaan ini sebagaimana disebutkan di atas.

Radon Rosborough
sumber
(setf (alist-get "\\.js\\'" auto-mode-alist nil nil #'equal) 'js2-mode)harus bekerja (membutuhkan Emacs 26 sekalipun).
npostavs
@RadonRosborough: ada fitur edit. Pertimbangkan untuk memperbaiki jawaban Anda.
antonio
Anda menggunakan alist-getdengan string "\\.js\\'", tetapi alist-getdidasarkan pada assq, sehingga tidak akan bekerja dengan string seperti yang Anda klaim dalam jawaban Anda.
antonio
@antonio Oh ya, Anda sepenuhnya benar. Saya tidak menyadari bahwa pertanyaan seperti yang diposting sebenarnya membutuhkan solusi yang menangani kunci string. Saya akan mengeditnya, terima kasih!
Radon Rosborough
2

Jika Anda tahu Anda tidak akan menggunakan mode javascript lagi, biarkan auto-mode-alist tidak tersentuh dan tambahkan ke init.el Anda

  (defalias 'javascript-mode 'js2-mode "Some handy explanation goes here.")
Matthias
sumber
1
Sebenarnya, tidak ada javascript-mode, sungguh: javascript-modehanya alias untuk js-mode(secara default) dan dilakukan dengan cara ini secara khusus sehingga pengguna dapat melakukan seperti yang Anda sarankan jika mereka lebih suka js2-mode(tanpa kehilangan kemampuan untuk digunakan js-modejika mereka mau).
Stefan
Saya mendapatkan jawaban dari kebiasaan aliasing untuk mode cperl dan mode nxml. Jadi apa triknya di sini? (defalias 'js-mode' js2-mode)?
Matthias
1
Anda salah paham dengan saya. Saya mengatakan bahwa jawaban Anda benar dan tidak menghalangi Anda untuk menggunakan "javascript-mode" karena apa yang Anda panggil dengan nama itu benar-benar js-mode(bertentangan dengan apa yang terjadi perl-mode, misalnya).
Stefan
Mengerti ... (pengguna mode javascript biasa di sini)
Matthias