Viết Elisp di động


8

Lý tưởng nhất, tôi muốn có thể lưu trữ toàn bộ nội dung trong .emacs.dthư mục của mình và để nó "chỉ hoạt động" trên bất kỳ Emacs nào tôi tải nó vào, nhưng vẫn tận dụng mọi tính năng của môi trường cụ thể, như hệ thống cửa sổ GUI.

Tôi không tìm kiếm một bách khoa toàn thư về các tính năng không tương thích. Tôi chỉ muốn biết cách kiểm tra các tính năng, HĐH, phiên bản, đồ họa, v.v. và cách tận dụng những tính năng này mà không phá vỡ mã cho các cấu hình khác.

Tôi có thể sử dụng những kỹ thuật cơ bản nào để viết Elisp hoạt động trong nhiều phiên bản Emacs phổ biến trong tự nhiên (ví dụ: 22.x +) và trên nhiều nền tảng cơ bản (ví dụ: OSX, Linux, Windows và * nix khác), trong khi tận dụng nền tảng và tính năng phiên bản cụ thể khi áp dụng?


1
@Malabarba Nếu câu hỏi được hiểu là liệt kê tất cả sự khác biệt giữa các phiên bản và nền tảng khác nhau, thì vâng, nó quá rộng. Nhưng các kỹ thuật cơ bản - kiểm tra nếu số nhận dạng bị ràng buộc, phục hồi từ các lỗi, kiểm tra window-system, vv có thể được trả lời hợp lý ở đây.
Gilles 'SO- ngừng trở nên xấu xa'

1
Emacs 22 không còn gần đây nữa. Ngay cả Emacs 23 là ngày.
lunaryorn

1
Tôi bao gồm emacs 22 vì nó phổ biến trong tự nhiên. Ví dụ: nó đi kèm với OSX 10.9.
Paul Miller

Bất kỳ người dùng Emacs nghiêm túc nào trên máy Mac đều tải xuống phiên bản gần đây. Emacs 22 chỉ được bao gồm trong OS X vì đây là phiên bản cuối cùng được cấp phép theo GPLv2 (và IMO họ chỉ nên bỏ nó hoàn toàn). Tôi nghĩ 23+ hữu ích hơn nhiều (IIRC Debian ổn định vẫn sử dụng 23).
shosti

2
Sheesh. Người đặt câu hỏi hỏi về Emacs 22+ và bạn muốn "sửa" yêu cầu đó để nhấn mạnh vào phiên bản mới hơn? Điều gì tiếp theo - ai đó hỏi về forward-charvà bạn muốn thay đổi câu hỏi để hỏi về scroll-upthay thế? Nếu OP muốn tương thích Emacs 22+, hãy để yên. Và không, câu hỏi được đặt ra không chỉ về OS X. Và vâng, vẫn còn rất nhiều người sử dụng các phiên bản Emacs cũ hơn (một số thậm chí cũ hơn 22, FWIW).
vẽ

Câu trả lời:


10

Elisp là một ngôn ngữ được giải thích. Bạn có thể đặt mã dành riêng cho phiên bản .emacs, nhưng bảo vệ mã bằng cách kiểm tra tại thời điểm tải mà nó hoạt động trên phiên bản chính xác.

(if (is-new-feature-available)
    (shiny-new-feature)
  (old-less-nifty-feature))

Mã này sẽ hoạt động trong tất cả các phiên bản vì (shiny-new-feature)chỉ được đánh giá khi (is-new-feature-available)trả về true. Phần lớn câu trả lời này được dành cho cách thực hiện (is-new-feature-available).

Đối phó với các bộ tính năng khác nhau

Tốt hơn hết là kiểm tra xem một tính năng có khả dụng hay không hơn là kiểm tra phiên bản Emacs. Đôi khi tính năng có thể có sẵn như là một gói tùy chọn. Nếu bạn muốn chạy mã trong XEmac hoặc biến thể Emacs khác, nó có thể đã có được các tính năng tương tự trong các phiên bản khác nhau. Sử dụng chức năng boundpđể kiểm tra nếu một biến có sẵn và fboundpđể kiểm tra nếu một chức năng có sẵn.

Ví dụ: đoạn mã sau liên kết một phím để chuyển đổi visual-line-modenếu có, và longlines-modenếu không.

