¿Dónde debo incluir una inicialización perezosa?

13

Quiero agregar un enlace de tecla específico al modo látex:

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

Al mismo tiempo, quiero configurarlo solo cuando se carga el modo específico. Por lo tanto, me gustaría saber si existe una preferencia (mejor práctica) entre usar el gancho apropiado ( latex-mode-hook) para lograr eso o usar la cláusula (with-eval-after-load "tex-mode" ...para ajustar la definición de enlace de clave. Probé ambos y funcionan bien, sin embargo, me pregunto cuál es la forma correcta de hacerlo.

jrbalderrama
fuente
2
with-eval-after-loadse carga una vez , por lo que un cambio de mapa de teclas va allí. Los ganchos se cargan cada vez que se ejecuta el modo , por ejemplo, al cargar un nuevo archivo asociado con el modo, o como se define el gancho. Cargaría, por ejemplo, flyspell-modeo hl-line-modeen un gancho. En mi init.eluso with-eval-after-loadaproximadamente 160 veces y add-hook110 veces. Un init flojo es un buen init (IMO).
rasmus
@rasmus suena como una respuesta si tienes tiempo :) La distinción de cuántas veces se ejecuta el código es la principal a considerar, en mi opinión. (También es el único que se me ocurre ...)
Sean Allred
Para saber por qué es una mala idea cambiar las asociaciones de
tarsius el

Respuestas:

18

Un init perezoso es un buen init.

(IMO)

Cuándo usar with-eval-after-load

with-eval-after-loadse carga una vez cuando una determinada característica o archivo se carga por primera vez, por lo que un cambio de mapa de teclas va claramente dentro de uno de estos. No menos importante porque el mapa de teclas puede no ser conocido en el tiempo de inicio [intente algo como (define-key message-mode-map (kbd "C-c f") 'Footnote-add-footnote)en emacs -q]. Un gancho no es una buena solución aquí ya que vincula la función a una tecla cada vez que se inicia el gancho. Como notas de tarsius , puedes leer más sobre por qué no hacerlo local-set-keyen ganchos.

Finalmente, tenga en cuenta que with-eval-after-loadde GNU Emacs 24.4 es un envoltorio de 2 líneas eval-after-loaddonde bodyno es necesario citarlo.

Cuando usar ganchos

Los ganchos son una lista de funciones cargadas cada vez que se cumple un criterio, por ejemplo, se inicia un modo determinado. Un uso común de los ganchos es cargar modos menores, como flyspell-modeo hl-line-mode. Por ej (add-hook 'org-agenda-mode-hook 'hl-line-mode). Como señala Rémi , add-hookses inteligente y hará lo correcto incluso si la variable de gancho aún no se ha cargado. No obstante, tengo muchas cláusulas como las siguientes, que pueden ser insignificantes para aumentar la velocidad, pero da un sentido de organización y estructura de dependencia:

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

¿Por qué agregar al gancho después org-agenda? Como siempre, C-h v org-agenda-mode-hook C-jentrega. El gancho se define org-agenda.elcomo se muestra en *help*.

Cargando funciones adicionales with-eval-after-load

with-eval-after-loadTambién es importante para cargar funciones adicionales. Probablemente desee algo como (with-eval-after-load 'org (require 'org-inlinetask))cargar las tareas en línea de la organización. A ver por qué (find-library "org-inlinetask"). Dado que org-inlinetasks.eldirectamente (require 'org), todo lo bueno autoloadque sus amables encargados del mantenimiento de Emacs tuvieron mucho cuidado en proporcionar será "ignorado" y todo org.el(c)será cargado.

Pero, ¿qué defunpasa si su (personal) se requiere varios lugares? Si es realmente quisquilloso, puede poner los defuns en otro archivo load-pathy agregar autoloadcookies, o puede decirle a Emacs dónde encontrar la función con la autoloadfunción. Entonces algo como esto funcionaría:

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

O podrías simplemente require orgcomo a su vez tiraríacdlatex

Y, sinceramente, la defuncion personal no va a importar mucho para el tiempo de inicio la mayor parte del tiempo. Las 1150 líneas de defuns personales (84 defuns) en mi init.elagrega 0.02s sobre Emacs de vainilla.

Medición del tiempo de inicialización

Una manera fácil de aproximar el tiempo de inicialización es

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

(punto de referencia contra emacs -q.

Pero para obtener una aproximación más detallada de dónde se encuentran los cuellos de botella de inicialización, consulte Joe Schafer's esup.

Finalmente, el tiempo de carga no desaparece mágicamente. Solo lo está empujando hacia adelante (en la medida en que usa todas las funciones en cada sesión).

rasmus
fuente
1
No necesita poner add-hook en un con-eval-after-load, porque add-hook unirá la variable si aún no está allí.
Rémi
¡Tienes razón! Sin embargo, ¿podría haber ganancias de velocidad? [Intentaré actualizar la respuesta más tarde para reflejar esto]
rasmus
¿Qué pasa con defuns que luego me gustaría vincular a un enlace de gancho o clave? ¿Debería definir un defun fuera de él with-eval-after-loadsin perder las ventajas de la inicialización diferida?
jrbalderrama
5

Además de sus sugerencias eval-after-loady el uso de un gancho, permítanme sugerir use-package.el. Puedes hacer lo que necesites con

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

LaTeX no se cargará hasta después de que lo solicite.

Solo como una nota al margen: el uso cuidadoso de use-packageha reducido mis tiempos de inicio a menos de un segundo. (Solía ​​tomar alrededor de cuatro segundos).

Sean Allred
fuente
Gracias por su sugerencia. También contemplé usar use-package pero realmente quiero descubrir cómo hacerlo sin paquetes adicionales.
jrbalderrama
1
@jrbalderrama nota que use-packagese enviará con Emacs 25.
Sean Allred