Как сделать конфигурацию emacs модульной?

Я решил переписать свой .emacs с нуля, и я хочу настроить что-то модульное, чтобы избежать ужасного файла init.el 1k + LoC ...

Я думаю, что есть некоторые основные проблемы, которые необходимо решить при каждой конфигурации:

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

Пока я все еще пытаюсь продумать структуру, я ищу некоторые советы о том, как этого добиться.
Я просмотрел некоторые .emacs на github и тому подобное, и, похоже, есть разные подходы, и нет предпочтительного способа пойти с этим, что немного сбивает с толку.
Мне было бы интересно прочитать некоторые идеи о том, как структурировать такую ​​установку, и особенно некоторый связанный код elisp.


edit: Я был в курсе вещей, и у него еще не было много времени, чтобы поиграть с этим. Попробую предложенные методы через несколько дней, и посмотрим, что лучше, а пока спасибо за все рекомендации!


edit2: я использовал грамотный файл инициализации с режимом org, и это просто потрясающе!
Я еще не настроил конкретный механизм загрузки, я использовал этот код, чтобы рекурсивно загружать мой каталог elisp, а затем требовать или независимо от того, что сказано в инструкциях по установке.

  (if (fboundp 'normal-top-level-add-subdirs-to-load-path)
  (let* ((my-lisp-dir "~/.emacs.d/elisp/")
  (default-directory my-lisp-dir))
  (setq load-path (cons my-lisp-dir load-path))
  (normal-top-level-add-subdirs-to-load-path)))

Мне все еще нужно отполировать это, возможно, используя автозагрузку и некоторые трюки с перекомпиляцией байтов, если они были изменены; хотелось бы услышать предложения по этому поводу.


person julien    schedule 16.01.2010    source источник


Ответы (10)


Мой файл .emacs загружает ~ / .emacs.d / init.el, который определяет следующие функции, написанные сначала для XEmacs, но уже достаточно хорошо работающие для Emacs в наши дни:

(defconst user-init-dir
  (cond ((boundp 'user-emacs-directory)
         user-emacs-directory)
        ((boundp 'user-init-directory)
         user-init-directory)
        (t "~/.emacs.d/")))


(defun load-user-file (file)
  (interactive "f")
  "Load a file in current user's configuration directory"
  (load-file (expand-file-name file user-init-dir)))

Затем идет оставшаяся часть файла и загружает множество отдельных файлов с такими формами:

(load-user-file "personal.el")

Мой текущий набор файлов выглядит следующим образом:

  • personal.el
  • platform.el
  • cygwin.el
  • variables.el
  • paths.el
  • mail-news.el
  • misc-funcs.el
  • bbdb.el
  • calendar.el
  • gnus-funcs.el
  • c-and-java.el
  • lisp.el
  • clojure.el
  • go.el
  • markdown.el
  • sgml-xml.el
  • tex.el
  • орфография.el
  • org.el
  • packages.el
  • fonts.el
  • color-theme.el
  • frame.el
  • server.el
  • keys.el
  • aquamacs.el

Некоторые из них гораздо более конкретны по своим намерениям, чем другие, как следует из названий. Чем более детализированы файлы, тем проще отключить кластер форм при переустановке пакета или библиотеки. Это особенно полезно при «переходе» в новую систему, когда вы перетаскиваете файлы конфигурации, но еще не установили все поддерживающие пакеты.

person seh    schedule 16.01.2010
comment
Как раз то, к чему я стремился. Хороший. - person dmckee --- ex-moderator kitten; 17.01.2010
comment
Вот почему я обычно храню вспомогательные пакеты где-нибудь в папке .emacs. - person klynch; 19.08.2010
comment
Разве имя файла не противоречит реальному пакету? Или вы загружаете полный путь вместо простого запроса? - person xwl; 11.06.2014
comment
Обратите внимание на вызов load-file, показанный выше: он предоставляет путь, сформированный из базового имени файла в user-init-dir. То есть вместо того, чтобы пытаться загрузить первый файл с именем markdown.el из load-path, он специально загрузит файл /home/myusername/.emacs.d/markdown.el. - person seh; 11.06.2014
comment
Сегодня я обнаружил, что Аарон Бедра умело использует org-mode, чтобы определить свою конфигурацию как грамотную программу: github.com/abedra/emacs.d. См. Экспортированную документацию в формате org-as-HTML здесь: aaronbedra.com/emacs.d. Меня вдохновляет попытаться изменить свой подход к конфигурации, чтобы использовать один такой файл, хотя я потеряю более точное отслеживание контроля версий, когда изменю всего несколько связанных вещей в одном из файлов, перечисленных выше. Стоит ли возможность писать документацию, чтобы перевернуть обычное расположение документации внутри кода? - person seh; 15.01.2015

Чтобы разделить настройки на разные файлы, вы можете использовать initsplit.el. Кроме того, в вики есть страница с модульным макетом .emacs.

person Joe Casadonte    schedule 17.01.2010

Вы можете сделать (require 'foo), и это загрузит первый elisp "foo.el", найденный в вашем пути загрузки, или (require 'foo "/home/user/experimental/foo.el") для чего-то вне вашего пути загрузки. Он сообщит об ошибке, если "foo.el" не содержит выражения (provide 'foo). В извращенной ситуации вы можете сделать (require 'foo "bar.el"), и это будет работать, пока "bar.el" имеет предложение (provide 'foo).

person Justin Smith    schedule 16.01.2010

Что плохого в использовании load-file?

Некоторые дополнительные биты, которые могут оказаться полезными, включают

  • file-exists-p
  • file-expand-wildcards

Используйте C-h f <function>, чтобы получить помощь, и вы можете найти Введение в программирование в Emacs Lisp полезно (или загрузите PDF-файл)

person dmckee --- ex-moderator kitten    schedule 16.01.2010

Если вы хотите разделить свой custom-set-variables, но хотите что-то более легкое, чем initsplit.el, попробуйте следующее:

(defmacro custom-set-variable (var value)
  "Call `custom-set-variables' with a warning shown
when customizing using the customize GUI.

XXX: does not support setting the optional NOW and
REQUEST (dependency) fields."
  (custom-set-variables
    ;; `load-file-name' is set by `load-file':
    ;; http://stackoverflow.com/a/1971376/470844
    `(,var ,value nil nil
      ,(format "!!! CAREFUL: CUSTOM-SET IN %s !!!" load-file-name))))

Теперь поместите модули конфигурации в отдельные файлы и загрузите их с load-file в свой ~/.emacs, как предлагали другие. В каждом модуле конфигурации используйте

(custom-set-variable var value)

вместо

(custom-set-variables '(var value))

or

(setq-default var value)

при установке переменных, управляемых с помощью customize. Затем, если вам когда-либо понадобится настроить переменную с помощью интерфейса настройки, вы увидите предупреждение о том, в каком файле следует сохранить настройку:

"!!! CAREFUL: CUSTOM-SET IN <path to module file> !!!"

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

Обсуждение проблем с наивным использованием нескольких custom-set-variables вызовов: http://www.dotemacs.de/custbuffer.html < / а>

Изменить: ответ на вопросы Алана

Проблема, которую решает макрос custom-set-variable выше

Интерфейс настройки в Emacs сохраняет все переменные пользовательского набора в вашем ~/.emacs всякий раз, когда вы редактируете любую переменную пользовательского набора. Если вы модулируете свои настраиваемые переменные, распределяя их по нескольким файлам, тогда вам нужно понимать, когда emacs вставляет повторяющиеся настройки в ваш .emacs и удаляет их. Приведенный выше макрос custom-set-variable поможет вам в этом.

Реальный пример из моих файлов конфигурации

Я настраиваю переменные, связанные с пробелами, в файле ~/.emacs.d/extensions/whitespace.el, который загружается моим _ 16_. Например, я установил свой _ 17_ примерно так:

(nc:custom-set-variable search-whitespace-regexp "[ \t\r\n]+")

Теперь происходят две вещи. Во-первых, когда я сталкиваюсь с этой переменной в интерфейсе настройки, я получаю предупреждение:

Предупреждение в диалоговом окне настройки Emacs

Во-вторых, если я редактирую какие-либо переменные с помощью интерфейса настройки, мой ~/.emacs делает очень очевидным, что я затенял некоторые определения. Например, после изменения search-whitespace-regexp и global-whitespace-mode в интерфейсе настройки я получаю:

$ svn di --diff-cmd "diff" -x "-U0" ~/v/conf
Index: /home/collins/v/conf/dot.emacs
===================================================================
--- /home/collins/v/conf/dot.emacs  (revision 267)
+++ /home/collins/v/conf/dot.emacs  (working copy)
@@ -55,0 +56 @@
+ '(agda2-include-dirs (\` ("." (\, (file-truename "~/local/opt/agda-std-lib/src")))) nil nil "!!! CAREFUL: CUSTOM-SET IN /home/collins/.emacs.d/extensions/agda.el !!!")
@@ -58,0 +60,3 @@
+ '(global-whitespace-mode t)
+ '(indent-tabs-mode nil nil nil "!!! CAREFUL: CUSTOM-SET IN /home/collins/.emacs.d/extensions/whitespace.el !!!")
+ '(indicate-empty-lines t nil nil "!!! CAREFUL: CUSTOM-SET IN /home/collins/.emacs.d/extensions/whitespace.el !!!")
@@ -72,0 +77 @@
+ '(search-whitespace-regexp "" nil nil "!!! CAREFUL: CUSTOM-SET IN /home/collins/.emacs.d/extensions/whitespace.el !!!")
@@ -74,0 +80 @@
+ '(tab-width 2 nil nil "!!! CAREFUL: CUSTOM-SET IN /home/collins/.emacs.d/extensions/whitespace.el !!!")

Макрос не помогает мне вспомнить, что я изменил search-whitespace-regexp, только то, что он уже установлен где-то еще, но он помогает мне узнать, какие настройки переменных я должен удалить из моего ~/.emacs (все с предупреждениями), а какие я должен оставить в my ~/.emacs, или переместить в другие отдельные файлы (все без предупреждений).

Вывод

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

person ntc2    schedule 10.06.2012
comment
Так какой же смысл в интерфейсе настройки, если у вас есть этот код? Вы должны сохранить изменения через интерфейс, а затем перенести полученные изменения из файла .emacs в свой собственный файл, удалив их из файла .emacs? - person Alan; 02.03.2013
comment
Кроме того, я полагаю, вы говорите, что собираетесь изменить что-то вроде этого: (custom-set-variables '(column-number-mode t)' (display-time-mode t)) на это: (custom- установить-переменную номер-столбца-режим t) (режим-времени-отображения-времени-отображения нестандартной-переменной-столбца t) Это верно? - person Alan; 02.03.2013
comment
@Alan: см. Новые примеры выше. Основное использование - помочь вам избежать случайной установки переменных дважды в двух разных файлах при использовании интерфейса настройки. Вы можете вносить изменения через интерфейс или непосредственно в файлы конфигурации, но на практике я считаю интерфейс более удобным, например когда я не знаю, что называется переменная, которую я изменяю, чтобы изменить, и поэтому я просматриваю настройки. И да, я использую его именно так, как вы предлагаете. - person ntc2; 03.03.2013
comment
Спасибо за очень ясное и ясное объяснение. Теперь я понимаю, как это работает. - person Alan; 04.03.2013
comment
Ключевым моментом является изменение параметра any с помощью пользовательского интерфейса настройки, в результате чего все программно установленные настраиваемые параметры (с custom-set-variables) дублируются в назначенном настраиваемом файле - ключевой момент. возможно, слишком подробно здесь, пройдя пошаговую демонстрацию разницы setq и custom-set-variables, если это помогает людям: emacs.stackexchange.com/questions/55018/ - person Phil; 23.02.2020

Взгляните на отличный стартовый комплект emacs, который очень хорошо организован и также включает ELPA. пакеты. Я использовал эту структуру как источник вдохновения для моей более простой настройки.

person justinhj    schedule 17.01.2010

Спасибо @JoeCasadonte за упоминание страницы EmacsWiki. Поскольку я использую Debian и Ubuntu, этот конкретный фрагмент из него работал очень хорошо (для вставки в .emacs.d / init.el):

(setq dotfiles-dir (file-name-directory (or load-file-name (buffer-file-name))))

(let ((user-site-start-dir (concat dotfiles-dir "/site-start.d")))
    (debian-run-directories user-site-start-dir))

Затем мне просто нужно поместить мои файлы .el в ~ / .emacs.d / site-start.d (например, ~/.emacs.d/site-start.d/50cedet.el), и все они загрузятся автоматически.

person Paulo    schedule 28.12.2014

Вот библиотека, которая позволяет вам устанавливать новые модули, просто сохраняя их в назначенном каталоге. Его можно загрузить и установить с http://github.com/tripleee/my-site-start/

    ;;; my-site-start.el --- set up personal .emacs.d/site-start.d/
    ;;
    ;; Copyright (C) era eriksson <http://www.iki.fi/~era/> 2008-2009
    ;; License: GPL v2
    ;; Version: see `my-site-start-version' below
    ;;
    ;;; Commentary:
    ;;
    ;; The purpose of my-site-start is to simplify maintenance of user libraries.
    ;; Instead of indefinitely tweaking your .emacs, just create a site-start.d
    ;; directory and add symlinks to the libraries you want to load into Emacs.

Эта архитектура налагает некоторые соглашения, которые могут вам понравиться, а могут и не понравиться. См. Остальную часть комментария в верхней части файла, чтобы получить полную информацию.

Я являюсь автором этого кода и ценю любые отзывы (хотя и не напрямую через этот общедоступный форум).

person tripleee    schedule 06.08.2011

Я сделал для каждой вещи X, которую я мог бы захотеть использовать, создал файл с именем configure-X и поместил соответствующий require в .emacs. Затем эту функцию можно удалить, закомментировав одну строку.

Например, чтобы выбрать самый простой (если он плохо назван), у меня есть configure-picture-and-artist-mode.el. Этот файл очень прост:

(global-set-key (kbd "C-M-P")
                'picture-mode)

(provide 'configure-picture-and-artist-mode)

И в .emacs:

(require 'configure-picture-and-artist-mode)

Разобравшись с этим, у меня нет ничего в моем .emacs, кроме большого списка require и нескольких изменений в load-path, данный пакет можно довольно легко удалить, и вся конфигурация для каждого пакета находится в одном месте.

(У меня также есть универсальный файл .el, который я использую для хранения вещей, у которых нет очевидного дома (мои глобальные привязки клавиш, вспомогательные функции и т. Д.), Но в идеале я хочу держаться подальше от .emacs. Это bit не очень модульный и может вводить неявные зависимости для пакетов, которые моя схема должна сделать легко выгружаемыми, но на практике это не кажется большой проблемой.)

person Community    schedule 16.01.2010
comment
Не могли бы вы рассказать больше о том, как вы уговариваете «требовать» найти файлы, содержащие формы «предоставить»? Указываете ли вы имя файла для второго аргумента require? - person seh; 17.01.2010
comment
@seh вам не нужно, пока «предоставленный» файл находится в пути загрузки. У меня может быть файл foo.el, в котором у меня есть (предоставить 'foo) или (предоставить' foobar) или что-то еще, тогда в моем файле инициализации я могу сказать (требовать 'foo) (или foobar или что-то еще), и он загрузить файл. - person vedang; 17.01.2010
comment
Я назвал каждый файл в честь предоставленного символа, убедился, что содержащая его папка находится в пути загрузки ... и это просто сработало. (Я не уверен в подробностях этого механизма, но подозреваю, что require просто знает, чтобы попытаться загрузить файл, названный в честь символа, если ни один из загруженных файлов уже не предоставил запрошенный символ. В любом случае это именно то, что я Я заметил, что другие файлы elisp работают, поэтому скопировал его.) - person ; 17.01.2010
comment
Спасибо. Я собираюсь поэкспериментировать с настройкой этого в моих собственных файлах конфигурации сегодня. - person seh; 17.01.2010
comment
См. C-h f require RET для получения подробной информации о том, как работает этот механизм. Также обратите внимание на аргумент NOERROR, который упрощает условное поведение в зависимости от того, может ли быть загружена рассматриваемая функция. - person phils; 03.03.2013

Вы можете попробовать init-loader.el, это загрузчик конфигурационных файлов. init-loader.el загружает файлы конфигурации из указанного каталога. Это позволяет вам классифицировать ваши конфигурации и разделять их на несколько файлов.

Для получения дополнительной информации посетите репозиторий init-loader на GitHub

person Juanito Fatas    schedule 05.04.2013