¿Cómo obtener buffers (no solo archivos) para honrar la lista automática de modos?

13

P: ¿cómo puedo obtener nuevos buffers para honrar el mapeo auto-mode-alist?

Al encontrar un archivo , Emacs compara la extensión del archivo auto-mode-alistpara determinar qué modo principal usar para el búfer del archivo. ¿Hay alguna forma de utilizar la información auto-mode-alistpara determinar el modo de un búfer que (todavía) no tiene un archivo asociado?

Es decir: si abro un nuevo búfer cuyo nombre tiene algo parecido a una extensión de archivo, ¿puedo hacer que se abra automáticamente en el modo esperado? Por ejemplo, si tuviera que abrir un nuevo búfer a-new-buffer.elque aún no está asociado con un archivo, quiero que se abra en emacs-lisp-modelugar del modo predeterminado.

Dan
fuente
2
Solo curiosidad: ¿Cuál es el caso de uso? IOW, ¿por qué / cuándo / en qué contexto quieres hacer esto? Normalmente, si desea asociar un búfer con un archivo y, por lo tanto, elegir su modo auto-mode-alist, hace que el búfer " visite " el archivo (y eso se encarga de todo).
Dibujó el
55
Ejemplos de casos de uso típicos para mí son: a) un orgbúfer temporal para probar nuevas funciones en las que estoy escribiendo para su uso org-mode; b) un Rbuffer temporal para hacer algunas manipulaciones estadísticas rápidas y descartables; c) un búfer de texto temporal para componer un correo electrónico. En cada caso, no quiero crear un archivo para visitar, solo quiero un búfer desechable que, sin embargo, se abra en el modo apropiado.
Dan
2
Archivos visitar comandos como C-x C-fno , no " crear un archivo de la visita ". Ese es un malentendido fundamental. Simplemente hacen exactamente lo que estás buscando. Es solamente si y cuando intenta guardar el búfer que un archivo se crea. Si no intenta guardar el búfer, no se crea ningún archivo. Lo que quieres, por lo que entiendo hasta ahora, es "visitar un archivo" (lo que realmente significa abrir un búfer en el modo adecuado).
Dibujó el
8
Al igual que Dan, creo buffers temporales todo el tiempo que no quiero asociar con una ruta de archivo real. Visitar una ruta de archivo falsa funcionaría, pero hay al menos una pequeña cantidad de fricción al elegir un directorio (o aceptar el actual). Podría haber otros efectos secundarios dependiendo del resto de su configuración: ¿Comportamiento de guardado automático? ¿Grupos de buffer o proyectos de proyectiles determinados por ruta? ¿Indicaciones de confirmación de Ido? Dado que los búferes deben tener un nombre de todos modos, usar el nombre para establecer el modo automáticamente para un búfer temporal tiene sentido para mí.
glucas
@Drew, sí, eso tiene sentido y sería la respuesta más simple a esta pregunta. ¿Podría publicarlo como respuesta, por favor? Se merece una actualización.
Dan

Respuestas:

8

Comandos de visita de archivos como C-x C-f no crear un archivo para visitar. Hacen lo que estás buscando.

Solo si y cuando intentas guardar el búfer se crea un archivo .

Si no intenta guardar el búfer, no se crea ningún archivo. Lo que quieres, por lo que entiendo hasta ahora, es " visitar un archivo " (lo que realmente significa abrir un búfer en el modo adecuado).

