Bagaimana cara menambal paket Emacs?


16

Saya ingin mengubah paket, mengujinya dan mudah-mudahan mengirimkan permintaan tarik sesudahnya. Bagaimana saya melakukannya dengan cara yang aman dan efisien? Pertanyaannya mungkin terasa terlalu luas, saya akan menerima jawaban yang mencakup masalah-masalah berikut:

  1. Saya berharap untuk menginstal cabang terpisah dari sebuah paket dan dapat beralih di antara itu dan cabang stabil pada kemauan, dengan kompilasi dilakukan secara otomatis ketika diperlukan, tetapi package.eltampaknya tidak menawarkan cara mudah untuk melakukan itu. Jawaban pada emacs-SE ini memberi tahu kita bahwa "Jika banyak salinan paket diinstal, maka yang pertama akan dimuat" jadi saya kira orang bisa mengacaukan secara manual load-pathtetapi ini tidak terasa kuat. Apa cara standar untuk memilih versi paket tertentu di antara yang diinstal?

  2. Bahkan jika saya berhasil mengekspos beberapa cabang ke Emacs, untuk penyesuaian signifikan saya perlu memastikan cabang yang belum ditambal "dibongkar" dan efek sampingnya terisolasi. Apakah unload-featuremenangani ini dengan benar atau mungkin memiliki kekhasan yang harus diketahui oleh setiap penguji paket multi-versi?

  3. Bagaimana cara saya menginstal dan menguji versi lokal? Jawabannya tampaknya tergantung pada apakah paket itu sederhana (= satu file) atau multifile. EmacsWiki mengatakan tentang paket multi-fungsi : " MELPA membuat paket untuk Anda ". Saya ragu bahwa saya harus (atau harus) berbicara dengan MELPA setiap kali saya mengubah defunformulir dalam paket multifile tetapi pertanyaannya tetap. Setidaknya saya perlu memberi tahu manajer paket tentang versi lokal, dan jika demikian, bagaimana saya melakukannya?

  4. Nama apa yang harus saya tetapkan untuk versi paket lokal? Misalkan saya ingin mengerjakan beberapa fitur atau bug secara bersamaan, yang berarti memiliki beberapa cabang. Emacs tidak akan mengizinkan untuk menyebutkan versi secara deskriptif (sepanjang baris 20170117.666-somebugorfeature). Saya kira saya bisa mengganti nama paket itu sendiri, akhiran per cabang, tapi sekali lagi, seperti mengacaukan secara manual load-pathdi Q1, ini adalah hack yang jelek, jadi saya tidak akan mencobanya dengan sesuatu yang saya ingin kirim ke hulu kecuali itu adalah praktik yang diterima secara luas .

Pertanyaannya mungkin naif, karena saya tidak pernah menulis tambalan yang tidak diterapkan dengan git atau vcs serupa. Namun, bagi banyak pengguna Emacs, menambal paket Emacs mungkin merupakan upaya pemrograman sosial pertama mereka (atau mungkin satu-satunya), yang mengapa, saya yakin, jawaban atas pertanyaan ini masih berharga.

Jawaban:


7

Untuk berpadu dengan alur kerja yang sedikit berbeda untuk memuat versi paket yang berbeda, inilah beberapa variasi dari apa yang saya lakukan, keduanya menggunakan load-pathuntuk mengontrol versi yang saya gunakan (mengubah nama paket adalah ide yang buruk jika ada dependensi). Saya memiliki versi saat ini dari "paket bagus" diinstal ~/.emacs.d/elpamenggunakan M-x package-install, dan paket repo clone ~/src/nice-packagedengan git clone ....

Dengan paket-penggunaan

Di init.el, saya punya

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

Dengan :load-pathbaris yang tidak di-komentar, ini akan menggunakan versi git dari paket. Mengomentari baris ini, dan memuat ulang emacs menggunakan versi elpa.

Serupa tanpa menggunakan paket

Di init.el,

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

Sekarang lakukan trik komentar yang sama dengan baris pertama.

