Gdzie powinienem podać leniwą inicjalizację?

13

Chcę dodać określone powiązanie klucza do trybu lateksowego:

(define-key latex-mode-map (kbd "<f6>") 'my-latex-defun)

Jednocześnie chcę to ustawić tylko po załadowaniu określonego trybu. Chciałbym więc wiedzieć, czy istnieje preferencja (najlepsza praktyka) między użyciem odpowiedniego hook ( latex-mode-hook) w celu osiągnięcia tego, a użyciem klauzuli (with-eval-after-load "tex-mode" ...do zawijania definicji powiązania klucza. Przetestowałem oba i działają dobrze, ale zastanawiam się, który z nich jest właściwy.

jrbalderrama
źródło
2
with-eval-after-loadjest ładowany jeden raz , więc następuje zmiana mapy klawiszy. Haki ładują się przy każdym uruchomieniu trybu , np. Przy ładowaniu nowego pliku związanego z trybem lub niezależnie od tego, jak hak jest zdefiniowany. Załadowałbyś np. flyspell-modeLub hl-line-modehak. W moim init.elużywam with-eval-after-loadokoło 160 razy i add-hook110 razy. Leniwy init jest dobrym inicjatorem (IMO).
rasmus
@rasmus brzmi jak odpowiedź, jeśli masz czas :) Moim zdaniem, rozróżnienie, ile razy kod jest uruchamiany, jest najważniejsze. (Jest to również jedyny, o którym myślę ...)
Sean Allred
Aby dowiedzieć się, dlaczego
tarsius

Odpowiedzi:

18

Leniwy inicjator jest dobrym inicjatorem.

(IMO)

Kiedy użyć with-eval-after-load

with-eval-after-loadjest ładowany raz, gdy pewna funkcja lub plik jest ładowany po raz pierwszy , więc zmiana mapy klawiszy wyraźnie wchodzi w jeden z nich. Nie tylko dlatego, że mapa klawiszy może nie być znana podczas inicjalizacji [spróbuj czegoś takiego jak (define-key message-mode-map (kbd "C-c f") 'Footnote-add-footnote)w emacs -q]. Hak nie jest tutaj dobrym rozwiązaniem, ponieważ wiąże funkcję z klawiszem przy każdym uruchomieniu haka. Jak Tarsius notatek, można dowiedzieć się więcej o tym, dlaczego nie do local-set-keyw haki.

Na koniec zauważ, że with-eval-after-loadGNU Emacs 24.4 jest 2-liniowym opakowaniem, w eval-after-loadktórym bodynie trzeba cytować.

Kiedy stosować haki

Haki to lista funkcji ładowanych za każdym razem, gdy spełnione jest kryterium, np. Uruchamiany jest określony tryb. Powszechnym zastosowaniem haków jest ładowanie mniejszych trybów, takich jak flyspell-modelub hl-line-mode. Np (add-hook 'org-agenda-mode-hook 'hl-line-mode). Jak podkreśla Rémi , add-hooksjest sprytny i zrobi właściwą rzecz, nawet jeśli zmienna haka nie została jeszcze załadowana. Niemniej jednak mam wiele klauzul, takich jak następujące, które mogą być nieistotne dla przyspieszenia, ale dają poczucie organizacji i struktury zależności:

(with-eval-after-load 'org-agenda
  (add-hook 'org-agenda-mode-hook 'hl-line-mode))

Po co dodawać do haka po org-agenda? Jak zawsze C-h v org-agenda-mode-hook C-jdostarcza. Hak jest zdefiniowany org-agenda.eljak pokazano w *help*.

Ładowanie dodatkowych funkcji with-eval-after-load

with-eval-after-loadjest również ważne przy ładowaniu dodatkowych funkcji. Prawdopodobnie chcesz coś takiego jak (with-eval-after-load 'org (require 'org-inlinetask))ładowanie orglinaskasks. Aby zobaczyć dlaczego (find-library "org-inlinetask"). Ponieważ org-inlinetasks.elbezpośrednio (require 'org)wszystkie miłe autoloadrzeczy, o które dbali Twoi przyjaźni opiekunowie Emacsa, zostaną „zignorowane” i wszystkie org.el(c)zostaną załadowane.

Ale co jeśli twoje (osobiste) defunjest wymagane kilka miejsc? Jeśli jesteś naprawdę wybredny, możesz umieścić defuns w innym pliku w swoim pliku load-pathi dodać autoloadpliki cookie lub możesz powiedzieć Emacsowi, gdzie znaleźć funkcję za pomocą tej autoloadfunkcji. Wtedy coś takiego działałoby:

(autoload 'org-cdlatex-mode "org" "cdlatex mode from org.")
(with-eval-after-load "latex"
  (add-hook 'TeX-mode-hook 'org-cdlatex-mode))

Lub możesz tak, require orgjak to z kolei pociągniecdlatex

I, szczerze mówiąc, osobisty defun nie będzie miał większego znaczenia dla czasu inicjacji przez większość czasu. 1150 linii osobistej porażki (84 porażek) u mnie init.eldodaje 0,02s w stosunku do waniliowego Emacsa.

Pomiar czasu inicjalizacji

Prostym sposobem na przybliżenie czasu inicjalizacji jest

time emacs --eval "(kill-emacs)"

(punkt odniesienia przeciwko emacs -q.

Ale aby uzyskać bardziej szczegółowe przybliżenie, gdzie są wąskie gardła podczas inicjalizacji, sprawdź Joe Schafer esup.

Wreszcie czas ładowania nie znika magicznie. Popychasz go tylko do przodu (do tego stopnia, że ​​używasz wszystkich funkcji w każdej sesji).

rasmus
źródło
1
Nie musisz umieszczać add-hook w opcji-eval-after-load, ponieważ add-hook wiąże zmienną, jeśli jeszcze jej nie ma.
Rémi
Masz rację! Czy jednak nadal może z tego wynikać wzrost prędkości? [Postaram się zaktualizować odpowiedź później, aby to odzwierciedlić]
rasmus
A co z odrzuceniem, które później chciałbym powiązać z hakiem lub kluczem? Czy powinienem zdefiniować defun poza with-eval-after-loadnie tracąc leniwych zalet inicjalizacji?
jrbalderrama
5

Oprócz twoich sugestii eval-after-loadi używania haka, pozwól, że zasugeruję use-package.el. Możesz robić, co potrzebujesz

(use-package latex
  :ensure auctex
  :bind ("<f6>" . my-latex-defun))

LaTeX nie zostanie załadowany aż po poprosić go.

Na marginesie: ostrożne użycie use-packageskróciło moje czasy uruchamiania do mniej niż sekundy. (Zwykle zajmowało to około czterech sekund.)

Sean Allred
źródło
Dziękuje za twoją sugestię. Zastanawiałem się również nad użyciem pakietu use, ale naprawdę chcę wymyślić, jak to zrobić bez dodatkowych pakietów.
jrbalderrama
1
@jrbalderrama note, który use-packagema zostać wysłany z Emacsem 25.
Sean Allred