Cómo iniciar emacs con un directorio de usuario-emacs personalizado

58

Estoy trabajando en una configuración de Emacs pequeña y personalizada que quiero compartir con algunos amigos como un repositorio git para que puedan usar como línea de base para sus propias configuraciones futuras.

Para esto necesito alguna forma de probar mi configuración y la solución más simple que puedo encontrar es algo como:

$ emacs --eval "(setq user-emacs-directory \"~/Code/my_custom_emacs.d/\")"

Pero parece que no puedo hacer que funcione.

Cualquier ayuda muy apreciada.

Mattias Bengtsson
fuente
3
Leí los argumentos de la línea de comandos del Apéndice C para la invocación de Emacs, pero no encontré una opción simple de línea de comandos para iniciar Emacs con un .emacs.ddirectorio personalizado a menos que cambie HOME, lo que me parece problemático. La gente ha proporcionado soluciones a continuación, pero, para mí, esto parece una solicitud de función muy razonable para el propio Emacs.
David J.
55
@DavidJames Tienes razón: en realidad hay un elemento de la lista de deseos sobre esto en el rastreador de errores de Emacs.
ffevotte
2
Actualización: parece que esta característica no interesa tanto a los desarrolladores de Emacs: la solicitud ha sido etiquetada wontfixy cerrada en el rastreador de errores.
ffevotte
@Francesco: pruebo un enfoque dinámico que permite colocar el directorio de Emacs del usuario fuera de "~". Puede ser que lo intentes.
antonio

Respuestas:

39

El enfoque básico que uso para esto es modificar $HOME, ejecutando:

env HOME=/path/to/dir emacs

Entonces usas /path/to/dir/.emacs.d

Es posible que también desee vincular cualquier archivo o directorio de importancia en este directorio de inicio falso a los reales, para que Emacs los vea.

phils
fuente
2
Esto funciona perfecto!
Mattias Bengtsson
8
De acuerdo con el Manual de Emac - Apéndice C Argumentos de la línea de comandos para la invocación de Emacs - Variables de entorno - Variables generales , HOME establece "La ubicación de sus archivos en el árbol de directorios; se utiliza para la expansión de nombres de archivos que comienzan con una tilde (~)". Cambiar INICIO suena como una receta para problemas más tarde cuando desea navegar rápidamente o encontrar archivos de su carpeta de inicio real .
David J.
2
David James: Sí, eso es una molestia menor con este enfoque. Como se mencionó, querrá copiar o vincular cosas que necesita que vea Emacs en INICIO, y si desea visitar su directorio de inicio real, entonces debe usar la ruta absoluta (o también puede agregar un enlace simbólico a eso) )
phils
3
También puede experimentar con la restauración del HOME original dentro de Emacs durante la inicialización. No lo he intentado, pero parece que vale la pena investigarlo.
phils
1
@phils: probé lo que sugieres.
antonio
39

La forma en que uso para mantener varios .emacs.ddirectorios en paralelo es la siguiente.

  1. emacs se inicia así:

    alias emacs='emacs -q --load "/path/to/init.el"'
    
  2. Cada init.elarchivo comienza así, para configurar correctamente las variables user-init-filey user-emacs-directory:

    (setq user-init-file (or load-file-name (buffer-file-name)))
    (setq user-emacs-directory (file-name-directory user-init-file))
    

He encontrado que esto funciona de manera muy confiable en los últimos meses. Aquí hay algunos comentarios:

  • se rompe emacs-init-time, que solo informa el tiempo necesario para cargar la configuración predeterminada del sistema, pero no su propio archivo de inicio. Si está interesado en comparar su tiempo de inicio, tendrá que hacerlo de otra manera (consulte, por ejemplo, ¿Cómo mido el rendimiento del código elisp? ).

  • no es equivalente a un inicio normal y deberá ocuparse de algunos puntos específicos. En particular:

    • after-init-hookse ejecuta antes cargar el archivo init.
    • El *scratch*búfer se crea antes de cargar el archivo de inicio. Tendrás que cambiar su modo explícitamente (en lugar de usarinitial-major-mode ).
    • Deberá llamar explícitamente package-initialize; no se hará automáticamente
  • el camino a init.elpuede ser elegido arbitrariamente; en particular, el directorio en el que init.elreside no tiene que ser nombrado .emacs.d. Utilizo esto para tener, por ejemplo, al .emacs.d.23lado .emacs.d.24para poder cambiar entre diferentes versiones de emacs (el sistema que estoy usando en el trabajo está desactualizado y no puedo instalar emacs 24 en todas las máquinas que uso).

  • Este flujo de trabajo no requiere modificar el entorno (y especialmente el HOMEentorno), lo que puede ser deseable si ejecuta programas desde dentro de emacs, que podrían verse afectados por el entorno modificado).