Menggunakan emacs -L

Ini adalah ide yang sama, tetapi memanipulasi load-pathdari baris perintah. Anda dapat memuat instance emacs dengan versi git dari paket

emacs -L ~/src/nice-package

yang hanya menambahkan jalan ini ke depan jalur beban. Dengan begitu, Anda dapat meluncurkan emacsdari terminal yang berbeda dan mendapatkan versi lama dan baru dari paket yang berjalan berdampingan.

Komentar lain-lain

  1. Gunakan M-x eval-buffersetelah mengedit file paket untuk memuat definisi baru yang Anda buat.
  2. Memeriksa apa yang dikatakan kompiler M-x emacs-lisp-byte-compilejuga berguna

Saya menggunakan emacs -Lpendekatan untuk memuat versi lokal dari sebuah paket yang saya juga instal secara global menggunakan Tong. Satu hal yang membuat saya kecewa adalah menjalankan <package>-versionselalu mengembalikan versi yang diinstal secara global, bahkan ketika saya benar-benar menjalankan versi modifikasi lokal. Ternyata ini karena <package>-versionpaket untuk mendapatkan versi dari packages.el.
ntc2

3

Pertanyaan bagus! Jawabannya adalah bahwa sampai sekarang, tidak ada jawaban yang baik, karena tidak ada manajer paket yang ada yang dirancang untuk kasus penggunaan ini (kecuali untuk Borg , tetapi Borg tidak berusaha untuk menangani operasi manajemen paket umum lainnya seperti penanganan ketergantungan) .

Tapi sekarang, ada straight.el, manajer paket generasi berikutnya untuk Emacs yang menangani masalah ini selengkap mungkin. Penafian: Saya menulis straight.el!

Setelah memasukkan potongan bootstrap , menginstal paket semudah

