Jak zastąpić element listy?

36

Mam to domyślnie w moim auto-mode-alist:

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

(nawet z emacs -Q). Chciałbym podstawić js2-modeza javascript-mode. Oczywiście, mogę używać assq-delete-all, a następnie add-to-listponownie, ale zastanawiam się, czy nie ma lepszego sposobu.

Edycja: wyraźnie nie chcę używać opcji Dostosuj, wolę tworzyć init.elwłasne.

Mbork
źródło

Odpowiedzi:

37

O ile odpowiedź @ Dana jest doskonałym rozwiązaniem, nie jest konieczna. Jednym z powodów, dla których Emacs używa tutaj alist , jest to, że za pomocą alist można po prostu dodać nowy element na początku listy i będzie on dopasowywał dopasowania w dalszej części listy .

(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
Drew
źródło
1
Chcesz powiedzieć, dlaczego głosowanie negatywne?
Drew
1
Poparłem twoją odpowiedź - dziękuję, dobrze wiedzieć. Wydaje mi się, że downvoter uznał to rozwiązanie za nieeleganckie (muszę przyznać, że się zgadzam, choć nie uważam tego za powód do rezygnacji z głosowania - w końcu rozwiązuje on mój problem i jest cenną informacją!)
mbork
7
Trzeba przyznać, że nie odpowiada to na pytanie, jak wymienić . Chodzi o to, że nie musisz go wymieniać (chyba że masz jakieś inne potrzeby niż te, które opisałeś).
Drew
2
pytanie tak naprawdę nie dotyczyło zastąpienia w sensie technicznym, ale raczej zmiany w sensie wyższego poziomu.
Erik Allik,
2
To zawsze będzie działać bez względu na to, czy minusy są w czystej przestrzeni, czy też zostaną usunięte w przyszłości.
politza
33

Użyj, setfaby zmienić wartość na miejscu:

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

Jeśli chcesz zastąpić wartość na liście, setfto musisz uogólnić maszynę. Aby uzyskać bardziej idiomatyczny sposób radzenia sobie z auto-mode-alist, zobacz odpowiedź @ Drew (i jego wyjaśnienie dotyczące cieniowania).

Dan
źródło
Łał. Czuję się teraz głupio. Dzięki! (I pomysł (prawie) każdego miejsca, aby setfmóc, powinien być naprawdę pokazany
facetom
6
@mbork To klasyczne wytłumaczenie dla facetów Perla. lists.warhead.org.uk/pipermail/iwe/2005-July/000130.html
purple_arrows
@mork: naprawdę nie ma powodu, aby czuć się głupio - setfjest używany przez cały czas w Common Lisp, ale w elisp spotykasz go o wiele rzadziej.
Dan
@Dan: true. Teraz zastanawiam się, dlaczego Elisp setftak rzadko używa , w porównaniu do CL ...
mbork
19

Najszybszym sposobem na faktyczną zmianę komórki przeciwnej jest prawdopodobnie setcdr

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

(setcdr CELL NEWCDR)

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

Warto zauważyć, że setfnie jest dostępne w starszych Emacsen, ale setcdrjest.


*** 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
źródło
Czy wiesz, która wersja Emacsa została dodana setf?
dshepherd,
1
@dsheperd nie z ręki, nie. Po co ci to wiedzieć? Powiedziałbym, że każdy emacs, który powinien być ukierunkowany na nowy program, będzie miał setf, ale może nie być obsługiwany dla tego rodzaju danych, które chcesz ustawić. Nazywa się je zmiennymi uogólnionymi .
Sean Allred
Chciałem wiedzieć, czy można użyć setf w jakimś nowym kodzie, ale jak powiedziałeś, okazuje się, że nie było uogólnionej zmiennej dla tego, czego chciałem, aż do najnowszej wersji.
dshepherd
5

OP prosi o rozwiązanie, które obsługuje listy zawierające klucze łańcuchowe. Aby sobie z tym poradzić, zobacz to pytanie . Jeśli przypadkiem potrzebujesz tylko obsługiwać listy przy pomocy klawiszy symboli, to od Emacsa 25 możesz użyć:

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

zastąpić cdr. Jeśli masz dostęp do Emacsa 26, ta technika działa z następującymi kluczami:

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

Zauważ, że w Emacsie 26 istnieją również inne sposoby obsługi kluczy ciągów; zobacz to pytanie, jak wspomniano powyżej.

Radon Rosborough
źródło
(setf (alist-get "\\.js\\'" auto-mode-alist nil nil #'equal) 'js2-mode)powinien działać (wymaga Emacsa 26).
npostavs
@RadonRosborough: istnieje funkcja edycji. Zastanów się, aby naprawić odpowiedź.
Antonio
Używasz alist-getłańcucha "\\.js\\'", ale alist-getjest oparty na assq, więc nie będzie działać z łańcuchem, jak twierdzisz w odpowiedzi.
Antonio
@antonio O tak, masz całkowitą rację. Nie zdawałem sobie sprawy, że postawione pytanie faktycznie wymaga rozwiązania, które obsługuje klucze ciągów. Dokonam edycji, dzięki!
Radon Rosborough
2

Jeśli wiesz, że już nigdy nie użyjesz trybu javascript, pozostaw auto-mode-alist nietknięty i dodaj do pliku init.el

  (defalias 'javascript-mode 'js2-mode "Some handy explanation goes here.")
Matthias
źródło
1
W rzeczywistości nie ma javascript-mode, naprawdę: javascript-modejest tylko aliasem js-mode(domyślnie) i zostało to zrobione specjalnie po to, aby użytkownicy mogli robić to, co sugerujesz, jeśli wolą js2-mode(bez utraty możliwości używania, js-modejeśli chcą).
Stefan
Swoją odpowiedź zaczerpnąłem z nawyku aliasingu dla trybu cperl i trybu nxml. Więc co by tu zrobiło? (defalias 'js-mode' js2-mode)?
Matthias
1
Nie zrozumiałeś mnie. Mówię, że twoja odpowiedź jest dokładnie poprawna i nie przeszkadza ci w używaniu „trybu javascript”, ponieważ tak naprawdę nazywasz to js-mode(na przykład w przeciwieństwie do tego, co się dzieje perl-mode).
Stefan
Rozumiem ... (tutaj zwykły użytkownik trybu javascript)
Matthias