Come accedere alla modalità di sola visualizzazione durante la navigazione del codice sorgente di Emacs dalla guida?


10

Quando sfoglio la guida di Emacs per le funzioni tramite C-h f, spesso voglio dare un'occhiata all'implementazione di Elisp / C. Voglio inserire view-modeautomaticamente quando accedo al codice sorgente in questo modo per evitare modifiche non necessarie. C'è un gancio o una funzione che posso consigliare di realizzare questo?


2
Ecco cosa uso per impedire la modifica accidentale di uno qualsiasi dei miei file che si aprono emacs-lisp-modee lo faccio solo C-x C-qse voglio modificare il codice sorgente. (defun set-buffer-read-only () (setq buffer-read-only t)) (add-hook 'emacs-lisp-mode-hook 'set-buffer-read-only)
elenco delle leggi

Risposte:


2

Aggiornamento (dopo una notte di sonno): questa risposta ha un grosso difetto: si abilita view-modequando si naviga verso qualsiasi funzione, non solo con le fonti Emacs. Questo può essere risolto, ma è meglio usare la risposta di @phils .

Facendo C-h f describe-function RETe quindi leggere il codice sorgente di describe-functionho scoperto che crea un "bottone" di un tipo speciale per i collegamenti alle definizioni di funzioni: help-function-def.

Correre zrgrepcon questa stringa (" help-function-def") mi ha indicato help-mode.el.gz.

Dopo tutto questo scavare possiamo sostituire questo tipo di pulsante con il nostro (notare il commento nel codice):

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

Per quanto posso dire non c'è alcuna funzione per aggiungere consigli a: Emacs usa un lambdaqui. D'altra parte (come sottolineato da @rationalrevolt ) si può sostituire la help-functionproprietà del help-function-deftipo di pulsante:

(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
Penso di poter provare a usare button-type-gete button-type-putsostituire il lambda con il mio che inoltra al lambda esistente.
rationalrevolt

@rationalrevolt: buona idea! (Sembra un po 'fragile, ma suppongo che anche questo sia fragile.)
Costantino

@rationalrevolt: vedere la risposta aggiornata. (Non può esserci newline nei commenti, sembra ...)
Costantino,

Grazie! Stavo provando qualcosa di simile, ma essendo un principiante in elisp, ero morso dall'associazione dinamica e non riuscivo a far funzionare la mia chiusura :)
rationalrevolt

16

Puoi utilizzare le variabili locali della directory per rendere i file sorgente di Emacs di sola lettura per impostazione predefinita. (Vedi anche C-hig (emacs) Directory Variables RET).

Creare un file chiamato .dir-locals.elnella radice dell'albero delle directory che si desidera proteggere, con i seguenti contenuti:

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

Modifica: Michał Politowski sottolinea nei commenti che abilitare view-modein questo modo è problematico, perché quando si elimina il buffer con qesso disabilita anche la modalità, il che significa che la prossima volta che si visita quel buffer view-modenon sarà abilitato.

Modifica 2: Costantino ha fornito una soluzione a questo problema nei commenti seguenti:

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

Questo aggiunge utilmente un test per assicurarsi che il buffer stia già visitando un file, ma la modifica della chiave è l'uso di view-mode-enterinvece di view-mode, poiché il primo accetta un EXIT-ACTIONargomento che determina cosa fare quando qviene digitato. In questo caso, l'azione di uscita consiste nell'uccidere il buffer, assicurandosi che alla successiva visita del file finisca nuovamente view-mode.

Modifica 3: Seguendo quel percorso, possiamo anche vedere che lo specifico EXIT-ACTIONviene infine passato alla view-mode-exitfunzione e il suo docstring ci offre una soluzione alternativa:

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.

Quindi possiamo usare quanto segue:

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

Uso un approccio alternativo che puoi specificare interamente nel tuo file init (invece di creare un .dir-locals.elfile), e faccio semplicemente i file in sola lettura piuttosto che usare view-mode. La mia configurazione è simile a questa:

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

Ovviamente puoi fare la stessa cosa per la tua directory elpa e qualsiasi altra directory che contiene codice sorgente di terze parti.


Grande! Questo è chiaramente migliore di quello che mi è venuto in mente. (A cosa stavo pensando? Conosco e uso .dir-locals.elme stesso ...)
Costantino,

Sono stato sulla stessa linea in base a un find-file-hooke un read-only-dirselenco, ma mi piace questo approccio.
glucas,

Sembra un approccio molto pulito. Ho un piccolo problema però. Con ((nil . ((eval . (view-mode 1)))))qual è il modo più semplice per fare View-quituccidere i buffer si accede tramite aiuto? Altrimenti, dopo essere uscito dalla vista di origine premendo q, il buffer rimane indietro e quando in seguito si accede alle fonti dallo stesso file dalla modalità di visualizzazione aiuto non viene avviato.
Michał Politowski,

Michał Politowski: Esatto. Ho aggiornato la risposta per incorporare questo fatto, ma non ho una soluzione alternativa. La risposta (modificata) di Costantino potrebbe essere la migliore soluzione per l'uso view-mode.
phils,

1
Oggi ho capito che ho bisogno di una soluzione alternativa per il problema segnalato da @ MichałPolitowski --- e ne ho trovato uno: usa ((nil . ((eval . (when buffer-file-name (view-mode-enter nil #'kill-buffer))))))(nota (view-mode-enter ...)invece di (view-mode 1)). In questo modo premendo si quccide il buffer e view-mode viene abilitato la prossima volta che visito lo stesso file.
Costantino,

0

Penso che tutto ciò che serve sia aggiungere un hook :

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

È meglio della mia mostruosità, ma non corrisponde ancora alla domanda: si accende view-modequando si naviga verso qualsiasi funzione utilizzando C-h f, non solo le fonti Emacs.
Costantino,

Sperimentalmente, i collegamenti di aiuto in realtà non eseguono questo hook. Sembra che solo i find-THINGcomandi interattivi utilizzino questo hook e i pulsanti di aiuto lo bypassino.
phils,

0

Questo non risolve il tuo caso specifico, ma il caso più generale di passare view-modeogni volta che visiti un file sorgente da un buffer della guida. Lo sto offrendo in alternativa alla risposta di @Costantina, poiché non era leggibile come commento.

Sembra che ho originariamente preso questo da 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

Ecco una soluzione che funziona per la documentazione integrata e un esempio che mostra come estenderlo a ELPA. Funziona abbinando il percorso al file corrente con alcune regex e applicando read-only-modese uno di essi corrisponde.

Nota che il buffer è di sola lettura se lo visiti anche attraverso dired, non solo attraverso l'aiuto.

Ho aggiunto un hook che viene eseguito dopo aver inserito emacs-lisp-modeche controlla se il percorso del file corrisponde /\.el\.gz$/e applica la modalità di sola lettura se lo fa.

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

Ecco un esempio che controlla anche ELPA, usando l'euristica che qualsiasi percorso contenente .emacs.d/elpasia in realtà un codice 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.