ฉันจะสืบทอดจากโหมด prog ขณะที่ยังคงรองรับ emacsen รุ่นเก่าได้อย่างไร


10

ฉันกำลังเขียนโหมดหลักสำหรับภาษาการเขียนโปรแกรม แต่ฉันต้องการสนับสนุน Emacs รุ่นเก่ากว่า prog-modeค่อนข้างใหม่ ฉันต้องการรับช่วงจากprog-modeถ้ามันถูกกำหนด แต่ยังคงทำสิ่งที่เหมาะสมเป็นอย่างอื่น

วิธีที่ดีที่สุดคืออะไร ฉันควรจะdefalias prog-modeใช้ Emacsen รุ่นเก่าหรือว่าจะรบกวนโหมดอื่นหรือไม่หากพวกเขาทำสิ่งเดียวกัน


ฉันต้องการคำแนะนำที่จะเพียงแค่วางสนับสนุนสำหรับ Emacs < 24. prog-modeในความคิดของฉันมันไม่คุ้มค่าความพยายามอีกต่อไปและคุณจะต้องสละคุณสมบัติที่สำคัญมากกว่า โดยเฉพาะอย่างยิ่งคุณจะต้องทนทุกข์ทรมานจากการขาดคำศัพท์
Lunaryorn

ฉันมีส่วนร่วมในโหมด julia และทีมแกนหลักบางคนใช้ Emacsen ที่เก่ากว่าและต้องการให้เราสนับสนุน
Wilfred Hughes

1
@ lunaryorn Emacs 24 ยังใหม่อยู่ Emacs 23 เป็นเวอร์ชั่นปัจจุบันของหลาย OS Emacs 22 ยังคงเป็นปัจจุบันอยู่ไม่กี่คน ไม่ใช่ทุกคนที่จะอัพเกรดซอฟต์แวร์อย่างบ้าคลั่ง การสนับสนุนที่ลดลงสำหรับ Emacs 23 จะ จำกัด คุณให้ผู้ใช้ไม่กี่คนที่กระหายเลือดออกมา
Gilles 'หยุดความชั่วร้าย'

1
มีหลายเหตุผลที่ต้องใช้เวอร์ชั่นเก่าของ Emacs ตัวอย่างเช่นบน Windows Emacs 23 กลายเป็นคนเฉื่อยชาจริงๆดังนั้นฉันจึงเลือกที่จะติดกับ Emacs 22 ที่นั่น
Lindydancer

@Gilles ฉันสงสัยว่ามันเป็นเพียง "ผู้ใช้ไม่กี่คน" Flycheck ไม่เคยได้รับการสนับสนุน Emacs 23 ในสถานที่แรกและกลายเป็นหนึ่งในแพคเกจที่นิยมมากที่สุดใน MELPA กระนั้น ...
lunaryorn

คำตอบ:


11

ด้วยค่าใช้จ่ายของการผูกสัญลักษณ์ระดับบนสุดพิเศษมีวิธีแก้ไขที่เรียบร้อยซึ่งหลีกเลี่ยงการทำซ้ำdefine-derived-modeฟอร์ม:

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

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

ทำงานได้ดีใน Emacs ใด ๆ > = 23. ฉันคิดเรื่องนี้haml-modeเป็นเวลาสองปีที่ผ่านมา IIRC และดูเหมือนว่าจะแพร่กระจายจากที่นั่นไปยังโหมดหลักอื่น ๆ สิ่งสำคัญที่define-derived-modeแมโครทำกับสัญลักษณ์โหมดแม่คือการสร้างรหัสที่เรียกใช้ฟังก์ชัน: ในแง่นี้defaliasทำให้ตัวแปรใหม่เทียบเท่ากับฟังก์ชัน aliased

หนึ่งข้อแม้คือสิ่งนี้อาจสร้างความสับสนderived-mode-pดังนั้นรหัสที่ตรวจสอบเพื่อดูว่าโหมดของคุณมาจากprog-modeอาจทำงานไม่ถูกต้อง ในทางปฏิบัติฉันไม่ได้พบปัญหาใด ๆ : เป็นเรื่องปกติมากขึ้นที่รหัสดังกล่าวจะprog-mode-hookถูกเรียกเข้าซึ่งยังคงทำงานได้

(ในขณะที่ Jorgen ชี้ให้เห็นในความคิดเห็นให้define-derived-modeใช้mode-classคุณสมบัติจากสัญลักษณ์โหมดผู้ปกครองและdefaliasจะไม่คัดลอกในขณะที่เขียนคุณสมบัตินี้ดูเหมือนจะถูกใช้เพื่อspecial-mode )

อัปเดต: วันนี้ฉันขอแนะนำให้ใช้อย่างน้อย Emacs 24 เนื่องจากเวอร์ชั่นเก่าล้าสมัยมานาน


2
เป็นทางออกที่ดี! แค่ข้อแม้: มันใช้งานได้prog-modeแต่จะไม่สามารถใช้ได้กับทุกโหมด define-derived-modeคัดลอกmode-classคุณสมบัติสัญลักษณ์ไปที่โหมดชายน์ defaliasจะไม่โอนคุณสมบัตินี้ หากmode-classเกี่ยวข้องกับกรณีการใช้งานของคุณคุณต้องคัดลอก / ตั้งค่าด้วยตนเอง
Jorgen Schäfer

