¿Cómo ingresar al modo de solo lectura al buscar el código fuente de Emacs desde la ayuda?


10

Cuando busco la ayuda de Emacs para las funciones vía C-h f, a menudo quiero echar un vistazo a la implementación de Elisp / C. Quiero ingresar view-modeautomáticamente cuando accedo al código fuente de esta manera para evitar modificaciones innecesarias. ¿Hay algún gancho o función que pueda recomendar para lograr esto?


2
Esto es lo que uso para evitar la modificación accidental de cualquiera de mis archivos que se abren emacs-lisp-modey solo lo hago C-x C-qsi quiero editar el código fuente. (defun set-buffer-read-only () (setq buffer-read-only t)) (add-hook 'emacs-lisp-mode-hook 'set-buffer-read-only)
abogados

Respuestas:


2

Actualización (después de una noche de sueño): esta respuesta tiene una falla importante: se habilita view-modeal navegar a cualquier función, no solo a las fuentes de Emacs. Esto se puede solucionar, pero es mejor usar la respuesta de @phils .

Al hacer C-h f describe-function RETy luego leer el código fuente de la describe-functionque descubrió que crea un "botón" de un tipo especial para los enlaces a las definiciones de funciones: help-function-def.

Correr zrgrepcon esta cadena (" help-function-def") me señaló help-mode.el.gz.

Después de toda esta búsqueda, podemos reemplazar este tipo de botón con el nuestro (tenga en cuenta el comentario en el código):

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

Por lo que puedo decir, no hay ninguna función para agregar consejos: Emacs usa un lambdaaquí. Por otro lado (como lo señaló @rationalrevolt ) se puede reemplazar la help-functionpropiedad del help-function-deftipo de botón:

(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
Creo que puedo intentar usar button-type-gety button-type-putreemplazar el lambda con el mío que reenvía al lambda existente.
racionalrevolt

@rationalrevolt: ¡Buena idea! (Parece un poco frágil, pero supongo que esto también es frágil.)
Constantino

@rationalrevolt: Consulte la respuesta actualizada. (Parece que no puede haber nuevas líneas en los comentarios ...)
Constantine

¡Gracias! Estaba intentando algo similar, pero siendo un novato para elisp, me mordió el enlace dinámico y no pude hacer que mi cierre funcionara :)
racionalrevolt

16

Puede usar variables locales de directorio para hacer que los archivos fuente de Emacs sean de solo lectura de manera predeterminada. (Ver también C-hig (emacs) Directory Variables RET)

Cree un archivo llamado .dir-locals.elen la raíz del árbol de directorios que desea proteger, con el siguiente contenido:

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

Editar: Michał Politowski señala en los comentarios que habilitar view-modede esta manera es problemático, porque cuando descarta el búfer con qél también deshabilita el modo, lo que significa que la próxima vez que visite ese búfer view-modeno estará habilitado.

Edición 2: Constantine ha proporcionado una solución a ese problema en los comentarios a continuación:

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

Esto agrega útilmente una prueba para garantizar que el búfer ya esté visitando un archivo, pero el cambio de clave es el uso de en view-mode-enterlugar de view-mode, ya que el primero toma un EXIT-ACTIONargumento que determina qué hacer cuando qse escribe. En este caso, la acción de salida es matar el búfer, asegurando que la próxima vez que se visite el archivo vuelva a terminar view-mode.

Edición 3: Siguiendo esa ruta, también podemos ver que lo especificado EXIT-ACTIONfinalmente se pasa a la view-mode-exitfunción, y su cadena de documentos nos da una solución 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.

Por lo tanto, podemos usar lo siguiente:

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

Utilizo el enfoque alternativo que puede especificar completamente en su archivo de inicio (en lugar de crear un .dir-locals.elarchivo), y simplemente hago que los archivos sean de solo lectura en lugar de usarlos view-mode. Mi configuración se ve así:

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

Obviamente, puede hacer lo mismo para su directorio elpa y cualquier otro directorio que contenga código fuente de terceros.


¡Excelente! Esto es claramente mejor de lo que se me ocurrió. (¿En qué estaba pensando? Sé sobre .dir-locals.elmí y me uso a mí mismo ...)
Constantino

He estado en la misma línea en base a find-file-hookuna read-only-dirslista, pero me gusta este enfoque.
glucas

Esto parece un enfoque muy limpio. Aunque tengo un problema menor. ((nil . ((eval . (view-mode 1)))))¿ Con cuál es la forma más sencilla de View-quitmatar a los buffers a los que se accede mediante ayuda? De lo contrario, después de salir de la vista de origen presionando q, el búfer se queda atrás y cuando se accede a las fuentes desde el mismo archivo desde la ayuda nuevamente, el modo de vista no se inicia.
Michał Politowski

Michał Politowski: Tienes razón. He actualizado la respuesta para incorporar ese hecho, pero no tengo una solución alternativa. La respuesta de Constantine (editada) puede ser la mejor solución para usar view-mode.
Phil

1
Hoy descubrí que necesito una solución para el problema señalado por @ MichałPolitowski --- y encontré uno: use ((nil . ((eval . (when buffer-file-name (view-mode-enter nil #'kill-buffer))))))(note en (view-mode-enter ...)lugar de (view-mode 1)). De esta manera, presionar qmata el búfer y view-mode se habilita la próxima vez que visite el mismo archivo.
Constantine

0

Creo que todo lo que necesitas es agregar un gancho :

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

Esto es mejor que mi monstruosidad, pero todavía no coincide con la pregunta: se enciende view-modeal navegar a cualquier función usando C-h f, no solo las fuentes de Emacs.
Constantino

Experimentalmente, los enlaces de ayuda en realidad no ejecutan este enlace. Parece que solo los find-THINGcomandos interactivos utilizan este enlace, y los botones de ayuda lo omiten.
Phil

0

Esto no trata su caso específico, sino el caso más general de cambiar view-modecada vez que visita un archivo fuente desde un búfer de ayuda. Lo estoy ofreciendo como una alternativa a la respuesta de @ Constantine, ya que no era legible como comentario.

Parece que originalmente obtuve esto de 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

Aquí hay una solución que funciona para la documentación incorporada y un ejemplo que muestra cómo extenderla a ELPA. Funciona haciendo coincidir la ruta del archivo actual con algunas expresiones regulares y aplicando read-only-modesi alguna de ellas coincide.

Tenga en cuenta que el búfer es de solo lectura si lo visita diredtambién, no solo a través de la ayuda.

Agregué un gancho que se ejecuta después de ingresar emacs-lisp-modeque comprueba si la ruta del archivo coincide /\.el\.gz$/y aplica el modo de solo lectura si lo hace.

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

Aquí hay un ejemplo que también comprueba ELPA, utilizando la heurística de que cualquier ruta que contenga .emacs.d/elpaes en realidad código 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)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.