Wie kann ich beim Durchsuchen des Emacs-Quellcodes über die Hilfe in den Nur-Ansicht-Modus wechseln?

10

Wenn ich in der Emacs-Hilfe nach Funktionen über C-h fsuche, möchte ich oft einen Blick in die Elisp / C-Implementierung werfen. Ich möchte view-modeautomatisch eingeben , wenn ich auf diese Weise auf den Quellcode zugreife, um unnötige Änderungen zu vermeiden. Gibt es einen Haken oder eine Funktion, die ich empfehlen kann, um dies zu erreichen?

Rationalrevolt
quelle
2
Hier ist, was ich verwende, um ein versehentliches Ändern einer meiner Dateien zu verhindern, die sich öffnen, emacs-lisp-modeund ich mache es nur, C-x C-qwenn ich den Quellcode bearbeiten möchte. (defun set-buffer-read-only () (setq buffer-read-only t)) (add-hook 'emacs-lisp-mode-hook 'set-buffer-read-only)
Lawlist

Antworten:

2

Update (nach einer Nacht Schlaf): Diese Antwort hat einen großen Fehler: Sie ermöglicht das view-modeNavigieren zu einer beliebigen Funktion, nicht nur zu Emacs-Quellen. Dies kann behoben werden, aber Sie sollten die Antwort von @phils verwenden .

Beim Ausführen C-h f describe-function RETund anschließenden Lesen des Quellcodes von stellte describe-functionich fest, dass eine "Schaltfläche" eines speziellen Typs für Links zu Funktionsdefinitionen erstellt wird : help-function-def.

Das Laufen zrgrepmit dieser Zeichenfolge (" help-function-def") hat mich darauf hingewiesen help-mode.el.gz.

Nach all dem Herumgraben können wir diesen Schaltflächentyp durch unseren eigenen ersetzen (beachten Sie den Kommentar im Code):

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

Soweit ich das beurteilen kann, gibt es keine Funktion, zu der Ratschläge hinzugefügt werden können: Emacs verwendet lambdahier ein. Andererseits kann man (wie von @rationalrevolt hervorgehoben ) die help-functionEigenschaft des help-function-defSchaltflächentyps ersetzen :

(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))))
Konstantin
quelle
1
Ich denke, ich kann versuchen, das Lambda zu verwenden button-type-getund button-type-putdurch mein eigenes zu ersetzen, das an das vorhandene Lambda weitergeleitet wird.
Rationalrevolt
@rationalrevolt: Gute Idee! (Scheint ein bisschen zerbrechlich, aber ich nehme an, das ist auch zerbrechlich.)
Constantine
@rationalrevolt: Bitte beachten Sie die aktualisierte Antwort. (Kann keine Zeilenumbrüche in Kommentaren haben, wie es scheint ...)
Constantine
Vielen Dank! Ich habe etwas Ähnliches versucht, aber als Neuling in Elisp wurde ich von der dynamischen Bindung gebissen und konnte meinen Verschluss nicht zum Laufen bringen :)
Rationalrevolt
16

Sie können verzeichnislokale Variablen verwenden , um die Quelldateien von Emacs standardmäßig schreibgeschützt zu machen. (Siehe auch C-hig (emacs) Directory Variables RET).

Erstellen Sie eine Datei .dir-locals.elmit dem folgenden Inhalt, die im Stammverzeichnis des zu schützenden Verzeichnisbaums aufgerufen wird :

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

Bearbeiten: Michał Politowski weist in den Kommentaren darauf hin, dass das Aktivieren view-modeauf diese Weise problematisch ist, denn wenn Sie den Puffer qdamit schließen, wird auch der Modus deaktiviert, was bedeutet, dass der Puffer beim nächsten Besuch view-modenicht aktiviert wird.

Bearbeiten 2: Constantine hat in den folgenden Kommentaren eine Lösung für dieses Problem bereitgestellt:

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

Dies fügt sinnvollerweise einen Test hinzu, um sicherzustellen, dass der Puffer bereits eine Datei besucht. Die Schlüsseländerung ist jedoch die Verwendung von view-mode-enteranstelle von view-mode, da erstere ein EXIT-ACTIONArgument verwendet, das bestimmt, was zu tun ist, wenn qeingegeben wird. In diesem Fall besteht die Exit-Aktion darin, den Puffer zu beenden und sicherzustellen, dass die Datei beim nächsten Besuch erneut in gespeichert wird view-mode.