ขอบคุณสำหรับการจับ Jorgen - ฉันจะต้องขุดไปรอบ ๆ และเรียนรู้เพิ่มเติมเกี่ยวกับสิ่งที่mode-classคุณสมบัติหมายถึง
sanityinc

3

tl; dr: การใช้งานifและฟังก์ชั่น init ของคุณเอง:

(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)))

จากนั้นทำโหมดเริ่มต้นyour-cool-initทั้งหมด

คำอธิบายอีกต่อไป:

ปัญหาคือวิธีการเขียนโหมดหลักอย่างเป็นทางการคือการใช้define-derived-modeมาโคร:

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

สำหรับ Emacsen รุ่นเก่า (อายุ 24 ปี) ช่วงนี้จะหยุดเมื่อprog-modeใด และคุณไม่สามารถใช้(if (fboundp 'prog-mode) ...)ตรงนั้นได้เพราะมาโครคาดหวังสัญลักษณ์สัญพจน์และจะอ้างถึงมันสำหรับคุณในส่วนขยาย

define-derived-modeใช้ผู้ปกครองในหลายวิธี คุณต้องคัดลอกทั้งหมดในนิยามโหมดของคุณเองเพื่อใช้ประโยชน์จากสิ่งเหล่านี้และนั่นก็เป็นเรื่องที่น่าเบื่อและอาจเกิดข้อผิดพลาดได้ง่าย

ดังนั้นวิธีเดียวคือการใช้สองdefine-derived-modeคำสั่งที่แตกต่างกันขึ้นอยู่กับว่าprog-modeมีอยู่หรือไม่ นั่นทำให้คุณมีปัญหาในการเขียนรหัสการเริ่มต้นของคุณสองครั้ง ซึ่งแน่นอนว่าไม่ดีดังนั้นคุณจึงแยกสิ่งนั้นลงในฟังก์ชั่นของตัวเองตามที่อธิบายไว้ข้างต้น

(ทางออกที่ดีที่สุดคือแน่นอนว่าจะลดการรองรับ 23.x และใช้การกำหนดขอบเขตคำศัพท์ แต่ฉันเดาว่าคุณได้พิจารณาแล้วและลบตัวเลือกนั้น :-))


อะไรที่ใกล้เคียงที่สุดกับprog-modeEmacsen รุ่นเก่า? มันจะสมเหตุสมผลไหมที่จะได้มาจากtext-modeหรือfundamental-modeถ้าprog-modeไม่มีอยู่?
Wilfred Hughes

@Jorgen หรือเราสามารถหาโหมดตัวกลางได้fboundpด้วยการใช้define-derived-modeคำสั่งแรก จากนั้นโหมดจริงที่มีความหมายเต็มสามารถหาได้จากโหมดกลางนั้น? วิธีนี้ไม่จำเป็นต้องกำหนดโหมดทั้งหมดสองครั้ง
Kaushal Modi

1
@ WilfredHughes ไม่มีเลย ที่เกิดจากการfundamental-modeเทียบเท่ากับมาจากnil(และแน่นอนdefine-derived-modeแทนที่fundamental-modeด้วยnil) ในขณะที่text-modeไม่เหมาะสมเช่นรหัสโปรแกรมไม่ได้เป็นข้อความ การตั้งค่าเริ่มต้นส่วนใหญ่text-modeไม่สมเหตุสมผลในการตั้งโปรแกรมโหมดนอกความคิดเห็น นี่คือเหตุผลที่prog-modeเปิดตัวใน Emacs 24
Jorgen Schäfer

@kaushalmodi คุณสามารถได้รับโหมดตัวกลาง แต่นั่นยังคงต้องใช้สองdefine-derived-modeคำจำกัดความในifรูปแบบเพียงสำหรับโหมดกลางแทนที่จะเป็นโหมดสุดท้าย คุณจะแทนที่defunฟังก์ชั่นสำหรับ init ด้วย a define-derived-modeสำหรับโหมดสุดท้าย ฉันไม่คิดว่ามันจะเป็นที่ต้องการโดยเฉพาะอย่างยิ่ง นอกจากนี้คุณยังสามารถกำหนดprog-modeตัวเองตามที่คำถามเดิมแนะนำ แต่ก็สามารถสร้างความสับสนให้กับโหมดอื่น ๆ ที่พึ่งพาfboundpการตรวจสอบสถานะของโหมดนั้น
Jorgen Schäfer

ฉันไม่เชื่อว่าdefine-derived-modeจำเป็นต้องมีสองข้อความที่ต่างกัน สองสามปีที่ผ่านมาฉันมาพร้อมกับคำตอบที่ฉันโพสต์เป็นคำตอบที่แยกต่างหากและดูเหมือนว่าจะทำงานได้ดีทั้งใน Emacs 23 และ 24 รหัสเช่นนี้ใช้ในโหมดหลักที่ได้รับความนิยมจำนวนมาก
sanityinc


0

คุณสามารถกำหนดแมโคร wrapper สำหรับการdefine-derived-modeประเมินอาร์กิวเมนต์

(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))

(คำเตือน: ทดสอบเพียงเล็กน้อยเท่านั้น)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.