ヘルプから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)
法律家、2014年

回答:


2

更新(夜の睡眠後):この回答には大きな欠陥があります。Emacsソースだけでなく、任意の関数view-modeに移動するときに有効になります。これは修正できますが@ 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はlambdahereを使用します。一方(@rationalrevoltで指摘されているようにhelp-functionhelp-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-getbutton-type-put、既存のラムダに転送することを自分でラムダを交換します。
rationalrevolt

@rationalrevolt:いい考えです!(少し壊れやすいようですが、これも壊れやすいと思います。)
コンスタンティン

@rationalrevolt:更新された回答をご覧ください。(コメントに改行を含めることはできないようです...)
コンスタンティン

ありがとう!私は同様のことを試みていましたが、初心者であるelispでしたが、動的バインディングに噛み付き、クロージャーを機能させることができませんでした:)
rationalrevolt 14年

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

(ファイルを作成するの.dir-locals.elではなく)initファイルで完全に指定できる別の方法を使用し、を使用するのではなく、単にファイルを読み取り専用にし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自分自身を使います...)
コンスタンティン14年

私はa find-file-hookread-only-dirslistに基づいて同じことをやっていますが、このアプローチが好きです。
グルカ2014年

これは非常にクリーンなアプローチのように見えます。でも、ちょっとした問題があります。と((nil . ((eval . (view-mode 1)))))にする最も簡単な方法は何かView-quitの助けを介してアクセスバッファを殺しますか?それ以外の場合、を押してソースビューを終了した後q、バッファは遅れたままになり、後でヘルプから同じファイルのソースに再度アクセスしても、ビューモードは開始されません。
のMichałPolitowski

ミハウポリトウスキ:そうです。その事実を組み込むために回答を更新しましたが、回避策はありません。コンスタンティンの(編集された)答えは、を使用するための最良の解決策かもしれませんview-mode
フィル、2014年

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)

これは私の怪物よりも優れていますが、それでも実際には質問と一致しません。Emacsソースだけでなく、を使用view-modeして任意の関数に移動するとオンになりC-h fます。
コンスタンティン

実験的に、ヘルプリンクは実際にはこのフックを実行しません。インタラクティブなfind-THINGコマンドだけがこのフックを利用していて、ヘルプボタンはそれをバイパスしているようです。
フィル、2014年

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に拡張する方法を示す例です。現在のファイルへのパスをいくつかの正規表現と照合し、一致するものがある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)

以下.emacs.d/elpaは、パスが実際には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.