Как мне исправить пакет Emacs?


16

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

  1. Я хотел бы установить отдельную ветвь пакета и иметь возможность переключаться между ним и стабильной веткой по прихоти, при этом перекомпиляция выполняется автоматически, когда это необходимо, но package.el, похоже, не предлагает прямого способа сделать это. Этот ответ на emacs-SE сообщает нам, что «если установлено несколько копий пакета, то будет загружена первая», так что я думаю, что можно вручную связываться, load-pathно это не кажется надежным. Каков стандартный способ выбора конкретной версии пакета среди установленных?

  2. Даже если мне удастся открыть несколько веток в Emacs, для значительных изменений мне нужно убедиться, что непатченная ветвь «выгружена» и ее побочные эффекты изолированы. unload-featureПравильно ли это обрабатывается, или, может быть, у него есть свои особенности, о которых должен знать каждый тестер версий с несколькими версиями?

  3. Как мне установить и протестировать локальную версию? Кажется, что ответ зависит от того, является ли пакет простым (= один файл) или многофайловым. EmacsWiki говорит о многофайловых пакетах: « MELPA создает пакеты для вас ». Я сомневаюсь, что мне приходится (или должен) разговаривать с MELPA каждый раз, когда я меняю defunформу в многофайловом пакете, но вопрос остается. По крайней мере, мне нужно сообщить менеджеру пакетов о локальной версии, и если да, то как мне это сделать?

  4. Какие имена следует назначать локальным версиям пакетов? Предположим, я хочу работать над несколькими функциями или ошибками одновременно, что означает наличие нескольких веток. Emacs не позволит называть версии в описательной форме (по аналогии с 20170117.666-somebugorfeature). Я думаю, я мог бы переименовать сам пакет, суффикс на ветку, но опять же, как и ручная работа load-pathв Q1, это отвратительный взлом, поэтому я не буду пробовать его с чем-то, что намереваюсь отправить в апстрим, если это не является общепринятой практикой ,

Вопросы, вероятно, наивны, так как я никогда не писал патч и не применял патч с git или подобным vcs. Однако для многих пользователей Emacs исправление пакета Emacs может стать их первым (или, возможно, единственным) приложением для социального программирования, поэтому я считаю, что ответы на этот вопрос будут по-прежнему полезны.

Ответы:


7

Чтобы добавить немного другой рабочий процесс для загрузки разных версий пакетов, вот пара вариантов того, что я делаю, оба из которых используют, load-pathчтобы контролировать, какую версию я использую (изменение названия пакета - плохая идея если есть зависимости). У меня есть текущая версия установленной в «хороший-пакет» , ~/.emacs.d/elpaиспользуя M-x package-installи клонировать пакет репо ~/src/nice-packageс git clone ....

С использованием пакета

В init.el у меня есть

(use-package nice-package
  :load-path "~/src/nice-package"
  ...)

Если :load-pathстрока не закомментирована, будет использоваться git-версия пакета. Комментирование этой строки и перезагрузка emacs использует версию elpa.

Похоже без использования пакета

В init.el,