(straight-use-package 'magit)

Ini akan mengkloning repositori Git untuk Magit, membangun paket dengan menghubungkan file-nya ke direktori yang terpisah, byte-compile, menghasilkan dan mengevaluasi pengisian otomatis, dan mengkonfigurasi dengan load-pathbenar. Tentu saja, jika paket sudah diklon dan dibangun, tidak ada yang terjadi, dan waktu init Anda tidak akan terganggu.

Bagaimana Anda membuat perubahan pada Magit? Itu sepele! Cukup gunakan M-x find-functionatau M-x find-libraryuntuk melompat ke kode sumber, dan retas! Anda dapat mengevaluasi perubahan Anda untuk mengujinya secara langsung, seperti praktik umum untuk pengembangan Emacs Lisp, dan ketika Anda memulai ulang Emacs, paket akan secara otomatis dibangun kembali, disusun ulang, dan sebagainya. Ini sepenuhnya otomatis dan sangat mudah.

Ketika Anda puas dengan perubahan Anda, cukup komit, dorong, dan buat permintaan tarik. Anda memiliki kontrol total atas paket lokal Anda. Tetapi konfigurasi Anda masih dapat direproduksi 100% karena Anda dapat meminta straight.eluntuk membuat file kunci yang menyimpan revisi Git dari semua paket Anda, termasuk straight.elitu sendiri, MELPA, dan sebagainya.

straight.eldapat menginstal paket apa pun dari MELPA, GNU ELPA, atau EmacsMirror. Tetapi ia juga memiliki resep DSL yang sangat fleksibel yang memungkinkan Anda untuk menginstal dari mana saja, serta untuk menyesuaikan bagaimana paket dibangun. Berikut ini contoh yang menunjukkan beberapa opsi:

(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.elmemiliki dokumentasi yang sangat komprehensif. Baca semua tentang itu di GitHub .


2

Ini semua adalah pertanyaan bagus!

Emacs bekerja pada model memori-gambar, di mana memuat kode baru mengubah gambar memori dari instance yang sedang berjalan. Mendefinisikan fungsi dan variabel baru dengan mudah diurungkan, jika Anda menyimpan daftarnya, tetapi ada banyak efek samping yang mungkin dimiliki modul yang ingin Anda batalkan. Sepertinya unload-featuremembuat itu cukup bagus.

Saya pikir apa yang ingin Anda lakukan adalah kombinasi live coding dan sesekali meluncurkan kembali Emacs, memuat modul yang sedang Anda kerjakan dari cabang Anda dan bukan dari tempat dipasangnya. Jika Anda memiliki banyak cabang ini, Anda mungkin menginginkan skrip shell yang meluncurkan emacs dengan benar load-pathuntuk yang sedang Anda kerjakan saat ini. Bagaimanapun saya tidak akan mengganti nama paket; Saya pikir itu akan lebih membingungkan karena emacs kemudian dapat memuat keduanya.

Saat Anda mengembangkan tambalan Anda, Anda bisa mulai dengan mendefinisikan kembali fungsi yang Anda ubah tepat di sesi Emacs langsung Anda. Ini memungkinkan Anda menguji definisi baru dengan segera, tanpa meninggalkan Emacs. Secara khusus, saat Anda mengedit file elisp Anda dapat menggunakan C-M-x( eval-defun) untuk mengevaluasi fungsi saat ini di sesi Emacs Anda saat ini. Anda kemudian dapat memanggilnya untuk memastikan itu berfungsi. Jika Anda mengubah sesuatu yang terjadi pada startup Emacs maka Anda harus memulai dan menghentikan Emacs untuk mengujinya; Anda dapat melakukannya dengan memulai dan menghentikan proses Emacs terpisah sehingga sesi pengeditan Anda tidak terganggu.


2

Saya tidak berpikir ada jawaban yang bagus untuk itu (saya harap Anda bisa mendapatkan solusi parsial dengan Cask, tho saya tidak cukup akrab dengannya untuk memberikan jawaban yang baik dengan menggunakannya; semoga orang lain akan), tapi di sini apa yang saya lakukan (saya jarang menggunakan paket Elisp tanpa membuat perubahan lokal untuk itu, jadi itu benar-benar cara saya "normal"):

  • cd ~/src; git clone ..../elpa.git
  • untuk setiap paket cd ~/src/elisp; git clone ....thepackage.git
  • cd ~/src/elpa/packages; ln -s ~/src/elisp/* .
  • cd ~/src/elpa; make
  • di ~/.emacsadd Anda

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

Dengan cara ini, semua paket diinstal "langsung dari Git", sebuah simpel cd ~/src/elpa; makeakan mengkompilasi ulang yang membutuhkannya, dan C-h o thepackage-functionakan melompat ke file sumber yang berada di bawah Git.

Untuk "beralih di antara itu dan cabang stabil pada kemauan", Anda harus git checkout <branch>; cd ~/src/elpa; make; dan jika Anda ingin itu mempengaruhi menjalankan sesi Emacs itu akan membutuhkan lebih banyak pekerjaan. Saya biasanya merekomendasikan untuk tidak menggunakan unload-featurekecuali dalam situasi luar biasa (ini adalah fitur yang baik, tetapi saat ini tidak cukup dapat diandalkan).

Itu juga tidak memenuhi banyak persyaratan Anda. Dan itu memiliki beberapa kelemahan tambahan, sebagian besar fakta bahwa banyak klon Git paket tidak cukup cocok dengan tata letak dan konten yang diharapkan oleh makefile elpa.git, jadi Anda harus mulai dengan mengubah paket-paket tersebut (biasanya hal-hal yang berkaitan dengan <pkg>-pkg.el, karena makefile dari elpa.git mengharapkan untuk membuat file ini <pkg>.eldaripada membuatnya disediakan, tetapi yang lebih bermasalah, kompilasi dilakukan secara berbeda, jadi kadang-kadang Anda perlu bermain dengan requires).

Oh dan tentu saja, ini pada dasarnya berarti Anda menginstal paket-paket itu dengan tangan, jadi Anda harus memperhatikan ketergantungan. Pengaturan ini benar berinteraksi dengan paket lain yang diinstal oleh package-install, tho, jadi tidak terlalu buruk.


2

Jawaban lain untuk pertanyaan ini, termasuk jawaban saya yang lain , berbicara tentang menambal paket Emacs dengan membuat perubahan pada kodenya. Tetapi orang-orang yang menemukan pertanyaan ini melalui Google mungkin memikirkan hal lain ketika mereka mengatakan "menambal paket Emacs" - yaitu, mengesampingkan perilakunya tanpa harus mengubah kode sumbernya.

Mekanisme untuk melakukan ini termasuk, dalam urutan peningkatan keagresifan:

Terlepas dari kekuatan dua opsi pertama, saya mendapati diri saya mengambil rute ketiga cukup sering, karena kadang-kadang tidak ada cara lain. Tetapi kemudian pertanyaannya adalah, bagaimana jika definisi fungsi asli berubah? Anda tidak akan mengetahui bahwa Anda perlu memperbarui versi definisi yang telah Anda salin dan tempel ke file init Anda!

Karena saya terobsesi dengan menambal sesuatu, saya menulis paket el-patch, yang menyelesaikan masalah ini selengkap mungkin. Idenya adalah Anda mendefinisikan perbedaan berbasis-ekspresi dalam file init Anda, yang menggambarkan definisi fungsi asli dan perubahannya. Ini membuat tambalan Anda jauh lebih mudah dibaca, dan juga memungkinkan el-patchuntuk memvalidasi nanti apakah definisi fungsi asli telah diperbarui sejak Anda membuat tambalan Anda. (Jika demikian, itu akan menunjukkan kepada Anda perubahan melalui Ediff!) Mengutip dari dokumentasi:

Pertimbangkan fungsi berikut yang didefinisikan dalam company-statisticspaket:

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

Misalkan kita ingin mengubah argumen ketiga dari nilmenjadi 'nomessage, untuk menekan pesan yang dicatat ketika company-statisticsmemuat file statistiknya. Kita dapat melakukannya dengan menempatkan kode berikut di init.el:

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

Cukup memanggil el-patch-defunalih-alih defunmendefinisikan patch no-op: artinya, itu tidak memiliki efek (well, tidak cukup — lihat nanti ). Namun, dengan memasukkan arahan tambalan , Anda dapat membuat versi modifikasi dari fungsi ini berbeda dari aslinya.

Dalam hal ini, kami menggunakan el-patch-swaparahan. The el-patch-swapBentuk diganti dengan nildalam definisi asli (yaitu, versi yang dibandingkan terhadap definisi "resmi" di company-statistics.el), dan dengan 'nomessagedalam definisi dimodifikasi (yaitu, versi yang sebenarnya dievaluasi dalam init-file Anda).


0

Ketika Anda membuat banyak perubahan, saya pikir Anda harus menggunakan straight.el, lihat jawabannya oleh Radon Rosborough .

Jika Anda hanya ingin membuat perubahan satu kali, mari kita asumsikan sebuah proyek bernama fork-mode, lakukan langkah-langkah berikut:

  • Buat direktori untuk menyimpan git mkdir ~/.emacs.d/lisp-gits
  • Buatlah garpu proyek yang ingin Anda ubah, katakan di https://github.com/user/fork-mode
  • Kloning garpu Anda cd ~/.emacs.d/lisp-gits && git clone git@github.com:user/fork-mode.git

Tulis kode berikut di .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"))))

Sekarang Anda dapat menggunakan mode emacs, gunakan C-h funtuk menemukan fungsi yang ingin Anda ubah. Anda akan melihat bahwa ketika paket diinstal di lisp-gits, Anda akan melompat ke sana. Gunakan perintah magit atau git lainnya untuk melakukan / mendorong perubahan dan kemudian menggunakan github untuk mengirim permintaan tarikan Anda.

Setelah permintaan tarik Anda diterima, Anda bisa menghapus proyek ~/.emacs.d/lisp-gitsdan membiarkan manajer paket melakukan tugasnya.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.