Dibujó
fuente
44
¿Qué sucede si tiene un dedo hiperactivo que guarda constantemente el archivo actual cada 3 segundos, independientemente de lo que desee?
Malabarba
1
@Malabarba: ¡De hecho, tengo ese dedo! ;-) Tal vez la mayoría de los viejos pedos lo hacen, un hábito recogido cuando las cosas fallaban todo el tiempo. Pero de todos modos, hago lo que sugerí: editar en un búfer de archivos visitados desechable. Si mi memoria muscular hiperactiva se interpone y trata de ahorrar, que así sea: o golpeo npara no guardar o (a menudo) simplemente guardo el búfer. Y luego lanzo el archivo creado ... o no.)
Dibujó el
1
@Malabarba Es exactamente para evitar el desorden de los archivos temporales, que comencé a usar búferes de memoria virtual específicos para el modo principal. Si el scratch merece un archivo, siempre puede guardarlo como uno más tarde.
Kaushal Modi
1
@kaushalmodi: nada en contra de sus búferes específicos de modo, pero un " desorden de archivos temporales " se limpia tan fácilmente como un desorden de búferes . ;-) Y el dedo hiperactivo en un búfer de rasguño específico del modo presenta el mismo problema, presumiblemente, igual que en *scratch*: se le pide que guarde cuando ese dedo golpea automáticamente C-x C-s.
Dibujó
9

Si ha estado usando la solución de Juri Linkov durante años.

Creo búferes temporales con algo así C-x b test.org C-j. El major-modeestá determinado por la extensión del archivo a través de auto-mode-alist.

;; http://thread.gmane.org/gmane.emacs.devel/115520/focus=115794
(setq-default major-mode
              (lambda () (if buffer-file-name
                          (fundamental-mode)
                            (let ((buffer-file-name (buffer-name)))
                          (set-auto-mode)))))

Para probar el efecto puedes probar (prog1 (and (switch-to-buffer "my-new.org") major-mode) (kill-buffer "my-new.org")) => org-mode. En una limpieza, emacs -qla prueba volvería fundamental-mode.

rasmus
fuente
1
Eso es muy inteligente! También es más ordenado que la adviceopción que había estado usando. No estoy seguro de si sigo para qué (prog1...)sirve la parte, pero la (setq-default major-mode ...)parte es bastante agradable.
Dan
1
Siéntase libre de visitar el sitio Emacs de Juri . La prog1prueba solo muestra que obtienes lo esperado major-modeal cambiar a un búfer. Evalúe la setq-defaultparte y ejecute la prueba. Volverá org-mode Sin el setq-defaultvolvería fundamental-mode.
rasmus
Esto es mucho más elegante que mi buffer-list-update-hook. ¡Gracias!
glucas
esta debería ser la respuesta aceptada, ya que en realidad responde la pregunta en lugar de decirnos por qué nos equivocamos al preguntarla :)
Shlomi
6

Descubrí una forma basada en consejos usando ideas que vinieron de los comentarios de @ Drew y la respuesta de @ glucas que registraré aquí en caso de que sean útiles para alguien.

La versión corta: use afterconsejos para consultar si el búfer tiene un nombre de archivo asociado, configure uno temporalmente si no lo tiene, y luego deje que el resto de la set-auto-modemaquinaria se encargue de los detalles. Después de un poco de pruebas (no extensas), parece estar funcionando bien.

Para ido-switch-buffery vainilla switch-to-buffer, los dos consejos serían:

(defadvice ido-switch-buffer (after set-mode activate)
  (unless buffer-file-name
    (let ((buffer-file-name (buffer-name)))
      (set-auto-mode t))))

(defadvice switch-to-buffer (after set-mode activate)
  (unless buffer-file-name
    (let ((buffer-file-name (buffer-name)))
      (set-auto-mode t))))

Considero que esta opción es útil además de find-fileque @Drew levantó porque mis dedos pueden adelantarse a mi cerebro: la memoria muscular a menudo me llevará al territorio de cambio a buffer antes de que se me ocurra completamente find-filelo que necesito. Ahora, ambas opciones están disponibles.

ACTUALIZACIÓN: error pequeño pero potencialmente irritante en el código anterior: volverá a ejecutar el gancho de modo en el búfer cada vez que lo cambie. Lo siguiente le da un nombre de archivo real fuera del /tmpdirectorio y evita ese problema:

(defadvice ido-switch-buffer (after set-mode activate)
  (unless buffer-file-name
    (setq buffer-file-name (concat "/tmp/" (buffer-name)))
    (set-auto-mode t)))