(global-set-key "\eml" (if (fboundp 'visual-line-mode)
                           'visual-line-mode
                         'longlines-mode))

Đôi khi, thay vì kiểm tra tính năng, việc chạy một đoạn mã nhỏ sẽ dễ dàng hơn và bỏ qua mọi lỗi do các hàm không xác định, đối số không hợp lệ, v.v. Đừng làm điều này với số lượng lớn mã, vì điều này sẽ làm cho mã của bạn rất khó gỡ lỗi.

Ví dụ: tôi không muốn xem thanh công cụ. Các phiên bản cũ hơn của Emacs hoàn toàn không có chúng. GNU Emacs và XEmac đã thêm tính năng đó theo nhiều cách khác nhau và biến nó thành mặc định. Đây là cách tôi tắt chúng đi. Các set-specifierchức năng cụ thể để XEmacs, và default-toolbar-visible-plà cụ thể cho các phiên bản gần đây của đủ Emacs; sử dụng condition-casechăm sóc cả hai yêu cầu. GNU Emacs cung cấp một chức năng chuyên dụng vì vậy tôi chỉ kiểm tra xem chức năng đó có khả dụng không.

;; For XEmacs
(condition-case nil
    (set-specifier default-toolbar-visible-p nil)
  (error nil))
;; For GNU Emacs
(if (fboundp 'tool-bar-mode)
    (tool-bar-mode 0))

Một số tên khuôn mặt thay đổi qua các phiên bản. Sử dụng facepđể kiểm tra tính khả dụng của một tên khuôn mặt.

(let ((face (if (facep 'mode-line) 'mode-line 'modeline)))
  (set-face-background face …))

Đôi khi bạn có thể muốn tải một gói đẹp nếu có, và không làm gì nếu gói đó không có sẵn. requirecó một đối số tùy chọn cho điều đó.

(require 'tex-site nil t) ;; Load AUCTeX if available

Đối số này đã được giới thiệu trong GNU Emacs 20.4 và không có sẵn trong XEmac, vì vậy nếu bạn muốn quay lại đó, bạn sẽ phải bọc nó lại condition-casehoặc sử dụng loadthay thế (không kiểm tra các thư viện đã được tải) .

Giới hạn các phụ thuộc phiên bản cho các tính năng cấp người dùng. Không sử dụng các tính năng lập trình mới hơn không có sẵn trong tất cả các phiên bản bạn muốn hỗ trợ: bạn sẽ phải cung cấp phiên bản tương thích cho các phiên bản cũ hơn và việc duy trì một phiên bản duy nhất sẽ dễ dàng hơn.

Đôi khi bạn cần một tính năng ở nhiều nơi và nó có sẵn trên tất cả các triển khai bạn quan tâm, nhưng theo một cách khác. Đây chủ yếu là trường hợp nếu bạn muốn hỗ trợ cả XEmac và GNU Emacs: chúng có xu hướng bực bội khi sao chép các tính năng của nhau nhưng không phải giao diện của chúng. Trong trường hợp này, việc xác định chức năng tương thích sẽ thuận tiện hơn so với thử nghiệm tại điểm sử dụng.

Ví dụ, đoạn mã sau định nghĩa một hàm trả về hệ thống cửa sổ của khung hiện tại, cách GNU hiện đại, cách XEmac hiện đại và cách kiểu cũ khi bạn không thể kết hợp các khung đầu cuối và GUI trong cùng một ví dụ.

(defalias 'compat-window-system
  (cond
   ((fboundp 'window-system) #'window-system)
   ((fboundp 'device-type)
    (lambda (&optional frame)
      (device-type (frame-device frame))))
   (t
    (lambda (&optional frame) window-system))))

Phụ thuộc môi trường

Không có nhiều mã cần phải phụ thuộc vào nền tảng. Biến system-typechỉ ra hệ điều hành. Tôi sử dụng nó để kích hoạt một vài bản hack cho ms-dos(vâng, các tệp của tôi đã cũ) và windows-nt.

Bạn có thể muốn thêm các thư mục vào đường dẫn tìm kiếm thực thi của mình ( PATH), nhưng điều đó thường được thực hiện tốt nhất bên ngoài Emacs, trong .profilehệ thống giống như Unix của bạn và thông qua bảng điều khiển trong Windows. Để kiểm tra xem một chương trình bên ngoài có sẵn hay không, hãy gọi executable-find.

Đối với mã cần hành động khác nhau tùy thuộc vào loại GUI nếu có, hãy kiểm tra window-typehoặc người kế thừa của nó (xem bên trên).

Tập tin khởi tạo

Để tương thích tối đa, đặt mã của bạn vào ~/.emacs. GNU Emac bắt đầu tìm kiếm trong ~/emacs.dphiên bản 22. XEmac bắt đầu tìm kiếm ~/.xemacstrong phiên bản 21.4. Một cách tiếp cận khác là đưa mã tương thích vào ~/.emacsvà kết thúc bằng cách tải tệp chính của bạn. Đặt (setq load-home-init-file t)một nơi nào đó để tránh có các phiên bản gần đây của XEmacs hỏi bạn có muốn di chuyển .emacsđến vị trí chỉ XEmacs không.

Các phiên bản khác nhau của Emacs có thể có sự mở rộng khác nhau và không tương thích đối với một số macro. Vì vậy, đừng chia sẻ các tệp được biên dịch byte của bạn giữa các phiên bản, biên dịch các tệp trên mỗi máy.

Đôi khi một tính năng không được dùng nữa, nhưng bạn vẫn muốn sử dụng nó vì đó là tất cả những gì có trong một phiên bản khác mà bạn muốn hỗ trợ. Các cảnh báo trình biên dịch byte đến từ byte-obsolete-variabletài sản.

(cond
 ((not (boundp 'desktop-enable))
  (defvaralias 'desktop-enable 'desktop-save-mode))
 ((get 'desktop-enable 'byte-obsolete-variable)
  (put 'desktop-enable 'byte-obsolete-variable nil)))

¹ Tương đối nói, so với XEmacs cũ.


6

(Wiki cộng đồng. Vui lòng thêm của bạn!)

  • Nếu có một chức năng, được thêm vào trong phiên bản Emacs mới hơn, mà bạn muốn sử dụng, hãy kiểm tra xem nó có được xác định fboundphay không và xác định chức năng tương thích nếu không được xác định.

    Nó được coi là một ý tưởng tồi để cung cấp cho chức năng tương thích cùng tên với chức năng thực, vì các mã Elisp khác có thể đang sử dụng cùng một fboundpthủ thuật. Do đó, sử dụng tiền tố cho chức năng tương thích và sử dụng defaliascho cùng tên nếu được xác định. Ví dụ:

    (if (fboundp 'propertize)
        (defalias 'my-propertize 'propertize)
      (defun my-propertize (string &rest properties)
        "Return a copy of STRING with text properties added.
    
     [Note: this docstring has been copied from the Emacs 21 version]
    
    First argument is the string to copy.
    Remaining arguments form a sequence of PROPERTY VALUE pairs for text
    properties to add to the result."
        (let ((str (copy-sequence string)))
          (add-text-properties 0 (length str)
                               properties
                               str)
          str)))
    
  • Nếu một số cấu hình chỉ nên áp dụng cho một hệ điều hành nhất định, có một vài khả năng khác nhau. Bạn có thể kiểm tra các system-typebiến, mà lợi nhuận gnu/linux, darwin, windows-ntvà một vài người khác (xem docstring).

    Bạn có thể bị cám dỗ để sử dụng window-system, mặc dù chuỗi doc của nó nói rằng "Sử dụng biến này làm boolean không được dùng nữa" và khuyên bạn nên sử dụng display-graphic-pthay thế. Lưu ý rằng Emacs có thể sử dụng các loại màn hình khác nhau cho các khung hình khác nhau hiện nay (ví dụ: một khung hình trên thiết bị đầu cuối và một khung hình khác trong cửa sổ "phù hợp"), vì vậy điều này có thể gây bất ngờ. Sử dụng current-frame-configurationhoặc get-buffer-window-listtrong elisp của bạn để lựa chọn đúng.

  • Bạn có thể muốn kiểm tra nếu bạn đang chạy theo đúng hương vị của emacs. Sử dụng featurep để kiểm tra các biến thể. Ví dụ:

    (when (featurep 'xemacs)
       (require 'fsf-compat))
    

    Bạn cũng có thể sử dụng nó để kiểm tra các mô-đun cụ thể được tải. Chẳng hạn, nếu bạn chỉ sử dụng một defun nhỏ và dễ xác định defun chung thì bạn có thể chọn xác định thay vì yêu cầu. Ví dụ:

    (unless (featurep 'cl)
       (defun caaar (x)
          "Return the `car' of the `car' of the `car' of X."
          (car (car (car x)))))
    
  • Tránh lưu trữ tập tin .elc. Chúng không tương thích tiến hoặc lùi với giữa một số phiên bản Emacs.


0

Nếu bạn đang sử dụng các chức năng từ cl-libnhưng không muốn sử dụng các phiên bản không được đặt tên không dùng nữa, hãy biến thư viện tương thích cl-lib thành một phụ thuộc của dự án của bạn. Điều đó sẽ cho phép bạn sử dụng các cl-chức năng được đặt tên nhưng vẫn giữ được tính tương thích ngược.


load-library: Không thể mở tệp tải: cl-lib - Tại sao tôi vẫn muốn cl-lib? Nó có lợi thế gì hơn cl, đã có từ ít nhất 20 năm trước?
Gilles 'SO- ngừng trở nên xấu xa'

1
clkhông được chấp nhận và cuối cùng có thể sẽ bị xóa. Sử dụng nó trong mã đã gây ra cảnh báo trình biên dịch byte trong một thời gian khá dài. Tôi nghĩ lý do là họ muốn sử dụng lại một số cltên (như dolist) với các ngữ nghĩa khác nhau.
shosti
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.