Comment entrer en mode lecture seule lorsque vous parcourez le code source d'Emacs à partir de l'aide?

10

Lorsque je parcours l'aide d'Emacs pour les fonctions via C-h f, je veux souvent jeter un œil à l'implémentation Elisp / C. Je souhaite entrer view-modeautomatiquement lorsque j'accède au code source de cette façon pour éviter toute modification inutile. Y a-t-il un crochet ou une fonction que je peux conseiller pour accomplir cela?

rationalrevolt
la source
2
Voici ce que j'utilise pour empêcher la modification accidentelle de l'un de mes fichiers qui s'ouvrent emacs-lisp-modeet je fais juste C-x C-qsi je veux modifier le code source. (defun set-buffer-read-only () (setq buffer-read-only t)) (add-hook 'emacs-lisp-mode-hook 'set-buffer-read-only)
lawlist

Réponses:

2

Mise à jour (après une nuit de sommeil): Cette réponse a un défaut majeur: elle permet view-modelors de la navigation vers n'importe quelle fonction, pas seulement les sources Emacs. Cela peut être corrigé, mais il vaut mieux utiliser la réponse de @phils .

En faisant C-h f describe-function RETpuis lire le code source de describe-functionje découvre qu'il crée un « bouton » d'un type spécial pour les liens vers les définitions de fonction: help-function-def.

Courir zrgrepavec cette chaîne (" help-function-def") m'a montré du doigt help-mode.el.gz.

Après toutes ces fouilles, nous pouvons remplacer ce type de bouton par le nôtre (notez le commentaire dans le 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"))

Autant que je sache, il n'y a pas de fonction pour ajouter des conseils: Emacs utilise un lambdaici. En revanche (comme souligné par @rationalrevolt ) on peut remplacer la help-functionpropriété du help-function-deftype de bouton:

(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))))
Constantine
la source
1
Je pense que je peux essayer d'utiliser button-type-getet button-type-putde remplacer le lambda par le mien qui transmet au lambda existant.
rationalrevolt
@rationalrevolt: Bonne idée! (Semble un peu fragile, mais je suppose que c'est aussi fragile.)
Constantine
@rationalrevolt: Veuillez voir la réponse mise à jour. (Il ne peut pas y avoir de nouvelles lignes dans les commentaires, il semble ...)
Constantine
Merci! J'essayais quelque chose de similaire, mais étant un débutant à elisp, j'ai été mordu par la liaison dynamique et je n'ai pas pu faire fonctionner ma fermeture :)
rationalrevolt
16

Vous pouvez utiliser des variables locales de répertoire pour rendre les fichiers source d'Emacs en lecture seule par défaut. (Voir aussi C-hig (emacs) Directory Variables RET).

Créez un fichier appelé .dir-locals.elà la racine de l'arborescence de répertoires que vous souhaitez protéger, avec le contenu suivant:

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

Edit: Michał Politowski souligne dans les commentaires que l'activation view-modede cette manière est problématique, car lorsque vous supprimez le tampon avec lui, qcela désactive également le mode, ce qui signifie que la prochaine fois que vous visiterez ce tampon view-modene sera pas activé.

Edit 2: Constantine a fourni une solution à ce problème dans les commentaires ci-dessous:

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

Cela ajoute utilement un test pour s'assurer que le tampon visite déjà un fichier, mais le changement de clé est l'utilisation de view-mode-enterau lieu de view-mode, car le premier prend un EXIT-ACTIONargument qui détermine ce qu'il faut faire quand il qest tapé. Dans ce cas, l'action de sortie consiste à tuer le tampon, en s'assurant que la prochaine fois que le fichier sera visité, il se retrouvera à nouveau view-mode.

Edit 3: En suivant ce chemin, nous pouvons également voir que le spécifié EXIT-ACTIONest finalement transmis à la view-mode-exitfonction, et sa docstring nous donne une solution alternative:

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.

Par conséquent, nous pouvons utiliser les éléments suivants:

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

J'utilise l'approche alternative que vous pouvez spécifier entièrement dans votre fichier init (par opposition à la création d'un .dir-locals.elfichier), et je fais simplement les fichiers en lecture seule plutôt que d'utiliser view-mode. Ma configuration ressemble à ceci:

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

Évidemment, vous pouvez faire la même chose pour votre répertoire elpa et tout autre répertoire contenant du code source tiers.

phils
la source
Génial! C'est clairement mieux que ce que j'ai imaginé. (À quoi pensais-je? Je me connais et .dir-locals.elje m'utilise ...)
Constantine
J'ai été quelque chose dans le même sens basé sur un find-file-hooket une read-only-dirsliste, mais j'aime cette approche.
glucas
Cela ressemble à une approche très propre. J'ai un problème mineur cependant. Avec ((nil . ((eval . (view-mode 1)))))quel est le moyen le plus simple de faire View-quittuer les tampons accessibles via l'aide? Sinon, après avoir quitté la vue source en appuyant sur q, le tampon reste derrière et lorsque vous accédez ultérieurement aux sources à partir du même fichier à partir de l'aide, le mode d'affichage n'est pas démarré.
Michał Politowski
Michał Politowski: C'est vrai. J'ai mis à jour la réponse pour intégrer ce fait, mais je n'ai pas de solution de contournement. La réponse de Constantine (éditée) peut être la meilleure solution pour l'utiliser view-mode.
phils
1
Aujourd'hui, j'ai compris que j'avais besoin d'une solution de contournement pour le problème signalé par @ MichałPolitowski --- et j'en ai trouvé un: utiliser ((nil . ((eval . (when buffer-file-name (view-mode-enter nil #'kill-buffer))))))(notez (view-mode-enter ...)plutôt que (view-mode 1)). De cette façon, appuyer sur qtue le tampon et view-mode est activé la prochaine fois que je visite le même fichier.
Constantine
0

Je pense que tout ce dont vous avez besoin est d'ajouter un crochet :

(add-hook 'find-function-after-hook 'view-mode)
sds
la source
C'est mieux que ma monstruosité, mais cela ne correspond toujours pas vraiment à la question: il s'allume view-modelors de la navigation vers n'importe quelle fonction utilisant C-h f, pas seulement les sources Emacs.
Constantine
Expérimentalement, les liens d'aide n'exécutent pas réellement ce hook. Il semble que seules les find-THINGcommandes interactives utilisent ce crochet et les boutons d'aide le contournent.
phils
0

Cela ne concerne pas votre cas spécifique, mais le cas plus général de basculer vers view-modechaque fois que vous visitez un fichier source à partir d'un tampon d'aide. Je la propose comme alternative à la réponse de @ Constantine, car elle n'était pas lisible en tant que commentaire.

Il me semble que j'ai obtenu cela à l'origine sur 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)))
glucas
la source
0

Voici une solution qui fonctionne pour la documentation intégrée et un exemple montrant comment l'étendre à ELPA. Il fonctionne en faisant correspondre le chemin d'accès au fichier actuel avec certaines expressions rationnelles et en appliquant read-only-modesi l'un d'eux correspond.

Notez que le tampon est en lecture seule si vous le consultez diredégalement, pas seulement via l'aide.

J'ai ajouté un hook qui s'exécute après la saisie emacs-lisp-modeet vérifie si le chemin d'accès au fichier correspond /\.el\.gz$/, et applique le mode lecture seule dans le cas contraire.

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

Voici un exemple qui vérifie également ELPA, en utilisant l'heuristique que tout chemin contenant .emacs.d/elpaest en fait du code 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)
Gregory Nisbet
la source