Як я виправити пакет Emacs?


16

Я хочу змінити пакет, протестувати його і, сподіваюся, після цього надіслати запит на тягу. Як це зробити безпечним та ефективним способом? Питання може бути занадто широким, я прийму відповідь, яка охоплює такі питання:

  1. Я очікував би встановити окрему гілку пакету і мати можливість перемикатися між ним та стабільною гілкою на примху, при цьому перекомпіляція виконується автоматично, коли це необхідно, але package.el, здається, не пропонує прямого способу зробити це. Ця відповідь на emacs-SE повідомляє нам, що "Якщо встановлено кілька копій пакета, то перша буде завантажена", тому я думаю, що можна було б вручну зіпсуватись, load-pathале це не відчуває себе надійним. Який стандартний спосіб вибрати конкретну версію пакета серед встановлених?

  2. Навіть якщо мені вдасться піднести кілька гілок до Emacs, для значних налаштувань мені потрібно переконатись, що незапалена гілка «вивантажена» та її побічні ефекти ізольовані. Чи unload-featureправильно поводитися з цим чи, можливо, в ньому є ідіосинкразії, про які повинен знати кожен тестер багатоверсійних пакетів?

  3. Як встановити та протестувати локальну версію? Здається, відповідь залежить від того, простий пакет (= один файл) або багатофайл. EmacsWiki говорить про багатофайлові пакети: " MELPA створює пакети для вас ". Я сумніваюся, що мені доводиться (або повинен) говорити з MELPA щоразу, коли я міняю defunформу в мультифайловому пакеті, але питання залишається. Принаймні мені потрібно розповісти менеджеру пакунків про локальну версію, і якщо так, то як це зробити?

  4. Які імена слід призначити локальним версіям пакетів? Припустимо, я хочу працювати над кількома функціями або помилками одночасно, а це означає мати кілька гілок. Emacs не дозволить називати версії в описовому порядку (по рядках 20170117.666-somebugorfeature). Напевно, я міг би перейменувати сам пакет, суфікс на гілку, але знову ж таки, як вручну возитися з load-pathQ1, це некрасивий хак, тому я не намагатимусь із тим, що я маю намір відправити вгору, якщо це не є загальноприйнятою практикою .

Питання, ймовірно, наївні, оскільки я ніколи не писав патч, не застосовував жодного з 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правильно. Звичайно, якщо пакет вже клонований і побудований, нічого не станеться, і ваш час init не страждає.

Як вносити зміни до 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-клон багатьох пакетів не зовсім відповідає макеті та вмісту, який очікує файл makepa elpa.git, тому вам потрібно буде почати з переробки цих пакетів (як правило, це стосується <pkg>-pkg.el, оскільки файл makepa 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визначити патч без відключення: тобто він не має ефекту (ну, не зовсім - див. Пізніше ). Однак, включивши директиви щодо патчів , ви можете зробити модифіковану версію функції відмінною від оригінальної.

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


0

Коли ви зробите багато змін, я думаю, вам варто скористатися straight.el, дивіться відповідь Радона Росборо .

Якщо ви просто хочете внести разову зміну, припустимо, що проект називається fork-mode, виконайте наступні дії:

  • Складіть каталог для зберігання git 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.