Làm cách nào để tôi kế thừa từ chế độ prog, trong khi vẫn hỗ trợ emacsen cũ hơn?


10

Tôi đang viết một chế độ chính cho ngôn ngữ lập trình, nhưng tôi muốn hỗ trợ các phiên bản Emacs cũ hơn. prog-modelà tương đối mới. Tôi muốn thừa kế từ prog-modenếu nó được xác định, nhưng vẫn làm điều gì đó hợp lý.

Cách tiếp cận tốt nhất là gì? Tôi có nên sử dụng defalias prog-modeEmacsen cũ hơn hay sẽ can thiệp vào các chế độ khác nếu chúng làm điều tương tự?


Tôi khuyên bạn chỉ nên bỏ hỗ trợ cho Emacs <24. Theo tôi, nó không còn đáng để nỗ lực nữa và bạn sẽ phải từ bỏ nhiều tính năng quan trọng hơn prog-mode. Đáng chú ý, bạn sẽ bị thiếu sự ràng buộc từ vựng.
lunaryorn

Tôi đang đóng góp cho chế độ julia và một số nhóm nòng cốt sử dụng Emacsen cũ hơn và muốn chúng tôi hỗ trợ nó.
Wilfred Hughes

1
@lunaryorn Emacs 24 vẫn còn khá mới. Emacs 23 là phiên bản hiện tại trên nhiều HĐH. Emacs 22 vẫn còn hiện hành trên một vài. Không phải ai cũng nâng cấp phần mềm của mình như điên. Giảm hỗ trợ cho Emacs 23 sẽ giới hạn bạn trong số ít người dùng khao khát sự cạnh tranh.
Gilles 'SO- ngừng trở nên xấu xa'

1
Có nhiều lý do để sử dụng các phiên bản Emacs cũ hơn. Ví dụ, trên Windows, Emacs 23 trở nên chậm chạp, vì vậy tôi đã chọn gắn bó với Emacs 22 ở đó.
Lindydancer

@Gilles Tôi nghi ngờ rằng đó chỉ là "một vài người dùng". Flycheck không bao giờ hỗ trợ Emacs 23 ngay từ đầu và trở thành một trong những gói phổ biến nhất trên MELPA dù sao cũng là
Lân

Câu trả lời:


11

Với chi phí của một ràng buộc biểu tượng cấp cao nhất, có một giải pháp rất gọn gàng tránh lặp lại define-derived-modebiểu mẫu:

(defalias 'my-fancy-parent-mode
  (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))

(define-derived-mode my-fancy-mode my-fancy-parent-mode
   ...)

Hoạt động tốt trong mọi Emacs> = 23. Tôi đã nghĩ ra điều này trong haml-modemột vài năm trước IIRC và dường như nó đã lan rộng từ đó sang một vài chế độ chính khác. Điều chính mà define-derived-modemacro thực hiện với biểu tượng chế độ cha là tạo mã gọi hàm của nó: theo nghĩa này, defaliaslàm cho biến mới chính xác tương đương với hàm bí danh.

Một lưu ý là điều này có thể gây nhầm lẫn derived-mode-p, vì vậy mã kiểm tra xem chế độ của bạn có nguồn gốc từ prog-modecó thể không hoạt động chính xác không. Trong thực tế, tôi không gặp phải bất kỳ vấn đề nào: thông thường hơn là mã đó được nối vào prog-mode-hook, mã này vẫn được chạy.

(Như Jorgen chỉ ra trong các bình luận, define-derived-modecũng sử dụng thuộc mode-classtính từ biểu tượng chế độ cha mẹ và defaliassẽ không sao chép nó. Tại thời điểm viết, thuộc tính này dường như chỉ được sử dụng chospecial-mode .)

Cập nhật: những ngày này tôi chỉ đơn giản đề nghị yêu cầu ít nhất là Emacs 24, vì các phiên bản cũ đã lỗi thời.


2
Giải pháp tốt đẹp! Chỉ là một cảnh báo: Điều này hoạt động prog-mode, nhưng sẽ không hoạt động cho mọi chế độ. define-derived-modesao chép thuộc tính mode-classký hiệu sang chế độ con. Các defaliassẽ không chuyển thuộc tính này. Nếu mode-classcó liên quan đến trường hợp sử dụng của bạn, bạn cần sao chép / thiết lập thủ công.
Jorgen Schäfer

Cảm ơn vì đã nắm bắt được điều đó, Jorgen - tôi sẽ phải tìm hiểu thêm và tìm hiểu thêm về những gì mode-classtài sản biểu thị.
sanityinc

3

tl; dr: Sử dụng ifvà chức năng init của riêng bạn:

