Как заменить элемент списка?

36

У меня это по умолчанию в моем auto-mode-alist:

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

(даже с emacs -Q). Я хотел бы заменить js2-modeна javascript-mode. Конечно, я мог бы использовать, assq-delete-allа потом add-to-listснова, но мне интересно, нет ли лучшего способа.

Редактировать: Я явно не хочу использовать Customize, я предпочитаю создавать свои собственные init.el.

mbork
источник

Ответы:

37

Хотя ответ @ Dan является идеальным решением, в нем нет необходимости. Одна из причин , почему Emacs использует ассоциативный список здесь является то , что с креном вы можете просто добавить новый элемент в передней части списка , и он будет теневым матчи дальше вниз по списку .

(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
Нарисовался
источник
1
Не хочешь сказать, почему понизить?
Дрю
1
Я проголосовал за ваш ответ - спасибо, это приятно знать. Я предполагаю, что downvoter считал, что это решение не элегантно (я должен сказать, что я согласен, хотя и не считаю это причиной для понижения голосов - в конце концов, это и решает мою проблему, и является ценной информацией!)
mbork
7
По общему признанию, это не отвечает на вопрос о том, как заменить . Суть в том, что вам не нужно заменять (если у вас нет какой-то другой необходимости, кроме той, что вы описали).
Дрю
2
вопрос не был действительно о замене в техническом смысле, а изменение в смысле более высокого уровня.
Эрик Каплун
2
Это всегда будет работать независимо от того, находится ли минус в чистом пространстве или будет удален в какой-то будущей версии.
политза
33

Используйте setfдля изменения значения на месте:

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

Если вы хотите заменить значение в списке, то setfэто обобщенный механизм, который вам необходим для этого. Для более идиоматического способа справиться с auto-mode-alist, см. Ответ @ Drew (и его объяснение затенения).

Дэн
источник
Вау. Я чувствую себя глупо сейчас. Благодарность! (И идея (почти) каждого места, которое можно использовать, setfдействительно должна быть показана ребятам из Java.)
mbork
6
@mbork Возможно, вам понравится это классическое объяснение ребятам из Perl. lists.warhead.org.uk/pipermail/iwe/2005-July/000130.html
purple_arrows
@mbork: на самом деле нет причин чувствовать себя глупо - setfвсе время используется в Common Lisp, но вы сталкиваетесь с этим гораздо реже в elisp.
Дан
@ Дан: правда. Теперь мне интересно, почему Elisp использует setfтак редко, по сравнению с CL ...
mbork
19

Вероятно, самый быстрый способ изменить ячейку минуса setcdr

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

(setcdr CELL NEWCDR)

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

Стоит отметить, что setfнедоступен в более старых 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))
Шон Оллред
источник
Вы случайно не знаете, какая версия Emacs добавлена setf?
dshepherd
1
@dsheperd нет, нет. Зачем тебе знать? Я бы сказал, что любой emacs, который должен быть предназначен для новой разработки, будет иметь setf, но он может не обрабатывать тот тип данных, который вы хотите установить. Они называются обобщенными переменными .
Шон Оллред
Я хотел знать, нормально ли было использовать setf в каком-то новом коде, но, как вы сказали, оказалось, что в любом случае не было обобщенной переменной для того, что я хотел, до слишком недавней версии.
dshepherd
5

OP запрашивает решение, которое обрабатывает списки, которые имеют строковые ключи. Чтобы справиться с этим, посмотрите на этот вопрос . Если случайно вам нужно обрабатывать только списки с символьными клавишами, то, начиная с Emacs 25, вы можете использовать:

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

заменить CDR. Если у вас есть доступ к Emacs 26, этот метод работает со строковыми ключами следующим образом:

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

Обратите внимание, что в Emacs 26 есть и другие способы обработки строковых ключей; см. этот вопрос, как указано выше.

Радон Росборо
источник
(setf (alist-get "\\.js\\'" auto-mode-alist nil nil #'equal) 'js2-mode)должно работать (требуется Emacs 26, хотя).
npostavs
@RadonRosborough: есть функция редактирования. Подумайте, чтобы исправить ваш ответ.
Антонио
Вы используете alist-getстроку "\\.js\\'", но alist-getона основана на том assq, что она не будет работать со строкой, как вы утверждаете в своем ответе.
Антонио
@antonio Ах да, ты совершенно прав. Я не осознавал, что опубликованный вопрос действительно требует решения, которое обрабатывает строковые ключи. Я сделаю правку, спасибо!
Радон Росборо
2

Если вы знаете, что больше не будете использовать javascript-mode, оставьте auto-mode-alist без изменений и добавьте его в свой init.el

  (defalias 'javascript-mode 'js2-mode "Some handy explanation goes here.")
Матиас
источник
1
На самом деле, нет javascript-mode, на самом деле: javascript-modeэто только псевдоним для js-mode(по умолчанию), и это было сделано именно так, чтобы пользователи могли делать то, что вы предлагаете, если они предпочитают js2-mode(без потери возможности использовать, js-modeесли они этого хотят).
Стефан
Я получил ответ по привычке использовать псевдонимы для cperl-mode и nxml-mode. Так что бы сделать трюк здесь? (defalias 'js-mode' js2-mode)?
Матиас
1
Ты не понял меня. Я говорю, что ваш ответ совершенно правильный и не мешает вам использовать «режим javascript», поскольку то, что вы называете этим именем, действительно js-mode(в отличие от того, что происходит perl-mode, например).
Стефан
Понял ... (случайный пользователь javascript-режима здесь)
Матиас