วิธีการเข้าสู่โหมดดูอย่างเดียวเมื่อเรียกดูซอร์สโค้ด Emacs จากความช่วยเหลือ?


10

เมื่อฉันเรียกดู Emacs ช่วยฟังก์ชั่นผ่านC-h fฉันมักจะมองเข้าไปในการใช้งาน Elisp / C ฉันต้องการป้อนview-modeอัตโนมัติเมื่อฉันเข้าถึงซอร์สโค้ดด้วยวิธีนี้เพื่อหลีกเลี่ยงการแก้ไขที่ไม่จำเป็น มีตะขอหรือฟังก์ชั่นที่ฉันสามารถแนะนำให้ทำสิ่งนี้ได้หรือไม่?


2
นี่คือสิ่งที่ฉันใช้เพื่อป้องกันการดัดแปลงไฟล์ใด ๆ ที่เปิดโดยไม่ตั้งใจemacs-lisp-modeและฉันจะทำC-x C-qถ้าฉันต้องการแก้ไขซอร์สโค้ด (defun set-buffer-read-only () (setq buffer-read-only t)) (add-hook 'emacs-lisp-mode-hook 'set-buffer-read-only)
ฏหมาย

คำตอบ:


2

อัปเดต (หลังจากนอนหลับตอนกลางคืน):คำตอบนี้มีข้อบกพร่องที่สำคัญ: ช่วยให้view-modeเมื่อนำทางไปยังฟังก์ชั่นใด ๆไม่เพียง แต่แหล่ง Emacs นี้สามารถแก้ไขได้ แต่คุณดีกว่าการใช้คำตอบโดย @phils

โดยการทำC-h f describe-function RETแล้วการอ่านรหัสที่มาของdescribe-functionผมค้นพบว่ามันจะสร้าง "ปุ่ม" help-function-defชนิดพิเศษสำหรับการเชื่อมโยงไปยังคำจำกัดความของฟังก์ชั่น:

เล่นzrgrepกับสตริงนี้ (" help-function-def") help-mode.el.gzชี้ให้ฉันไป

หลังจากขุดทั้งหมดนี้ไปรอบ ๆ เราสามารถแทนที่ปุ่มประเภทนี้ด้วยของเราเอง (หมายเหตุความคิดเห็นในรหัส):

