Làm cách nào để vá một gói Emacs?


16

Tôi muốn thay đổi một gói, kiểm tra nó và hy vọng gửi yêu cầu kéo sau đó. Làm thế nào để tôi làm điều đó một cách an toàn và hiệu quả? Câu hỏi có thể cảm thấy quá rộng, tôi sẽ chấp nhận câu trả lời bao gồm các vấn đề sau:

  1. Tôi hy vọng sẽ cài đặt một nhánh riêng của gói và có thể chuyển đổi giữa nó và nhánh ổn định theo ý thích, với việc biên dịch lại được thực hiện tự động khi cần thiết, nhưng package.eldường như không cung cấp một cách đơn giản để làm điều đó. Câu trả lời này trên emacs-SE thông báo cho chúng tôi rằng Nếu một bản sao của gói được cài đặt, thì bản đầu tiên sẽ được tải lên vì vậy tôi đoán người ta có thể tự làm rối load-pathnhưng điều này không cảm thấy mạnh mẽ. Cách tiêu chuẩn để chọn một phiên bản cụ thể của gói được cài đặt là gì?

  2. Ngay cả khi tôi quản lý để hiển thị một số chi nhánh cho Emacs, đối với các chỉnh sửa quan trọng, tôi cần đảm bảo rằng chi nhánh chưa được chỉnh sửa là không được tải xuống và các tác dụng phụ của nó bị cô lập. Liệu unload-featurexử lý việc này đúng cách hay có thể nó có những đặc điểm riêng mà mọi người thử nghiệm các gói đa phiên bản nên biết?

  3. Làm cách nào để cài đặt và kiểm tra phiên bản cục bộ? Câu trả lời dường như phụ thuộc vào việc gói đơn giản (= một tệp) hay đa tệp. EmacsWiki nói về các gói multifile: MELPA xây dựng các gói cho bạn . Tôi nghi ngờ rằng tôi phải (hoặc nên) nói chuyện với MELPA mỗi khi tôi thay đổi một defunbiểu mẫu trong gói đa biến nhưng câu hỏi vẫn còn. Ít nhất tôi cần nói với người quản lý gói về phiên bản địa phương, và nếu vậy, tôi phải làm thế nào?

  4. Tôi nên gán tên nào cho các phiên bản địa phương của gói? Giả sử tôi muốn làm việc trên nhiều tính năng hoặc lỗi đồng thời, có nghĩa là có nhiều nhánh. Emacs sẽ không cho phép đặt tên phiên bản theo cách mô tả (dọc theo dòng 20170117.666-somebugorfeature). Tôi đoán rằng tôi có thể đổi tên chính gói đó, hậu tố cho mỗi nhánh, nhưng một lần nữa, như làm rối thủ công load-pathtrong Q1, đây là một hack xấu xí, vì vậy tôi sẽ không thử nó với thứ gì đó mà tôi dự định gửi ngược dòng trừ khi đó là một thực tế được chấp nhận rộng rãi .

Các câu hỏi có lẽ là ngây thơ, vì tôi không bao giờ viết một bản vá không áp dụng một bản vá với git hoặc một vcs tương tự. Tuy nhiên, đối với nhiều người dùng Emacs, việc vá gói Emacs có thể là nỗ lực lập trình xã hội đầu tiên (hoặc có thể là duy nhất) của họ, đó là lý do tại sao, tôi tin rằng, câu trả lời cho câu hỏi này vẫn có giá trị.

Câu trả lời:


7

Để kết hợp với một luồng công việc hơi khác nhau để tải các phiên bản gói khác nhau, đây là một vài biến thể của những gì tôi làm, cả hai đều sử dụng load-pathđể kiểm soát phiên bản nào tôi đang sử dụng (thay đổi tên của gói là một ý tưởng tồi nếu có phụ thuộc). Tôi có phiên bản hiện tại của "đẹp-gói" cài đặt trong ~/.emacs.d/elpasử dụng M-x package-install, và clone gói repo ở ~/src/nice-packagevới git clone ....

Với gói sử dụng

Trong init.el, tôi có

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

Với :load-pathdòng không bị lỗi, điều này sẽ sử dụng phiên bản git của gói. Nhận xét dòng này và tải lại emacs sử dụng phiên bản elpa.

Tương tự không có gói sử dụng

Trong init.el,

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

Bây giờ làm thủ thuật bình luận tương tự với dòng đầu tiên.