Edit 3: Wenn wir diesem Pfad folgen , können wir auch sehen, dass das Angegebene EXIT-ACTIONletztendlich an die view-mode-exitFunktion übergeben wird, und seine Dokumentzeichenfolge gibt uns eine alternative Lösung:

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.

Daher können wir Folgendes verwenden:

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

Ich verwende den alternativen Ansatz, den Sie vollständig in Ihrer Init-Datei angeben können (im Gegensatz zum Erstellen einer .dir-locals.elDatei), und mache die Dateien einfach schreibgeschützt, anstatt sie zu verwenden view-mode. Meine Konfiguration sieht folgendermaßen aus:

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

Natürlich können Sie dasselbe für Ihr elpa-Verzeichnis und jedes andere Verzeichnis tun, das Quellcode von Drittanbietern enthält.

Phils
quelle
Groß! Das ist eindeutig besser als das, was ich mir ausgedacht habe. (Woran habe ich gedacht? Ich weiß über .dir-locals.elmich selbst Bescheid und benutze mich selbst ...)
Konstantin
Ich war etwas in der gleichen Richtung, basierend auf einer find-file-hookund einer read-only-dirsListe, aber ich mag diesen Ansatz.
Glucas
Dies sieht nach einem sehr sauberen Ansatz aus. Ich habe jedoch ein kleines Problem. Mit ((nil . ((eval . (view-mode 1)))))was ist der einfachste Weg , um View-quitdie Puffer über Hilfe zugegriffen zu töten? Andernfalls qbleibt der Puffer nach dem Verlassen der Quellansicht durch Drücken zurück und wenn später über die Hilfe erneut auf Quellen aus derselben Datei zugegriffen wird, wird der Ansichtsmodus nicht gestartet.
Michał Politowski
Michał Politowski: Richtig. Ich habe die Antwort aktualisiert, um diese Tatsache zu berücksichtigen, aber ich habe keine Problemumgehung. Die (bearbeitete) Antwort von Constantine ist möglicherweise die beste Lösung für die Verwendung view-mode.
Phils
1
Heute habe ich herausgefunden, dass ich eine Problemumgehung für das von @ MichałPolitowski aufgezeigte Problem benötige --- und ich habe eine gefunden: use ((nil . ((eval . (when buffer-file-name (view-mode-enter nil #'kill-buffer))))))(note (view-mode-enter ...)anstelle von (view-mode 1)). Auf diese Weise drücken qtötet den Puffer und view-mode wird das nächste Mal besuche ich die gleiche Datei aktiviert.
Constantine
0

Ich denke, alles was Sie brauchen, ist einen Haken hinzuzufügen :

(add-hook 'find-function-after-hook 'view-mode)
sds
quelle
Dies ist besser als meine Monstrosität, entspricht aber immer noch nicht wirklich der Frage: Sie wird aktiviert, view-modewenn Sie zu einer Funktion navigieren C-h f, die nicht nur Emacs-Quellen verwendet.
Konstantin
Experimentell führen die Hilfelinks diesen Hook nicht aus. Es sieht so aus, als würden nur die interaktiven find-THINGBefehle diesen Hook verwenden und die Hilfetasten umgehen ihn.
Phils
0

Dies betrifft nicht Ihren speziellen Fall, sondern den allgemeineren Fall des Wechsels zu, view-modewenn Sie eine Quelldatei aus einem Hilfepuffer besuchen. Ich biete es als Alternative zu @ Constantines Antwort an, da es nicht als Kommentar lesbar war.

Ich sehe so aus, als hätte ich das ursprünglich aus dem EmacsWiki bekommen .

(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)))
Glucas
quelle
0

Hier ist eine Lösung für die integrierte Dokumentation und ein Beispiel für die Erweiterung auf ELPA. Es funktioniert, indem der Pfad zur aktuellen Datei mit einigen regulären Ausdrücken abgeglichen und angewendet wird, read-only-modewenn einer von ihnen übereinstimmt.

Beachten Sie, dass der Puffer schreibgeschützt ist, wenn Sie ihn dirednicht nur über die Hilfe, sondern auch besuchen .

Ich habe einen Hook hinzugefügt, der nach der Eingabe ausgeführt wird und emacs-lisp-modeprüft, ob der Pfad zur Datei übereinstimmt. /\.el\.gz$/Wenn dies der Fall ist, wird der schreibgeschützte Modus angewendet.

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

Hier ist ein Beispiel, das auch ELPA überprüft und dabei die Heuristik verwendet, dass jeder Pfad, der enthält, .emacs.d/elpatatsächlich ELPA-Code ist.

(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)
Gregory Nisbet
quelle