ffevotte
fuente
1
Esto (en efecto) altera el orden de ejecución normal, si está considerando que el --loadarchivo ed es el archivo init. Para empezar, me parece que la inicialización del paquete normal (predeterminado) no se producirá y after-init-hookse ejecutará antes de que se evalúe el archivo de inicio (falso). Estas son cosas que puede solucionar, sin duda, pero tenga en cuenta que no es exactamente lo mismo que Emacs que usa la ruta especificada como el archivo de inicio.
phils
2
@phils sí, tienes razón. De hecho, esto cambia el orden de ejecución normal y no es equivalente a usar un archivo de inicio normal. Edité mi respuesta para reflejar tu punto after-init-hook. Pero tengo que decir que aunque uso esta técnica todo el tiempo, nunca tuve ningún problema after-init-hook(pero no la uso explícitamente, y tal vez soy afortunado de que los paquetes que uso no confíen en ella) . ¿Qué quiere decir con "la inicialización normal (predeterminada) del paquete no ocurrirá"?
ffevotte
1
Quiero decir que command-lineeso no llamará package-initializeen esa situación. Debería llamarlo manualmente en el archivo de inicio falso.
phils
1
@phils gracias. Agregué esto a la respuesta, junto con una mención de que el modo principal inicial también debe ser atendido específicamente.
ffevotte
Esto funcionó perfectamente .. ¡Gracias!
Stryker
15

Puedes vincular ~/.emacs.d , esto es lo que hago

  1. Intentar mantener mi configuración de emacs ~/.emacs.dorientada, es decir, todos los archivos de configuración relacionados con emacs deberían vivir en esa carpeta

  2. Luego tengo una ~/.emacs_configscarpeta donde viven todas las carpetas de configuración (básicamente una carpeta con una init.ely el resto de la configuración), por lo que mi carpeta de configuración personal será ~/emacs_configs/iqbal, habrá una distribución previa~/emacs_configs/prelude

  3. Muy temprano en mi configuración personal de emacs configuré user-emacs-directoryla ruta completa a mi configuración usando lo siguiente

    (setq user-emacs-directory (file-truename "~/.emacs.d/"))
    
  4. Luego, finalmente, hago un enlace simbólico ~/.emacs.da la configuración que realmente quiero usar, por ejemplo. para usar mi configuración lo haré ln -s ~/emacs_configs/iqbal .emacs.d. Si desea probar alguna configuración, simplemente copie la carpeta de configuración ~/emacs_configs/whatever_namey cambie el enlace simbólico

La ventaja del tercer paso es que emacs comenzó con mi configuración personal y no se ve afectada incluso si cambio el .emacs.denlace simbólico mientras emacs se está ejecutando.

Otra ventaja es que HOMEno se modifican los programas externos con los que emacs podría necesitar interactuar y no se ven afectados

Iqbal Ansari
fuente
1
¿Esto significa que podemos ajustar todas las configuraciones de emacs por separado (setq user-emacs-directory (file-truename "~/.emacs.d/"))para que todas puedan ejecutarse sin verse afectadas simultáneamente?
user1011471
1
En teoría sí, pero en la práctica puede haber algunas bibliotecas que codifiquen el camino en ~/.emacs.dlugar de usar user-emacs-directory. He encontrado al menos una de esas bibliotecas, pero desafortunadamente no puedo recordar el nombre.
Iqbal Ansari
7

Puede encontrar una configuración que no cambia HOMEo que funciona con enlaces simbólicos en mi respuesta https://emacs.stackexchange.com/a/20508/934 . Con esta configuración, puede cambiar la user-emacs-directoryconfiguración de una variable de entorno:

EMACS_USER_DIRECTORY=~/.emacsenv.d/spacemacs emacs

y esto incluso funciona con el demonio.

Uwe Koloska
fuente
5

Encontré esta solución ordenada de EmacsWiki :

emacs -q -l ~/my-init-file.el

(no utiliza exactamente un directorio personalizado, pero funciona bien porque es muy probable que tenga un solo archivo de entrada de todos modos)