(define-button-type 'help-function-def
  :supertype 'help-xref
  'help-function (lambda (fun file)
               (require 'find-func)
               (when (eq file 'C-source)
                 (setq file
                       (help-C-file-name (indirect-function fun) 'fun)))
               ;; Don't use find-function-noselect because it follows
               ;; aliases (which fails for built-in functions).
               (let ((location
                      (find-function-search-for-symbol fun nil file)))
                 (pop-to-buffer (car location))
                 (if (cdr location)
                     (goto-char (cdr location))
                   (message "Unable to find location in file")))
                   (view-mode t)) ; <= new line: enable view-mode
  'help-echo (purecopy "mouse-2, RET: find function's definition"))

เท่าที่ฉันสามารถบอกได้ว่าไม่มีฟังก์ชั่นในการเพิ่มคำแนะนำ: Emacs ใช้lambdaที่นี่ ในทางกลับกัน (ตามที่ระบุโดย@rationalrevolt ) เราสามารถแทนที่help-functionคุณสมบัติของhelp-function-defประเภทปุ่มได้:

(require 'help-mode)
(let ((help-func (button-type-get 'help-function-def 'help-function)))
  (button-type-put 'help-function-def 'help-function
                   `(lambda (func file)
                      (funcall ,help-func func file) (view-mode t))))

1
ฉันคิดว่าฉันสามารถลองใช้button-type-getและbutton-type-putแทนที่แลมบ์ดาด้วยตัวเองซึ่งส่งต่อไปเป็นแลมบ์ดาที่มีอยู่
rationalrevolt

@rationalrevolt: ความคิดที่ดี! (ดูเหมือนว่าจะเปราะบาง แต่ฉันคิดว่ามันก็เปราะบางเช่นกัน)
Constantine

@rationalrevolt: โปรดดูคำตอบที่ปรับปรุงแล้ว (ไม่สามารถขึ้นบรรทัดใหม่ในความคิดเห็นดูเหมือน ... )
Constantine

ขอบคุณ! ผมพยายามที่สิ่งที่คล้ายกัน แต่เป็นมือใหม่ในการ Elisp ฉันถูกกัดโดยแบบไดนามิกที่มีผลผูกพันและไม่สามารถได้รับการปิดการทำงานของฉัน :)
rationalrevolt

16

คุณสามารถใช้ตัวแปรไดเรกทอรีท้องถิ่นเพื่อทำให้ไฟล์ต้นฉบับของ Emacs เป็นแบบอ่านอย่างเดียวโดยค่าเริ่มต้น (ดูเพิ่มเติมที่C-hig (emacs) Directory Variables RET)

สร้างไฟล์ชื่อ.dir-locals.elที่รูทของทรีไดเรกทอรีที่คุณต้องการป้องกันโดยมีเนื้อหาดังต่อไปนี้:

((nil . ((eval . (view-mode 1)))))

แก้ไข: Michał Politowski ชี้ให้เห็นในความคิดเห็นที่การเปิดใช้งานview-modeในลักษณะนี้เป็นปัญหาเพราะเมื่อคุณปิดบัฟเฟอร์ด้วยqมันจะปิดใช้งานโหมดซึ่งหมายความว่าในครั้งต่อไปที่คุณเยี่ยมชมบัฟเฟอร์view-modeนั้นจะไม่เปิดใช้งาน

แก้ไข 2: Constantine ได้มอบวิธีแก้ไขปัญหาดังกล่าวในความคิดเห็นด้านล่าง:

((nil . ((eval . (when buffer-file-name (view-mode-enter nil #'kill-buffer))))))

สิ่งนี้มีประโยชน์เพิ่มการทดสอบเพื่อให้แน่ใจว่าบัฟเฟอร์กำลังเยี่ยมชมไฟล์อยู่แล้ว แต่การเปลี่ยนแปลงที่สำคัญคือการใช้view-mode-enterแทนที่จะview-modeเป็นเพราะก่อนหน้านี้จะมีการEXIT-ACTIONโต้แย้งซึ่งกำหนดว่าจะทำอย่างไรเมื่อqมีการพิมพ์ view-modeในกรณีนี้การกระทำทางออกคือการฆ่าบัฟเฟอร์เพื่อให้มั่นใจว่าครั้งต่อไปที่ไฟล์จะเข้าเยี่ยมชมอีกครั้งจะสิ้นสุดใน

แก้ไข 3:ตามเส้นทางนั้นเราจะเห็นได้ว่าในEXIT-ACTIONที่สุดการส่งผ่านที่ระบุไปยังview-mode-exitฟังก์ชันและ docstring ของมันทำให้เรามีทางเลือกอื่น:

view-no-disable-on-exit is a variable defined in `view.el'.
Its value is nil

Documentation:
If non-nil, View mode "exit" commands don't actually disable View mode.
Instead, these commands just switch buffers or windows.
This is set in certain buffers by specialized features such as help commands
that use View mode automatically.

ดังนั้นเราสามารถใช้สิ่งต่อไปนี้:

((nil . ((eval . (when buffer-file-name
                   (setq-local view-no-disable-on-exit t)
                   (view-mode-enter))))))

ผมใช้วิธีทางเลือกที่คุณสามารถระบุทั้งหมดในแฟ้มของคุณ init (เมื่อเทียบกับการสร้าง.dir-locals.elไฟล์) view-modeและฉันก็ทำให้ไฟล์อ่านอย่างเดียวมากกว่าการใช้ การกำหนดค่าของฉันมีลักษณะเช่นนี้:

;; Emacs
(dir-locals-set-class-variables
 'emacs
 '((nil . ((buffer-read-only . t)
           (show-trailing-whitespace . nil)
           (tab-width . 8)
           (eval . (whitespace-mode -1))))))

(dir-locals-set-directory-class "/usr/local/src/emacs" 'emacs)
(dir-locals-set-directory-class "/usr/local/share/emacs" 'emacs)
(dir-locals-set-directory-class "/usr/share/emacs" 'emacs)

เห็นได้ชัดว่าคุณสามารถทำสิ่งเดียวกันสำหรับไดเรกทอรี elpa ของคุณและไดเรกทอรีอื่น ๆ ที่มีซอร์สโค้ดของบุคคลที่สาม


ที่ดี! เห็นได้ชัดว่าดีกว่าที่ฉันคิดไว้ (ฉันกำลังคิดอะไรอยู่ฉันรู้และใช้.dir-locals.elตัวเอง ... )
คอนสแตนติน

ฉันได้รับบางสิ่งบางอย่างในบรรทัดเดียวกันตามfind-file-hookและread-only-dirsรายการ แต่ฉันชอบวิธีนี้
ลูกัส

ดูเหมือนว่าวิธีการที่สะอาดมาก ฉันมีปัญหาเล็กน้อยหนึ่งอย่าง ด้วย((nil . ((eval . (view-mode 1)))))วิธีที่ง่ายที่สุดที่จะทำให้View-quitฆ่าบัฟเฟอร์เข้าถึงได้ผ่านทางความช่วยเหลือคืออะไร? มิฉะนั้นหลังจากออกจากมุมมองต้นฉบับโดยการกดqบัฟเฟอร์จะอยู่ด้านหลังและเมื่อเข้าถึงภายหลังจากไฟล์เดียวกันจากความช่วยเหลืออีกครั้งโหมดดูจะไม่เริ่มขึ้น
Michał Politowski

Michał Politowski: ใช่แล้ว ฉันได้อัปเดตคำตอบเพื่อรวมข้อเท็จจริงนั้นแล้ว แต่ฉันไม่มีวิธีแก้ไข คอนสแตนติ (แก้ไข) view-modeคำตอบอาจจะเป็นทางออกที่ดีที่สุดสำหรับการใช้
Phils

1
วันนี้ฉันพบว่าฉันต้องการวิธีแก้ปัญหาสำหรับปัญหาที่ชี้ให้เห็นโดย @ MichałPolitowski --- และฉันพบหนึ่ง: ใช้((nil . ((eval . (when buffer-file-name (view-mode-enter nil #'kill-buffer))))))(หมายเหตุ(view-mode-enter ...)แทน(view-mode 1)) วิธีนี้กดqฆ่าบัฟเฟอร์และview-mode มีการเปิดใช้งานครั้งต่อไปที่เราจะไปเยี่ยมไฟล์เดียวกัน
Constantine

0

ฉันคิดว่าสิ่งที่คุณต้องการคือการเพิ่มเบ็ด :

(add-hook 'find-function-after-hook 'view-mode)

นี้ดีกว่าความโหดร้ายของฉัน แต่ก็ยังไม่ตรงกับคำถาม: มันจะเปิดขึ้นview-modeเมื่อนำทางไปยังฟังก์ชั่นใด ๆ ที่ใช้C-h fไม่ใช่แค่แหล่ง Emacs
Constantine

ทดลองลิงก์ช่วยเหลือไม่ได้ใช้เบ็ดนี้ ดูเหมือนว่าเฉพาะfind-THINGคำสั่งเชิงโต้ตอบเท่านั้นที่ใช้เบ็ดนี้และปุ่มวิธีใช้จะข้ามไป
phils

0

นี่ไม่ได้ระบุกรณีและปัญหาของคุณโดยเฉพาะ แต่กรณีทั่วไปมากขึ้นของการสลับไปที่view-modeเมื่อใดก็ตามที่คุณเยี่ยมชมไฟล์ต้นฉบับจากบัฟเฟอร์ความช่วยเหลือ ฉันเสนอเป็นทางเลือกสำหรับคำตอบของ @ Constantine เนื่องจากไม่สามารถอ่านเป็นความคิดเห็นได้

ฉันดูเหมือนว่าฉันเดิมได้นี้จากEmacsWiki

(defadvice find-function-search-for-symbol (after view-function-source last (symbol type library) activate)
  "When visiting function source via Help, switch to view-mode"
  (with-current-buffer (car ad-return-value)
    (view-mode 1)))

(defadvice find-variable-noselect (after view-var-source last (variable &optional file) activate)
  "When visiting variable source via Help, switch to view-mode"
  (with-current-buffer (car ad-return-value)
    (view-mode 1)))

0

ต่อไปนี้เป็นโซลูชันที่ใช้งานได้กับเอกสารในตัวและตัวอย่างที่แสดงวิธีการขยายไปยัง ELPA มันทำงานได้โดยการจับคู่พา ธ ไปยังไฟล์ปัจจุบันกับบาง regexes และนำไปใช้read-only-modeถ้ามันตรงกับ

โปรดทราบว่าบัฟเฟอร์นั้นเป็น read-only-ified หากคุณเยี่ยมชมผ่านdiredเช่นกันไม่ใช่แค่ผ่านความช่วยเหลือ

ฉันเพิ่มตะขอที่รันหลังจากป้อนemacs-lisp-modeแล้วตรวจสอบว่าเส้นทางไปยังไฟล์ตรงกัน/\.el\.gz$/หรือไม่และใช้โหมดอ่านอย่างเดียวหากทำได้

(defun readonly-if-el-gz ()
  (cond
   ((string-match "\\.el\\.gz\\'" (or (buffer-file-name) ""))
    (read-only-mode +1))))

(add-hook 'emacs-lisp-mode-hook 'readonly-if-el-gz)

นี่คือตัวอย่างที่ตรวจสอบ ELPA ด้วยโดยใช้ฮิวริสติกว่าเส้นทางใด ๆ ที่มี.emacs.d/elpaอยู่นั้นเป็นรหัสของ ELPA

(defun readonly-if-internal ()
  (let
      ((name (or (buffer-file-name) "")))
    (cond
     ((string-match "\\.el\\.gz\\'" name) (read-only-mode +1))
     ((string-match "\\.emacs\\.d/elpa" name) (read-only-mode +1)))))

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