Dan
fuente
Se ve bien y limpia la ruina que mi respuesta había acumulado en un par de iteraciones. :-) Solo repetiré aquí que si no desea establecer una ruta de archivo real por alguna razón, puede usar una variable local de búfer para evitar establecer el modo varias veces.
glucas
5

La set-auto-modefunción establece el modo en función del archivo asociado con un búfer. Aquí hay una función que se establece temporalmente buffer-file-namedesde el nombre del búfer para establecer el modo:

(defun my/set-buffer-mode (buffer &optional again)
  "Set the mode for BUFFER from the name.  
When called repeatedly for the same buffer only set the mode the first
time, unless the optional argument AGAIN is specified.
Does nothing if the buffer is associated with a file."

  (with-current-buffer buffer
    (when again (kill-local-variable 'my/buffer-mode-set))
    (unless (or buffer-file-name 
            (local-variable-p 'my/buffer-mode-set))
      (let ((buffer-file-name (buffer-name)))
        (set-auto-mode t)
        (setq-local my/buffer-mode-set t)))))

Puede ejecutar esto cuando se cambia el nombre de un búfer utilizando consejos:

(defadvice rename-buffer (after my/rename-update-mode activate)
  (my/set-buffer-mode (current-buffer) 'again))

No estoy seguro del mejor lugar para conectar esto para afectar los nuevos buffers. Aquí estoy usando el buffer-list-update-hook, pero eso se llama en más casos de los que necesitamos.

(add-hook 'buffer-list-update-hook
      '(lambda ()
         (my/set-buffer-mode (car (buffer-list)))))
glucas
fuente
La respuesta anterior se ha revisado para tratar algunos problemas. En particular, volví a usar el buffer-list-update-hookporque change-major-mode-hookno se llamaba con el búfer actual esperado. Para el registro, probablemente tenga más sentido aconsejar a su función switch-buffer como lo hace @Dan en su respuesta.
glucas
3

Puede usar buffers * scratch * con el fin de crear buffers temporales que tengan el mismo modo principal que el archivo en el que podría estar trabajando.

Aquí una respuesta de emacs SE que podría resolver su problema:

¿Cómo puedo alternar rápidamente entre un archivo y un búfer * scratch * que tiene el mismo modo principal?

La pregunta y la respuesta mencionadas fueron publicadas por mí. La respuesta en la función hace lo siguiente:

  • Si está trabajando en el modo X mayor en un archivo, al llamar a esta función se crea un nuevo búfer de memoria virtual llamado *scratch-X-mode*si aún no existe, y cambia a este búfer recién creado.
  • Si *scratch-X-mode*ya existe, simplemente cambia a ese búfer.
  • Al volver a llamar a esta función mientras está en ese búfer de memoria virtual, volverá al búfer de archivo en el que estaba trabajando originalmente.
Kaushal Modi
fuente
0

Aquí hay algunas buenas respuestas, pero quería agregar una cosa más. Emacs tiene un montón de características y, a menudo, hay varias formas de hacer algo. Puede agregar etiquetas en la parte superior de cualquier archivo que indiquen a emacs de qué tipo es, independientemente de la extensión. Por ejemplo agregando esto:

# -*-Python-*-

En la parte superior de un archivo se le hará saber a emacs que es un archivo Python incluso sin la .pyextensión. Tenga en cuenta que #al principio de la línea hay un comentario de estilo Python. Para diferentes tipos de archivos puede usar diferentes comentarios. Por ejemplo, para especificar un archivo Lisp que utiliza ;para iniciar una línea de comentarios y establecer el modo en emacs de esta manera:

; -*- mode: Lisp;-*-

Consulte Especificar variables de archivo y Elegir modos de archivo .

jcoffland
fuente
Sí, pero la pregunta aquí es específicamente sobre la creación de un nuevo búfer temporal (por ejemplo, con switch-buffer) y que el modo se configure automáticamente en algo diferente fundamental-mode.
glucas