Làm cách nào để vào chế độ chỉ xem khi duyệt mã nguồn Emacs từ trợ giúp?


10

Khi tôi duyệt trợ giúp Emacs cho các chức năng thông qua C-h f, tôi thường muốn xem qua triển khai Elisp / C. Tôi muốn nhập view-modetự động khi tôi truy cập mã nguồn theo cách này để tránh sửa đổi không cần thiết. Có một cái móc hoặc chức năng tôi có thể khuyên để thực hiện điều này?


2
Đây là những gì tôi sử dụng để ngăn chặn sự thay đổi ngẫu nhiên của bất kỳ tệp nào của tôi mở emacs-lisp-modevà tôi chỉ làm C-x C-qnếu tôi muốn chỉnh sửa mã nguồn. (defun set-buffer-read-only () (setq buffer-read-only t)) (add-hook 'emacs-lisp-mode-hook 'set-buffer-read-only)
luật

Câu trả lời:


2

Cập nhật (sau một đêm ngủ): Câu trả lời này có một lỗ hổng lớn: nó cho phép view-modekhi điều hướng đến bất kỳ chức năng nào , không chỉ các nguồn Emacs. Điều này có thể được khắc phục, nhưng tốt hơn hết là bạn nên sử dụng câu trả lời của @phils .

Bằng cách thực hiện C-h f describe-function RETvà sau đó đọc mã nguồn của describe-functiontôi phát hiện ra rằng nó tạo ra một "nút" thuộc loại đặc biệt để liên kết đến các định nghĩa hàm : help-function-def.

Chạy zrgrepvới chuỗi này (" help-function-def") chỉ cho tôi help-mode.el.gz.

Sau khi đào tất cả, chúng ta có thể thay thế loại nút này bằng chính nút của mình (lưu ý nhận xét trong mã):

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

Theo như tôi có thể nói không có chức năng để thêm lời khuyên: Emacs sử dụng một lambdaở đây. Mặt khác (như được chỉ ra bởi @rationalrevolt ) người ta có thể thay thế thuộc help-functiontính của help-function-defloại nút:

(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
Tôi nghĩ rằng tôi có thể cố gắng sử dụng button-type-getbutton-type-putthay thế lambda bằng lambda của riêng mình để chuyển sang lambda hiện có.
rationalrevolt

@rationalrevolt: Ý kiến ​​hay! (Có vẻ hơi mong manh, nhưng tôi cho rằng điều này cũng dễ vỡ.)
Constantine

@rationalrevolt: Vui lòng xem câu trả lời cập nhật. (Không thể có dòng mới trong các nhận xét, có vẻ như ...)
Constantine

Cảm ơn! Tôi đã thử một cái gì đó tương tự nhưng là một người mới đến elisp Tôi đã bị cắn bởi ràng buộc năng động và không thể đóng cửa để làm việc :)
rationalrevolt

16

Bạn có thể sử dụng các biến thư mục-cục bộ để làm cho các tệp nguồn của Emacs chỉ đọc theo mặc định. (Xem thêm C-hig (emacs) Directory Variables RET).

Tạo một tệp được gọi .dir-locals.elở thư mục gốc của cây thư mục mà bạn muốn bảo vệ, với các nội dung sau:

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

Chỉnh sửa: Michał Politowski chỉ ra trong các nhận xét cho phép view-modetheo cách này là có vấn đề, bởi vì khi bạn loại bỏ bộ đệm với qnó cũng sẽ vô hiệu hóa chế độ, có nghĩa là lần sau bạn truy cập bộ đệm đó view-modesẽ không được bật.

Chỉnh sửa 2: Constantine đã cung cấp một giải pháp cho vấn đề đó trong các bình luận bên dưới:

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

Điều này hữu ích thêm một bài kiểm tra để đảm bảo rằng bộ đệm đã truy cập một tệp, nhưng thay đổi chính là việc sử dụng view-mode-enterthay vì view-mode, vì trước đây có một EXIT-ACTIONđối số xác định những việc cần làm khi qđược nhập. Trong trường hợp này, hành động thoát là để giết bộ đệm, đảm bảo rằng lần tiếp theo tệp được truy cập, nó sẽ lại kết thúc view-mode.

Chỉnh sửa 3: Theo đường dẫn đó, chúng ta cũng có thể thấy rằng EXIT-ACTIONcuối cùng được chỉ định được truyền cho view-mode-exithàm và chuỗi doc của nó cung cấp cho chúng ta một giải pháp thay thế:

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.

