Как запустить emacs с пользовательским каталогом user-emacs

58

Я работаю над нестандартной и небольшой конфигурацией Emacs, которой я хочу поделиться с друзьями в качестве git-репозитория, чтобы они могли использовать его в качестве основы для своих будущих конфигураций.

Для этого мне нужен какой-то способ проверить мою конфигурацию, и самое простое решение, которое я могу найти, это что-то вроде:

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

Но я не могу заставить его работать.

Любая помощь высоко ценится.

Маттиас Бенгтссон
источник
3
Я перечитал Приложение C Аргументы командной строки для вызова Emacs, но я не нашел простой опции командной строки для запуска Emacs с пользовательским .emacs.dкаталогом, если вы не изменили HOME, что мне кажется проблематичным. Люди предоставили обходные пути ниже, но для меня это звучит как очень разумный запрос возможностей для самого Emacs.
Дэвид Дж.
Смотрите также 49.4 Файл инициализации Emacs, который указывает на 49.4.4 Как Emacs находит ваш файл инициализации .
Дэвид Дж.
5
@DavidJames Вы правы: на самом деле в трекере ошибок Emacs есть пункт списка желаний .
ffevotte
2
Обновление: похоже, эта особенность не очень интересует разработчиков Emacs: запрос был помечен wontfixи закрыт в системе отслеживания ошибок.
ffevotte
@Francesco: я пробую динамический подход, который позволяет поместить пользовательский каталог Emacs вне "~". Может быть, вы попробуете.
Антонио

Ответы:

39

Основной подход, который я использую для этого, состоит в том, чтобы изменить $HOME, запустив:

env HOME=/path/to/dir emacs

Затем вы используете /path/to/dir/.emacs.d

Вы также можете использовать символические ссылки любых важных файлов или каталогов в этом фальшивом домашнем каталоге на настоящие, чтобы Emacs мог их видеть.

Phils
источник
2
Это работает отлично!
Маттиас Бенгтссон
8
Согласно Руководству по Emac - Приложение C Аргументы командной строки для вызова Emacs - Переменные среды - Общие переменные , HOME устанавливает «Расположение ваших файлов в дереве каталогов; используется для расширения имен файлов, начинающихся с тильды (~)». Изменение HOME звучит как рецепт для проблем позже, когда вы хотите быстро перемещаться или находить файлы из вашей реальной домашней папки.
Дэвид Дж.
2
Дэвид Джеймс: Да, это небольшое раздражение при таком подходе. Как уже упоминалось, вы захотите скопировать или символическую ссылку на вещи, которые вам нужно увидеть в Emacs в HOME, и если вы хотите посетить свой настоящий домашний каталог, вам нужно использовать абсолютный путь (или вы можете добавить к нему также символическую ссылку) ).
Фил
3
Вы также можете поэкспериментировать с восстановлением исходного HOME в Emacs во время инициализации. Я этого не пробовал, но, похоже, стоит разобраться.
Филс
1
@phils: Я попробовал то, что вы предлагаете.
Антонио
39

Способ, которым я использую для поддержки нескольких .emacs.dкаталогов параллельно, заключается в следующем.

  1. Emacs запускается так:

    alias emacs='emacs -q --load "/path/to/init.el"'
    
  2. Каждый init.elфайл начинается так, чтобы правильно настроить user-init-fileи user-emacs-directoryпеременные:

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

Я обнаружил, что это работает очень надежно в течение последних месяцев. Вот несколько замечаний:

  • он ломается emacs-init-time, который сообщает только время, необходимое для загрузки конфигурации системы по умолчанию, но не ваш собственный файл инициализации. Если вы заинтересованы в тестировании времени инициализации, вам придется сделать это по-другому (см., Например, Как измерить производительность кода elisp? ).

  • это не эквивалентно обычному запуску, и вам нужно позаботиться о нескольких конкретных моментах. В частности:

    • after-init-hookзапускается до загрузки файла инициализации.
    • *scratch*Буфер создается , прежде чем будет загружен файл инициализации. Вам придется явно изменить его режим (вместо использования initial-major-mode).
    • Вам нужно будет явно позвонить package-initialize; это не будет сделано автоматически
  • путь к init.elможет быть выбран произвольно; в частности, каталог, в котором init.elнаходится, не должен быть назван .emacs.d. Я использую это , чтобы иметь, например , .emacs.d.23наряду .emacs.d.24с тем , чтобы иметь возможность переключаться между разными версиями Emacs (система , я использую на работе проходимо устарела, и я не могу установить Emacs 24 на все машины , которые я использую).

  • этот рабочий процесс не требует изменения среды (и особенно HOMEenvvar), что может быть желательно, если вы запускаете программы из emacs, на которые может повлиять измененная среда).

