Як увійти в режим лише перегляду під час перегляду вихідного коду 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: Перегляньте оновлену відповідь. (Не може бути нових рядків у коментарях, здається ...)
Костянтин

Дякую! Я намагався чогось подібного, але будучи новачком до Елісп, мене покусав динамічний зв'язок і не зміг заставити мою роботу закрити :)
раціональте

16

Ви можете використовувати локальні змінні для каталогу, щоб зробити вихідні файли Emacs за замовчуванням лише для читання. (Див. Також C-hig (emacs) Directory Variables RET).

Створіть файл, названий .dir-locals.elу корені дерева каталогів, який ви хочете захистити, із таким вмістом:

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

Редагувати: Michał Politowski вказує в коментарях, що включити view-modeтаким чином проблематично, тому що, коли ви відхиляєте буфер, qвін також вимикає режим, це означає, що наступного разу, коли ви відвідуєте цей буфер view-mode, не буде ввімкнено.

Редагувати 2: Константин вирішив цю проблему в коментарях нижче:

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

Міхал Політовський: Право, ти. Я оновив відповідь, щоб включити цей факт, але у мене немає вирішення. Відповідь Костянтина (відредагована) може бути найкращим рішенням для використання view-mode.
філ

1
Сьогодні я зрозумів, що мені потрібно вирішити проблему, на яку вказував @ MichałPolitowski ---, і знайшов одне: використання ((nil . ((eval . (when buffer-file-name (view-mode-enter nil #'kill-buffer))))))(замітка (view-mode-enter ...)замість (view-mode 1)). Таким чином натискання qвбиває буфер і view-mode його вмикають наступного разу, коли я відвідую той самий файл.
Костянтин

0

Я думаю, що все, що вам потрібно, це додати гачок :

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

Це краще, ніж моє чудовисько, але все-таки не відповідає дійсно питанню: воно вмикається під view-modeчас переходу до будь-якої функції за допомогою C-h f, а не лише джерел Emacs.
Костянтин

Експериментально, довідкові посилання насправді не запускають цей гачок. Схоже, що лише інтерактивні find-THINGкоманди використовують цей гачок, а довідкові кнопки обходять його.
філ

0

Це стосується не вашого конкретного випадку, а більш загального випадку переходу на view-modeкожен раз, коли ви відвідуєте вихідний файл із буфера довідки. Я пропоную це як альтернативу відповіді @ Константина, оскільки її не можна було прочитати як коментар.

Схоже, я спочатку отримав це від 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. Він працює, шляхом зіставлення шляху до поточного файлу проти деяких регулярних виразів та застосування, read-only-modeякщо будь-який з них відповідає.

Зауважте, що буфер ідентифікований лише для читання, якщо ви також відвідуєте його 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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.