Sử dụng emacs -L

Đây là cùng một ý tưởng, nhưng thao tác load-pathtừ dòng lệnh. Bạn có thể tải một phiên bản của emacs với phiên bản git của gói với

emacs -L ~/src/nice-package

mà chỉ cần chuẩn bị đường dẫn này đến phía trước của đường dẫn tải. Bằng cách đó, bạn có thể khởi chạy emacstừ một thiết bị đầu cuối khác và nhận các phiên bản cũ và mới của gói chạy song song.

Nhận xét linh tinh

  1. Sử dụng M-x eval-buffersau khi chỉnh sửa tệp gói để tải các định nghĩa mới mà bạn đã tạo.
  2. Kiểm tra những gì trình biên dịch nói với M-x emacs-lisp-byte-compilecũng tiện dụng

Tôi đang sử dụng emacs -Lphương pháp để tải phiên bản cục bộ của gói mà tôi cũng đã cài đặt trên toàn cầu bằng Cask. Một điều khiến tôi thất vọng là việc chạy <package>-versionluôn trả về phiên bản được cài đặt toàn cầu, ngay cả khi tôi thực sự đang chạy phiên bản sửa đổi cục bộ. Hóa ra điều này là do <package>-versiongói này lấy phiên bản từ packages.el.
ntc2

3

Câu hỏi hay! Câu trả lời là cho đến nay, không có câu trả lời hay, vì không có trình quản lý gói hiện tại nào được thiết kế cho trường hợp sử dụng này (ngoại trừ Borg , nhưng Borg không cố gắng xử lý các hoạt động quản lý gói thông thường khác như xử lý phụ thuộc) .

Nhưng bây giờ, có straight.elmột trình quản lý gói thế hệ tiếp theo cho Emacs giải quyết vấn đề này một cách toàn diện nhất có thể. Tuyên bố miễn trừ trách nhiệm: Tôi đã viết straight.el!

Sau khi chèn đoạn mã bootstrap , cài đặt gói đơn giản như

