Где я должен включить ленивую инициализацию?

13

Я хочу добавить конкретную привязку ключа к режиму латекса:

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

В то же время я хочу установить его только при загрузке определенного режима. Поэтому я хотел бы знать, есть ли предпочтение (лучшая практика) между использованием соответствующего hook ( latex-mode-hook) для выполнения этого или использованием предложения (with-eval-after-load "tex-mode" ...для переноса определения привязки ключа. Я проверил оба, и они работают хорошо, однако мне интересно, какой из них является правильным способом сделать это.

jrbalderrama
источник
2
with-eval-after-loadзагружается один раз , поэтому смена ключа происходит там. Хуки загружаются каждый раз, когда запускается режим , например, при загрузке нового файла, связанного с режимом, или если хук определен. Вы могли бы загрузить, например, flyspell-modeили hl-line-modeв крюк. По моему init.elя использую with-eval-after-loadпримерно 160 раз и add-hook110 раз. Ленивый инициат является хорошим инициатором (IMO).
Расм
На мой взгляд, @rasmus звучит как ответ, если у вас есть время :) Разница в том, сколько раз запускается код, является основной для рассмотрения. (Это также единственный, о котором я могу думать ...)
Шон Оллред
Почему плохая идея менять привязки клавиш в хуках
tarsius

Ответы:

18

Ленивый инициат - это хороший инициат.

(ИМО)

Когда использовать with-eval-after-load

with-eval-after-loadзагружаются один раз , когда определенная функция или файл будет первой загружена, поэтому раскладка смена явно идет в один из них. Не в последнюю очередь, потому что раскладка клавиш может быть неизвестна во время инициализации [попробуйте что-то вроде (define-key message-mode-map (kbd "C-c f") 'Footnote-add-footnote)в emacs -q]. Хук не является хорошим решением, поскольку он связывает функцию с клавишей каждый раз, когда хук запускается. Как Tarsius заметки, вы можете узнать больше о том, почему не на local-set-keyкрючки.

Наконец, обратите внимание, что with-eval-after-loadGNU Emacs 24.4 представляет собой двухстрочную оболочку, eval-after-loadгде нет bodyнеобходимости заключать в кавычки.

Когда использовать крючки

Хуки - это список функций, загружаемых при каждом выполнении критерия, например, при запуске определенного режима. Обычное использование хуков - это загрузка второстепенных режимов, таких как flyspell-modeили hl-line-mode. Например (add-hook 'org-agenda-mode-hook 'hl-line-mode). Как указывает Реми , add-hooksон умен и будет делать правильные вещи, даже если переменная хука еще не загружена. Тем не менее, у меня есть много предложений, подобных следующему, которые могут быть незначительными для увеличения скорости, но дают ощущение организации и структуры зависимости:

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

Зачем добавлять в крючок после org-agenda? Как всегда, C-h v org-agenda-mode-hook C-jдоставляет. Крюк определяется org-agenda.elкак показано на рисунке *help*.

Загрузка дополнительных функций with-eval-after-load

with-eval-after-loadтакже важно для загрузки дополнительных функций. Вы, вероятно, хотели бы что-то вроде (with-eval-after-load 'org (require 'org-inlinetask))загрузки org inlinetasks. Чтобы понять почему (find-library "org-inlinetask"). Так как org-inlinetasks.elнепосредственно (require 'org), все удобные , autoloadчто ваши дружественные Сопровождающие Emacs взяли большую осторожность , чтобы обеспечить будет «игнорировали» и все org.el(c)будет загружен.

Но что, если для вашего (личного) defunтребуется несколько мест? Если вы действительно требовательны, вы можете поместить defunфайлы s в другой файл load-pathи добавить autoloadкуки, или вы можете указать Emacs, где найти функцию с этой autoloadфункцией. Тогда что-то вроде этого будет работать:

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

Или вы могли бы так же, require orgкак он в свою очередь потянетcdlatex

И, честно говоря, личная защита не будет иметь большого значения для времени инициации большую часть времени. 1150 строк личных определений (84 определения) в моем init.elдобавлении 0,02 секунды по сравнению с ванильным Emacs.

Измерение времени инициализации

Простой способ приблизить время инициализации

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

(эталон против emacs -q.

Но чтобы получить более детальное приближение того, где узкие места инициализации, посмотрите на Джо Шефера esup.

Наконец, время загрузки не исчезает волшебным образом. Вы только продвигаете его вперед (в той степени, в которой вы используете все функции в каждом сеансе).

Расмус
источник
1
Вам не нужно помещать add-hook в with-eval-after-load, потому что add-hook свяжет переменную, если ее там еще нет.
Реми
Вы правы! Может ли быть все еще увеличение скорости от этого, хотя? [Я постараюсь обновить ответ позже, чтобы отразить это]
rasmus
Как насчет defuns, которые позже я хотел бы привязать к привязке крюка или ключа. Должен ли я определить defun вне with-eval-after-loadбез потери ленивых преимуществ инициализации?
Jrbalderrama
5

В дополнение к вашим предложениям eval-after-loadи использованию крючка, позвольте мне предложить use-package.el. Вы можете делать то, что вам нужно с

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

Латекс не будет загружен до после вы потребуете.

Как примечание: осторожное использование use-packageсократило время запуска до секунды. (Раньше это занимало около четырех секунд.)

Шон Оллред
источник
Спасибо за ваше предложение. Я также собирался использовать use-package, но я действительно хочу понять, как это сделать без дополнительных пакетов.
Джрбалдеррама
1
Замечание @jrbalderrama, которое use-packageбудет поставляться с Emacs 25.
Шон Оллред