(if (fboundp 'prog-mode)
    (define-derived-mode your-cool-mode prog-mode "Cool"
      "Docstring"
      (your-cool--init))
  (define-derived-mode your-cool-mode nil "Cool"
    "Docstring"
    (your-cool--init)))

Sau đó thực hiện tất cả các khởi tạo chế độ trong your-cool-init.

Giải thích dài hơn:

Vấn đề là cách chính thức để viết một chế độ chính xuất phát là sử dụng define-derived-modemacro:

(define-derived-mode your-cool-mode prog-mode ...)

Trên Emacsen cũ (trước 24), điều này sẽ phá vỡ khi prog-mode. Và bạn không thể sử dụng (if (fboundp 'prog-mode) ...)ở đó vì macro mong đợi một biểu tượng bằng chữ và sẽ trích dẫn nó cho bạn trong bản mở rộng.

define-derived-modesử dụng cha mẹ trong vô số cách. Bạn cần sao chép tất cả những thứ trong định nghĩa chế độ của riêng bạn để sử dụng chúng, và điều đó vừa tẻ nhạt vừa dễ bị lỗi.

Vì vậy, cách duy nhất là sử dụng hai define-derived-modecâu lệnh khác nhau , tùy thuộc vào việc có prog-modetồn tại hay không. Điều đó khiến bạn gặp phải vấn đề viết mã khởi tạo hai lần. Điều này tất nhiên là xấu, vì vậy bạn trích xuất nó vào chức năng của chính nó, như được mô tả ở trên.

(Tất nhiên, giải pháp tốt nhất là bỏ hỗ trợ cho 23.x và sử dụng phạm vi từ vựng. Nhưng tôi đoán bạn đã xem xét và bỏ tùy chọn đó. :-))


Những gì gần nhất tương đương với prog-modeEmacsen cũ? Nó có ý nghĩa để bắt nguồn từ text-modehoặc fundamental-modenếu prog-modekhông có sẵn?
Wilfred Hughes

@Jorgen Hoặc chúng ta có thể rút ra một chế độ trung gian bằng cách sử dụng fboundpđầu tiên, chỉ với define-derived-modetuyên bố? Vậy thì chế độ thực tế với định nghĩa đầy đủ có thể bắt nguồn từ chế độ trung gian đó? Bằng cách đó, toàn bộ chế độ không phải được xác định hai lần.
Kaushal Modi

1
@WilfredHughes, không có. Xuất phát từ fundamental-modetương đương với xuất phát từ nil(và thực tế, define-derived-modethay thế fundamental-modebằng nil), trong khi text-modekhông phù hợp, vì mã chương trình không phải là văn bản. Hầu hết các cài đặt mặc định text-modekhông có ý nghĩa trong các chế độ lập trình bên ngoài các bình luận. Đây là lý do tại sao prog-modeđược giới thiệu trong Emacs 24.
Jorgen Schäfer

@kaushalmodi, bạn có thể rút ra một chế độ trung gian, nhưng điều đó vẫn sẽ yêu cầu hai define-derived-modeđịnh nghĩa trong một ifbiểu mẫu, chỉ dành cho chế độ trung gian thay vì chế độ cuối cùng. Bạn sẽ thay thế defunchức năng init bằng define-derived-modechế độ cuối cùng. Tôi không nghĩ rằng điều này là đặc biệt thích hợp. Bạn cũng có thể tự xác định prog-mode, như câu hỏi ban đầu cho thấy, nhưng điều đó có thể dễ dàng nhầm lẫn các chế độ khác dựa vào fboundpđể kiểm tra sự hiện diện của chế độ đó.
Jorgen Schäfer

Tôi không tin rằng hai define-derived-modetuyên bố khác nhau là cần thiết. Một vài năm trước tôi đã đưa ra giải pháp tôi đã đăng dưới dạng một câu trả lời riêng biệt và dường như nó hoạt động tốt trong cả Emacs 23 & 24. Mã giống như nó được sử dụng trong một số chế độ chính phổ biến.
sanityinc

0

Tôi nghĩ rằng thử nghiệm sử dụng fboundpcó ý nghĩa hơn.

(if (fboundp 'prog-mode)
    ...
   ...)

0

Bạn có thể xác định một macro trình bao bọc để define-derived-modeđánh giá các đối số của nó.

(defmacro define-derived-mode* (child parent name &optional docstring &rest body)
  (macroexpand `(define-derived-mode ,(eval child) ,(eval parent) ,(eval name)
                                     ,(eval docstring) . ,body)))
(define-derived-mode* 'toy-mode
  (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode)
  "Toy"
  "Major mode for my favorite toy language"
  (toy-mode-setup))

(Cảnh báo: chỉ được thử nghiệm tối thiểu.)

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.