(straight-use-package 'magit)

Điều này sẽ sao chép kho Git cho Magit, xây dựng gói bằng cách liên kết các tệp của nó vào một thư mục riêng, biên dịch byte, tạo và đánh giá tự động tải và định cấu hình load-pathchính xác. Tất nhiên, nếu gói đã được sao chép và xây dựng, không có gì xảy ra và thời gian init của bạn không bị ảnh hưởng.

Làm thế nào để bạn thay đổi Magit? Thật tầm thường! Chỉ cần sử dụng M-x find-functionhoặc M-x find-libraryđể nhảy đến mã nguồn, và hack đi! Bạn có thể đánh giá các thay đổi của mình để kiểm tra chúng trực tiếp, như thông lệ chung cho phát triển Emacs Lisp và khi bạn khởi động lại Emacs, gói sẽ tự động được xây dựng lại, biên dịch lại, v.v. Nó hoàn toàn tự động và hoàn hảo.

Khi bạn hài lòng với những thay đổi của mình, chỉ cần cam kết, đẩy và đưa ra yêu cầu kéo. Bạn có toàn quyền kiểm soát các gói địa phương của bạn. Nhưng cấu hình của bạn vẫn có thể được tái tạo 100% vì bạn có thể yêu cầu straight.eltạo một tệp khóa để lưu bản sửa đổi Git của tất cả các gói của bạn, bao gồm straight.elchính nó, MELPA, v.v.

straight.elcó thể cài đặt bất kỳ gói nào từ MELPA, GNU ELPA hoặc EmacsMirror. Nhưng nó cũng có một DSL công thức rất linh hoạt cho phép bạn cài đặt từ bất cứ đâu, cũng như để tùy chỉnh cách gói được xây dựng. Đây là một ví dụ cho thấy một số tùy chọn:

(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.elcó tài liệu toàn diện lố bịch. Đọc tất cả về nó trên GitHub .


2

Đây là tất cả những câu hỏi hay!

Emacs hoạt động trên mô hình hình ảnh bộ nhớ, trong đó việc tải mã mới làm thay đổi hình ảnh bộ nhớ của thể hiện đang chạy. Việc xác định các hàm và biến mới dễ dàng được hoàn tác, nếu bạn giữ một danh sách về chúng, nhưng có rất nhiều tác dụng phụ mà một mô-đun có thể có mà bạn muốn hoàn tác. Có vẻ như unload-featurelàm cho một đi khá tốt của nó mặc dù.

Tôi nghĩ rằng những gì bạn sẽ muốn làm là sự kết hợp của mã hóa trực tiếp và đôi khi khởi chạy lại Emacs, tải mô-đun bạn đang làm việc từ chi nhánh của bạn chứ không phải từ nơi nó được cài đặt. Nếu bạn kết thúc với rất nhiều nhánh này, bạn có thể muốn một tập lệnh shell khởi chạy emacs với chính xác load-pathcho cái mà bạn đang làm việc vào lúc này. Trong mọi trường hợp tôi sẽ không đổi tên gói; Tôi nghĩ điều đó sẽ còn khó hiểu hơn nữa vì emacs có thể tải cả hai.

Khi bạn phát triển các bản vá của mình, bạn có thể bắt đầu bằng cách xác định lại các chức năng mà bạn đang thay đổi ngay trong phiên Emacs trực tiếp của mình. Điều này cho phép bạn kiểm tra các định nghĩa mới ngay lập tức mà không cần rời khỏi Emacs. Cụ thể, khi bạn chỉnh sửa một tệp elisp, bạn có thể sử dụng C-M-x( eval-defun) để đánh giá hàm hiện tại trong phiên Emacs hiện tại của mình. Sau đó bạn có thể gọi nó để đảm bảo nó hoạt động. Nếu bạn đang thay đổi điều gì đó xảy ra khi khởi động Emacs thì có khả năng bạn sẽ phải bắt đầu và dừng Emacs để kiểm tra nó; bạn có thể làm điều đó bằng cách bắt đầu và dừng một quy trình Emacs riêng biệt để phiên chỉnh sửa của bạn không bị gián đoạn.


2

Tôi không nghĩ rằng có một câu trả lời hay cho điều đó (tôi hy vọng bạn có thể nhận được một giải pháp một phần với Cask, tôi không đủ quen thuộc với nó để cung cấp cho bạn một câu trả lời tốt khi sử dụng nó; hy vọng người khác sẽ làm được), nhưng đây là những gì tôi làm (tôi hiếm khi sử dụng gói Elisp mà không thực hiện thay đổi cục bộ cho gói đó, vì vậy đó thực sự là cách "bình thường" của tôi):

  • cd ~/src; git clone ..../elpa.git
  • cho mỗi gói cd ~/src/elisp; git clone ....thepackage.git
  • cd ~/src/elpa/packages; ln -s ~/src/elisp/* .
  • cd ~/src/elpa; make
  • trong ~/.emacsphần thêm của bạn

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

Bằng cách này, tất cả các gói được cài đặt "trực tiếp từ Git", một đơn giản cd ~/src/elpa; makesẽ biên dịch lại những gói cần nó và C-h o thepackage-functionsẽ chuyển đến một tệp nguồn dưới Git.

Để "chuyển đổi giữa nó và chi nhánh ổn định theo ý thích", bạn sẽ cần phải git checkout <branch>; cd ~/src/elpa; make; và nếu bạn muốn nó ảnh hưởng đến việc chạy các phiên Emacs thì sẽ mất nhiều công sức hơn. Tôi thường khuyên bạn không nên sử dụng unload-featurengoại trừ trong những tình huống đặc biệt (đó là một tính năng tốt, nhưng nó không hiện đủ tin cậy).

Nó cũng không đáp ứng nhiều yêu cầu của bạn. Và nó còn có một số nhược điểm nữa, chủ yếu là thực tế là nhiều bản sao Git của gói không phù hợp với bố cục và nội dung mà elpa.git's makefile mong đợi, vì vậy bạn sẽ cần bắt đầu bằng cách điều chỉnh các gói đó (thường là những việc phải làm với <pkg>-pkg.el, vì makefile của elpa.git dự kiến ​​sẽ xây dựng tệp này <pkg>.elthay vì được cung cấp, nhưng vấn đề hơn là việc biên dịch được thực hiện khác nhau, vì vậy đôi khi bạn cần chơi với requires).

Ồ và tất nhiên, điều này về cơ bản có nghĩa là bạn đang cài đặt các gói đó bằng tay, vì vậy bạn phải chú ý đến các phụ thuộc. Thiết lập này không tương tác đúng với các gói khác được cài đặt bởi package-install, tho, vì vậy nó không quá tệ.


2

Các câu trả lời khác cho câu hỏi này, bao gồm cả câu trả lời khác của tôi , nói về việc vá gói Emacs bằng cách thay đổi mã của nó. Nhưng mọi người tìm thấy câu hỏi này thông qua Google có thể đang nghĩ đến điều gì khác khi họ nói "vá một gói Emacs" - cụ thể là ghi đè hành vi của nó mà không phải sửa đổi mã nguồn.

Các cơ chế để làm điều này bao gồm, theo thứ tự tăng cường tích cực:

  • thêm chức năng vào hook hoặc liên kết các biến động bằng cách sử dụnglet
  • hệ thống tư vấn mạnh mẽ
  • chỉ đơn giản là ghi đè chức năng bạn muốn sửa đổi

Bất chấp sức mạnh của hai lựa chọn đầu tiên, tôi thấy mình đi con đường thứ ba khá thường xuyên, vì đôi khi không còn cách nào khác. Nhưng sau đó, câu hỏi là, nếu định nghĩa hàm ban đầu thay đổi thì sao? Bạn sẽ không có cách nào để biết rằng bạn cần cập nhật phiên bản định nghĩa mà bạn đã sao chép và dán vào tệp init của mình!

Bởi vì tôi bị ám ảnh với việc vá các thứ, tôi đã viết gói el-patch, giải quyết vấn đề này một cách toàn diện nhất có thể. Ý tưởng là bạn định nghĩa khác biệt dựa trên biểu thức s trong tệp init của bạn, mô tả cả định nghĩa hàm ban đầu và các thay đổi của bạn đối với nó. Điều này làm cho các bản vá của bạn dễ đọc hơn nhiều và cũng cho phép el-patchsau đó xác thực xem định nghĩa chức năng ban đầu đã được cập nhật kể từ khi bạn thực hiện bản vá của mình. (Nếu vậy, nó sẽ cho bạn thấy những thay đổi thông qua Ediff!) Trích dẫn từ tài liệu:

Hãy xem xét các chức năng sau được định nghĩa trong company-statisticsgói:

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

Giả sử chúng ta muốn thay đổi đối số thứ ba từ nilsang 'nomessage, để chặn thông báo được ghi lại khi company-statisticstải tệp thống kê của nó. Chúng tôi có thể làm điều đó bằng cách đặt đoạn mã sau vào init.el:

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

Đơn giản chỉ cần gọi el-patch-defunthay vì defunđịnh nghĩa một bản vá không có op: đó là, nó không có tác dụng (tốt, không hoàn toàn có thể nhìn thấy sau này ). Tuy nhiên, bằng cách bao gồm các chỉ thị vá , bạn có thể làm cho phiên bản sửa đổi của chức năng khác với bản gốc.

Trong trường hợp này, chúng tôi sử dụng el-patch-swapchỉ thị. Biểu el-patch-swapmẫu được thay thế bằng nilđịnh nghĩa ban đầu (nghĩa là phiên bản được so sánh với định nghĩa "chính thức" trong company-statistics.el) và với 'nomessageđịnh nghĩa đã sửa đổi (nghĩa là phiên bản được đánh giá thực sự trong tệp init của bạn).


0

Khi bạn thực hiện nhiều thay đổi, tôi nghĩ bạn nên sử dụng straight.el, xem câu trả lời của Radon Rosborough .

Nếu bạn chỉ muốn thực hiện một thay đổi, hãy giả sử một dự án được gọi fork-mode, thực hiện các bước sau:

  • Tạo một thư mục để lưu trữ git mkdir ~/.emacs.d/lisp-gits
  • Tạo một ngã ba của dự án mà bạn muốn thay đổi, nói tại https://github.com/user/fork-mode
  • Nhân bản ngã ba của bạn cd ~/.emacs.d/lisp-gits && git clone git@github.com:user/fork-mode.git

Viết đoạn mã sau vào .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"))))

Bây giờ bạn có thể sử dụng chế độ emacs, sử dụng C-h fđể tìm các chức năng bạn muốn thay đổi. Bạn sẽ nhận thấy rằng khi gói được cài đặt trong lisp-gits, bạn sẽ nhảy đến đó. Sử dụng magit hoặc các lệnh git khác để cam kết / đẩy thay đổi và sau đó sử dụng github để gửi yêu cầu kéo của bạn.

Khi các yêu cầu kéo của bạn được chấp nhận, bạn có thể xóa dự án ~/.emacs.d/lisp-gitsvà để người quản lý gói thực hiện công việc của mình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.