(add-to-list 'load-path "~/src/nice-package")
(require 'nice-package)
...

Теперь сделайте то же самое с комментариями в первой строке.

С помощью emacs -L

Это та же идея, но манипулирование load-pathиз командной строки. Вы можете загрузить экземпляр emacs с помощью git-версии пакета с

emacs -L ~/src/nice-package

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

Разные комментарии

  1. Используйте M-x eval-bufferпосле редактирования файла пакета, чтобы загрузить новые определения, которые вы создали.
  2. Проверка того, что говорит компилятор, также M-x emacs-lisp-byte-compileудобна

Я использую emacs -Lподход для загрузки локальной версии пакета, который я также установил глобально, используя Cask. Одна вещь, которая меня оттолкнула, это то, что запуск <package>-versionвсегда возвращает глобально установленную версию, даже когда я фактически запускаю локальную модифицированную версию. Оказывается, это потому, <package>-versionчто версия для этого пакета получает версию packages.el.
ntc2

3

Хороший вопрос! Ответ заключается в том, что до сих пор не было хорошего ответа, поскольку ни один из существующих менеджеров пакетов не был разработан для этого варианта использования (кроме Borg , но Borg не пытается обрабатывать другие общие операции управления пакетами, такие как обработка зависимостей) .

Но теперь есть straight.elменеджер пакетов следующего поколения для Emacs, который максимально полно решает эту проблему. Отказ от ответственности: я написал straight.el!

После вставки фрагмента начальной загрузки установить пакет так же просто, как

(straight-use-package 'magit)

Это позволит клонировать Git-репозиторий для Magit, собрать пакет, поместив ссылки на его файлы в отдельный каталог, выполнить байтовую компиляцию, сгенерировать и оценить автозагрузки и load-pathправильно настроить их . Конечно, если пакет уже клонирован и собран, ничего не происходит, и ваше время инициализации не страдает.

Как вы вносите изменения в Magit? Это тривиально! Просто используйте M-x find-functionили, M-x find-libraryчтобы перейти к исходному коду, и взломать! Вы можете оценить свои изменения, чтобы протестировать их в режиме реального времени, как это обычно делается при разработке Emacs Lisp, и когда вы перезапустите Emacs, пакет будет автоматически перестроен, перекомпилирован и т. Д. Это полностью автоматический и надежный.

Когда вы удовлетворены своими изменениями, просто подтвердите, нажмите и сделайте запрос на извлечение. Вы имеете полный контроль над вашими местными пакетами. Но ваша конфигурация все еще может быть воспроизводима на 100%, потому что вы можете попросить straight.elсоздать файл блокировки, который сохранит ревизии Git всех ваших пакетов, включая straight.elсебя, MELPA и так далее.

straight.elМожно установить любой пакет из MELPA, GNU ELPA или EmacsMirror. Но он также имеет очень гибкий рецепт DSL, который позволяет устанавливать его из любого места, а также настраивать способ сборки пакета. Вот пример, который показывает некоторые параметры:

(straight-use-package
 '(magit :type git 
         :files ("lisp/magit*.el" "lisp/git-rebase.el"
                 "Documentation/magit.texi" "Documentation/AUTHORS.md"
                 "COPYING" (:exclude "lisp/magit-popup.el"))
         :host github :repo "raxod502/magit"
         :upstream (:host github :repo "magit/magit")))

straight.elимеет смехотворно полную документацию. Прочитайте все об этом на GitHub .


2

Это все хорошие вопросы!

Emacs работает на модели образа памяти, где загрузка нового кода изменяет образ памяти запущенного экземпляра. Определение новых функций и переменных легко отменить, если вы храните их список, но существует множество побочных эффектов, которые может иметь модуль, который вы бы хотели отменить. Похоже, что unload-featureделает это довольно хорошо.

Я думаю, что вы захотите сделать это сочетание живого программирования и периодического перезапуска Emacs, загружая модуль, над которым вы работаете, из вашей ветки, а не из того места, где он установлен. Если у вас получится много этих веток, вам может потребоваться сценарий оболочки, который запускает emacs с правильным load-pathдля того, над которым вы работаете в данный момент. В любом случае я бы не стал переименовывать пакет; Я думаю, что это будет еще более запутанным, так как emacs может загрузить их обоих.

Разрабатывая свои патчи, вы можете начать с простого переопределения функций, которые вы изменяете, прямо во время сеанса Emacs. Это позволяет вам тестировать новые определения немедленно, не покидая Emacs. В частности, когда вы редактируете файл elisp, вы можете использовать C-M-x( eval-defun) для оценки текущей функции в вашем текущем сеансе Emacs. Затем вы можете позвонить, чтобы убедиться, что он работает. Если вы изменяете что-то, что происходит при запуске Emacs, вам, вероятно, придется запустить и остановить Emacs, чтобы проверить это; Вы можете сделать это, запустив и остановив отдельный процесс Emacs, чтобы ваш сеанс редактирования не прерывался.


2

Я не думаю, что есть хороший ответ на этот вопрос (я ожидаю, что вы можете получить частичное решение с помощью Cask, хотя я недостаточно знаком с ним, чтобы дать вам хороший ответ, используя его, надеюсь, кто-то еще), но вот что я делаю (я редко использую пакет Elisp без локальных изменений, так что это действительно мой "нормальный" способ):

  • cd ~/src; git clone ..../elpa.git
  • за каждую упаковку cd ~/src/elisp; git clone ....thepackage.git
  • cd ~/src/elpa/packages; ln -s ~/src/elisp/* .
  • cd ~/src/elpa; make
  • в вашем ~/.emacsдополнении

    (eval-after-load 'package
     '(add-to-list 'package-directory-list
                   "~/src/elpa/packages"))
    

Таким образом, все пакеты устанавливаются «прямо из Git», простой cd ~/src/elpa; makeперекомпилирует те, которые в нем нуждаются, и C-h o thepackage-functionперейдет к исходному файлу, находящемуся под Git.

Для «переключения между ним и стабильной веткой по прихоти» вам необходимо git checkout <branch>; cd ~/src/elpa; make; и если вы хотите, чтобы это влияло на работу сессий Emacs, потребуется больше работы. Я обычно рекомендую не использовать, unload-featureза исключением исключительных ситуаций (это хорошая функция, но в настоящее время она недостаточно надежна).

Это также не удовлетворяет многим вашим требованиям. И у него есть некоторые дополнительные недостатки, в основном из-за того, что клон Git многих пакетов не совсем соответствует макету и содержимому, ожидаемому make-файлом elpa.git, поэтому вам нужно начать с настройки этих пакетов (как правило, с <pkg>-pkg.el, так как make-файл elpa.git предполагает собирать этот файл, <pkg>.elа не предоставлять его, но, что более проблематично, компиляция выполняется по-другому, поэтому иногда вам нужно поиграть с requires).

Да, и конечно, это в основном означает, что вы устанавливаете эти пакеты вручную, поэтому вы должны обращать внимание на зависимости. Эта установка правильно взаимодействует с другими пакетами, установленными package-install, так что это не так уж и плохо.


2

Другие ответы на этот вопрос, включая мой другой ответ , говорят о внесении исправлений в пакет Emacs путем внесения изменений в его код. Но люди, которые находят этот вопрос через Google, могут подумать о чем-то другом, когда говорят «исправить пакет Emacs», а именно - переопределить его поведение без необходимости изменять его исходный код.

Механизмы для этого включают в порядке возрастания агрессивности:

Несмотря на силу первых двух вариантов, я довольно часто выбирал третий путь, потому что иногда другого пути нет. Но тогда возникает вопрос: а что, если оригинальное определение функции изменится? У вас не будет возможности узнать, что вам нужно обновить версию этого определения, которую вы скопировали и вставили в свой init-файл!

Поскольку я одержим исправлениями, я написал пакет el-patch, который решает эту проблему как можно более подробно. Идея состоит в том, что вы определяете различия в s-выражениях в вашем init-файле, которые описывают как исходное определение функции, так и ваши изменения в ней. Это делает ваши патчи намного более читаемыми, а также позволяет el-patchпозже проверить, было ли обновлено исходное определение функции с момента создания вашего патча. (Если это так, он покажет вам изменения через Ediff!) Цитата из документации:

Рассмотрим следующую функцию, определенную в company-statisticsпакете:

(defun company-statistics--load ()
  "Restore statistics."
  (load company-statistics-file 'noerror nil 'nosuffix))

Предположим, мы хотим изменить третий аргумент с nilна 'nomessage, чтобы подавить сообщение, которое регистрируется при company-statisticsзагрузке файла статистики. Мы можем сделать это, разместив следующий код в нашем init.el:

(el-patch-defun company-statistics--load ()
  "Restore statistics."
  (load company-statistics-file 'noerror
        (el-patch-swap nil 'nomessage)
        'nosuffix))

Простой вызов el-patch-defunвместо defunопределения неоперативного патча: то есть он не имеет никакого эффекта (ну, не совсем - см. Позже ). Однако, включив директивы patch , вы можете сделать измененную версию функции отличной от оригинальной.

В этом случае мы используем el-patch-swapдирективу. el-patch-swapФорма заменяются nilв первоначальном определении (то есть версия , которая сравнивается с «официальным» определением в company-statistics.el), и 'nomessageв модифицированном определении (то есть версия , что на самом деле оцениваются в вашей инициализации-файл).


0

Когда вы делаете много изменений, я думаю, что вы должны использовать straight.el, см. Ответ Радона Росборо .

Если вы просто хотите внести одноразовое изменение, давайте предположим, что для проекта, который называется fork-mode, выполните следующие шаги:

  • Создайте каталог для хранения мерзавца mkdir ~/.emacs.d/lisp-gits
  • Сделайте форк проекта, который вы хотите изменить, скажем на https://github.com/user/fork-mode
  • Клонировать свою вилку cd ~/.emacs.d/lisp-gits && git clone git@github.com:user/fork-mode.git

Напишите следующий код в вашем .emacs

(if (file-exists-p "~/.emacs.d/lisp-gits/fork-mode")
    (use-package fork-mode :load-path "~/.emacs.d/lisp-gits/fork-mode")
  (use-package fork-mode :ensure t))

(use-package fork-mode
  :config
  (setq fork-mode-setting t)
  :hook
  ((fork-mode . (lambda () (message "Inside hook"))))

Теперь вы можете использовать режим emacs, используя C-h fдля поиска функции, которые вы хотите изменить. Вы заметите, что когда пакет установлен в lisp-gits, вы перейдете к нему. Используйте magit или другие команды git для фиксации / отправки изменений, а затем используйте github для отправки ваших запросов извлечения.

После того, как ваши запросы будут приняты, вы можете просто удалить проект ~/.emacs.d/lisp-gitsи позволить менеджеру пакетов выполнить свою работу.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.