phunehehe
fuente
Para su información, esto es redundante con un comentario de @Francesco de hace 2 años.
Bryce
3

Establezca su var antes de cargar su archivo init:

emacs -q --eval '(setq alt-conf t)' --load ~/.emacs

Luego, en su archivo init (en este caso ~/.emacs):

(defvar alt-conf nil)

(if alt-conf
    (let ((default-directory "~/src/elisp-test/"))
      (normal-top-level-add-subdirs-to-load-path)
      (various-alt-config-stuff)
      (message "Alternate conf"))
  (message "Regular conf"))
yPhil
fuente
Muy elegante, mi sistema favorito, ya que todo permanece en el dominio de Emacs, como debería. Gracias.
gsl
1

Ampliando la respuesta de @phils, hice este pequeño script de shell (llamado testrun.sh) para probar mi nueva configuración de emacs. Esto también podría tener sentido en otros casos (por ejemplo, cuando se prueban cambios en su init.el que pueden dañar emacs).

#!/bin/bash

cd $(dirname "${BASH_SOURCE[0]}")
[ -d .testrun ] || mkdir .testrun
cd .testrun
[ -h .emacs.d ] || ln -s .. .emacs.d

env HOME=`pwd` emacs

rm .emacs.d
cd ..
rm -rf .testrun
Mattias Bengtsson
fuente
1

Aquí hay un pequeño script basado en la respuesta y el comentario de @ Phil sobre cómo cambiar la HOMEvariable de entorno y luego restaurarla dentro de Emacs.

#!/bin/bash

# Use it like this:
#   /path/to/this/script  EMACS_USER_DIRECTORY  [OTHER EMACS ARGS]

# You can never be too careful
set -e

# First arg = emacs user directory
#   (get a canonical, absolute path)
EMACS_USER_DIRECTORY=$(readlink -f "$1")
shift
if [ ! -d "${EMACS_USER_DIRECTORY}" ]; then
    echo "Non-existent directory: '${EMACS_USER_DIRECTORY}'"
    exit 1
fi

# Bootstrap directory
BOOTSTRAP=$(mktemp --directory --tmpdir .emacs-bootstrap.XXXXXX)
mkdir "${BOOTSTRAP}/.emacs.d"

# Bootstrap init file
cat >"${BOOTSTRAP}/.emacs.d/init.el" <<EOF
  ;; # Correctly set-up emacs-user-directory
  (setq user-emacs-directory "${EMACS_USER_DIRECTORY}/")
  (setq user-init-file (concat user-emacs-directory "init.el"))

  ;; # Reset the HOME environment variable
  (setenv "HOME" "${HOME}")

  ;; # Load the real init file and clean-up afterwards
  (unwind-protect (load user-init-file)
    (delete-directory "${BOOTSTRAP}" :recursive))
EOF

# Forward remaining arguments to emacs
exec env HOME="${BOOTSTRAP}" emacs "$@"
ffevotte
fuente
1

Si el caso de uso es compartir el directorio ".emacs.d" de configuración de emacs con todos los usuarios de una máquina Linux, entonces esta solución https://emacs.stackexchange.com/a/4258/5488 funcionaría en la mayoría de los casos, pero en algunos casos emacs intenta escribir archivos temporales en el directorio de usuario-emacs (como el archivo .ido.last). En tales casos, si el directorio de configuración compartido tiene permiso de escritura para todos los usuarios, funcionará, pero puede que no sea la solución deseada, ya que cada usuario del sistema puede no querer compartir el mismo directorio para almacenar archivos temporales. En tal caso, la siguiente solución será una mejor opción.

El archivo de configuración común compartido .emacs.d / init.el debería comenzar con

;; should come before calling package-initialize as it will populate
;; everything under common config "~/.emacs.d/elpa"
(setq user-init-file (or load-file-name (buffer-file-name)))
(setq package-user-dir (concat (file-name-directory user-init-file) "elpa"))

(package-initialize)

Haga que la configuración compartida .emacs.d tenga permiso de lectura para todos los usuarios (no necesita tener permisos de escritura)

another_user $ emacs -q --load /path/to/shared/config/.emacs.d/init.el

Cada usuario tendrá su propio directorio "~ / .emacs.d /" pero solo se usará para guardar los archivos temporales, pero los paquetes y otras configuraciones se cargarán desde el directorio de configuración compartido.

Talespin_Kit
fuente