ffevotte
источник
1
Это (в действительности) изменяет обычный порядок выполнения, если вы считаете, что --loadфайл ed является файлом инициализации. Для начала, мне кажется, что нормальная (по умолчанию) инициализация пакета не произойдет, и after-init-hookбудет выполняться до того, как (поддельный) файл инициализации будет оценен. Это вещи, которые вы можете обойти, конечно, но помните, что это не совсем то же самое, что Emacs, использующий указанный путь в качестве файла инициализации.
Филс
2
@ phils да, ты прав. Это действительно меняет обычный порядок выполнения и не эквивалентно использованию обычного файла инициализации. Я отредактировал свой ответ, чтобы отразить вашу точку зрения after-init-hook. Но я должен сказать, что, хотя я использую эту технику все время, я никогда не сталкивался с какой-либо проблемой after-init-hook(но я не использую ее явно, и, возможно, мне просто повезло, что используемые мной пакеты не полагаются на нее) , Что вы подразумеваете под "нормальной (по умолчанию) инициализацией пакета не произойдет"?
ffevotte
1
Я имею в виду, что command-lineне будет звонить package-initializeв этой ситуации. Вам нужно будет вызвать его вручную в поддельном файле инициализации.
Филс
1
@ phils спасибо. Я добавил это к ответу вместе с упоминанием о том, что о начальном основном режиме также нужно позаботиться конкретно.
ffevotte
Это сработало отлично .. Спасибо !!!
Страйкер
15

Вы можете символическую ссылку ~/.emacs.d , это то, что я делаю

  1. Старайтесь ~/.emacs.dориентировать мою конфигурацию emacs, т.е. все файлы конфигурации, связанные с emacs, должны находиться в этой папке

  2. Затем у меня есть ~/.emacs_configsпапка, в которой находятся все папки конфигурации (в основном это папка с init.elи остальной конфигурацией), так что моя личная папка конфигурации будет ~/emacs_configs/iqbal, прелюдия будет в~/emacs_configs/prelude

  3. Очень рано в моей личной конфигурации Emacs я установил user-emacs-directoryполный путь к моей конфигурации, используя следующую

    (setq user-emacs-directory (file-truename "~/.emacs.d/"))
    
  4. Затем, наконец, я символическую ссылку ~/.emacs.dна конфигурацию, которую я действительно хочу использовать, например. использовать мою конфигурацию я сделаю ln -s ~/emacs_configs/iqbal .emacs.d. Если вы хотите попробовать какую-либо конфигурацию, просто скопируйте папку конфигурации ~/emacs_configs/whatever_nameи измените символическую ссылку

Преимущество третьего шага состоит в том, что emacs, запущенный с моей личной конфигурацией, может работать без изменений, даже если я изменю .emacs.dсимволическую ссылку, пока emacs работает.

Другое преимущество заключается в HOMEтом, что не изменяются внешние программы, с которыми может потребоваться взаимодействие emacs.

Икбал Ансари
источник
1
Значит ли это, что мы можем настроить все отдельные конфиги emacs, (setq user-emacs-directory (file-truename "~/.emacs.d/"))чтобы они могли работать без изменений одновременно?
user1011471
1
В теории да, но на практике могут быть некоторые библиотеки, которые жестко кодируют путь, ~/.emacs.dа не используют user-emacs-directory. Я встречал хотя бы одну такую ​​библиотеку, но, к сожалению, не могу вспомнить название.
Икбал Ансари
7

Конфигурация, которая не изменяется HOMEили работает с символическими ссылками, может быть найдена в моем ответе https://emacs.stackexchange.com/a/20508/934 . С помощью этой конфигурации вы можете изменить user-emacs-directory, установив переменную окружения:

EMACS_USER_DIRECTORY=~/.emacsenv.d/spacemacs emacs

и это даже работает с демоном.

Уве Колоска
источник
5

Я нашел это аккуратное решение от EmacsWiki :

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

(не совсем с использованием пользовательского каталога, но работает хорошо, потому что, скорее всего, у вас все равно будет один входной файл)

phunehehe
источник
К вашему сведению, это излишне с комментарием @Francesco от 2 лет назад.
Брайс
3

Установите вашу переменную перед загрузкой вашего файла инициализации:

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

Затем в вашем init-файле (в данном случае ~/.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
источник
Очень элегантная, моя любимая система, так как все остается в области Emacs, как и должно быть. Спасибо.
GSL
1

Расширяя ответ от @phils, я сделал этот небольшой сценарий оболочки (называемый testrun.sh) для тестирования моей новой конфигурации emacs. Это может иметь смысл делать и в других случаях (например, при тестировании изменений в вашем init.el, которые могут нарушить работу 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
Маттиас Бенгтссон
источник
1

Вот небольшой скрипт, основанный на ответе и комментарии @ Phil'а об изменении HOMEпеременной окружения и его восстановлении в 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
источник
1

Если в этом случае используется один каталог конфигурации emacs «.emacs.d» для всех пользователей компьютера с Linux, то это решение https://emacs.stackexchange.com/a/4258/5488 будет работать в большинстве случаев, но в некоторых случаи emacs пытается записать временные файлы в каталог user-emacs (например, файл .ido.last). В таких случаях, если общий каталог конфигурации имеет разрешение на запись для всех пользователей, он будет работать, но может оказаться нежелательным решением, поскольку каждый системный пользователь может не захотеть использовать один и тот же каталог для хранения временных файлов. В таком случае следующее решение будет лучшим вариантом.

Общий общий конфигурационный файл .emacs.d / init.el должен начинаться с

;; 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)

Сделайте, чтобы общий конфиг .emacs.d имел права на чтение для всех пользователей (не нужно иметь права на запись)

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

У каждого пользователя будет свой собственный каталог «~ / .emacs.d /», но он используется только для сохранения временных файлов, но пакеты и другие конфигурации загружаются из общего каталога конфигурации.

Talespin_Kit
источник