Do đó chúng ta có thể sử dụng như sau:

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

Tôi sử dụng phương pháp thay thế mà bạn có thể chỉ định hoàn toàn trong tệp init của mình (trái ngược với việc tạo .dir-locals.eltệp) và tôi chỉ đơn giản làm cho các tệp chỉ đọc thay vì sử dụng view-mode. Cấu hình của tôi trông như thế này:

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

Rõ ràng bạn có thể làm điều tương tự cho thư mục elpa của mình và bất kỳ thư mục nào khác chứa mã nguồn của bên thứ ba.


Tuyệt quá! Điều này rõ ràng tốt hơn những gì tôi nghĩ ra. (Tôi đã nghĩ gì? Tôi biết và sử dụng .dir-locals.elbản thân mình ...)
Constantine

Tôi đã có một cái gì đó dọc theo cùng một dòng dựa trên một find-file-hookvà một read-only-dirsdanh sách, nhưng tôi thích cách tiếp cận này.
glucas

Đây có vẻ là một cách tiếp cận rất sạch sẽ. Tôi có một vấn đề nhỏ mặc dù. Với ((nil . ((eval . (view-mode 1)))))cách đơn giản nhất để thực hiện View-quittiêu diệt bộ đệm truy cập thông qua trợ giúp là gì? Mặt khác, sau khi thoát khỏi chế độ xem nguồn bằng cách nhấn q, bộ đệm sẽ ở lại phía sau và khi truy cập các nguồn từ cùng một tệp từ chế độ xem trợ giúp lại không được khởi động.
Michał Politowski

Michał Politowski: Đúng vậy. Tôi đã cập nhật câu trả lời để kết hợp thực tế đó, nhưng tôi không có cách giải quyết. Câu trả lời (chỉnh sửa) của Constantine có thể là giải pháp tốt nhất để sử dụng view-mode.
phils

1
Hôm nay tôi đã tìm ra rằng tôi cần một cách giải quyết cho vấn đề được chỉ ra bởi @ MichałPolitowski --- và tôi đã tìm thấy một: sử dụng ((nil . ((eval . (when buffer-file-name (view-mode-enter nil #'kill-buffer))))))(lưu ý (view-mode-enter ...)thay vì (view-mode 1)). Cách này nhấn qgiết chết bộ đệm và view-mode được bật vào lần tới khi tôi truy cập cùng một tệp.
Constantine

0

Tôi nghĩ rằng tất cả những gì bạn cần là thêm một cái móc :

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

Điều này tốt hơn sự quái dị của tôi, nhưng vẫn không thực sự phù hợp với câu hỏi: nó bật view-modekhi điều hướng đến bất kỳ chức năng nào bằng cách sử dụng C-h f, không chỉ các nguồn Emacs.
Constantine

Thực nghiệm, các liên kết trợ giúp không thực sự chạy hook này. Dường như chỉ có các find-THINGlệnh tương tác sử dụng hook này và các nút trợ giúp bỏ qua nó.
phils

0

Điều này không giải quyết trường hợp cụ thể của bạn, nhưng trường hợp chung hơn là chuyển sang view-modebất cứ khi nào bạn truy cập tệp nguồn từ bộ đệm trợ giúp. Tôi đang cung cấp nó như là một thay thế cho câu trả lời của @ Constantine, vì nó không thể đọc được như một bình luận.

Tôi có vẻ như ban đầu tôi đã nhận được điều này từ 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

Đây là một giải pháp hoạt động cho tài liệu tích hợp và một ví dụ cho thấy cách mở rộng nó sang ELPA. Nó hoạt động bằng cách khớp đường dẫn đến tệp hiện tại với một số biểu thức chính quy và áp dụng read-only-modenếu bất kỳ trong số chúng khớp.

Lưu ý rằng bộ đệm là chỉ đọc nếu bạn truy cập nó thông qua dired, không chỉ thông qua trợ giúp.

Tôi đã thêm một hook chạy sau khi vào emacs-lisp-modekiểm tra xem đường dẫn đến tệp có khớp /\.el\.gz$/hay không và áp dụng chế độ chỉ đọc nếu có.

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

Đây là một ví dụ kiểm tra ELPA, bằng cách sử dụng heuristic rằng bất kỳ đường dẫn nào chứa .emacs.d/elpathực sự là mã 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)
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.