¿Qué hay de malo en `find-file-noselect`?

11

En una respuesta reciente de lunaryorn , declaró:

Sin embargo, recomendaría contra la mayoría de las otras partes de Org, por razones ya mencionadas en los comentarios: es antiguo y está lleno de prácticas heredadas y dañinas (por ejemplo, find-file-noselect para leer archivos de manera no interactiva).

¿Alguien puede explicar por qué es find-file-noselectuna mala idea leer archivos en los programas de Elisp? ¿Hay una mejor manera? Lo pregunto porque estaba pensando en usarlo en uno de mis proyectos.

mbork
fuente
Aparentemente, no había good-practicesetiqueta antes; ¿Es una buena idea usarlo?
mbork
Creo que eso good-practicescaería en la categoría de "metaetiqueta", que está mal visto por SE.
nispio
1
@nispio Creo que es una etiqueta válida, pero podemos llevar esto al meta por supuesto.
Malabarba
1
@nsipio: He leído ese artículo y no estoy de acuerdo. Pero no soy yo quien decide. ;-)
mbork

Respuestas:

14

TL; DR : Con find-file-noselectusted no tiene control sobre lo que realmente sucede, y puede terminar con modos menores arbitrarios habilitados en el búfer, dependiendo de lo que el usuario haya habilitado en ellos init.el. Además, la limpieza es difícil.

Uso with-temp-buffery en su insert-file-contentslugar. Si necesita modos mayores o menores específicos en el búfer, habilítelos explícitamente . Para escribir archivos, use with-temp-fileen su lugar, lo que, a pesar de su nombre, le permite escribir en archivos arbitrarios.

Efectos secundarios

find-file-noselecttiene muchos efectos secundarios, incluidos

  • hacer preguntas de forma interactiva (solo eso es un no-uso en uso no interactivo),
  • habilitación automática del modo de visualización para archivos de solo lectura,
  • entrando en modo normal de lo contrario,
  • y en funcionamiento find-file-hook.

Modo normal en sí

  • selecciona automáticamente un modo principal adecuado para el búfer actual,
  • ejecuta todos los ganchos de modo mayor y menor correspondientes,
  • y lee todas las variables locales para el búfer actual, es decir, las variables de archivo y las variables de directorio, que nuevamente pueden hacer preguntas interactivas sobre variables locales inseguras.

Como todos los ganchos se ejecutan, obtienes todos los modos menores y las funciones de gancho que el usuario habilitó en ellas init.el, lo que puede causar todo, desde inconvenientes menores (si se habilitan modos menores indeseables) hasta estragos mayores (si el usuario agregó una función de gancho que espera ser llamado desde un contexto interactivo).

Consulte https://github.com/flycheck/flycheck/issues/366 para ver un ejemplo. El uso de find-file-noselectprovocó que Flycheck verificara la sintaxis de un archivo de datos, y dado que estaba ocurriendo en el apagado de Emacs, no hubo tiempo para limpiarlo correctamente nuevamente, dejando atrás un archivo temporal.

Limpiar

Con find-file-noselectusted debe tener mucho cuidado para matar el búfer de nuevo. find-file-noselectno hace eso por ti

Debe recordar el búfer en algún lugar y utilizarlo unwind-protectcon cuidado para asegurarse de que el búfer se destruya incluso en el caso de salidas no locales.

Alternativas

Para leer archivos, use with-temp-buffery insert-file-contents, que solo hace las cosas más básicas, por ejemplo, la conversión del sistema de codificación, pero no hace preguntas, habilita enlaces o configura variables locales:

(with-temp-buffer
  (insert-file-contents (locate-user-emacs-file "foo.el"))
  ;; Enter the major mode explicitly
  (emacs-lisp-mode)
  ;; …
  )

with-temp-buffer se encarga de matar adecuadamente el búfer temporal al final de su cuerpo.

Para escribir archivos, use with-temp-file, que crea un búfer temporal y escribe el contenido en el nombre de archivo dado al final de su cuerpo:

(with-temp-file  (locate-user-emacs-file "foo.el")
  (prin1 (list 'my 'data) (current-buffer)))
Lunaryorn
fuente
10

De la sección 24.3 del manual de Elisp:

Para copiar el contenido de un archivo en una memoria intermedia, utilice la función insert-file-contents. (No use el comando insert-fileen un programa Lisp, ya que eso establece la marca).

Buscar en la documentación de Elisp find-file-noselectes obvio que hace mucho más que simplemente leer un archivo en un búfer. ¿Quizás las personas que piensan que usar esta función es una mala idea están pensando en los efectos secundarios, posiblemente no deseados? Supongo que depende de lo que quieras lograr. Si desea tener el contenido de búfer lo más limpio / intacto posible, puede ser una buena idea usar la combinación antigua y confiable with-temp-buffer+ insert-file-contents. Si desea que el contenido del búfer a estar tan cerca de lo que find-fileproducen, tal vez usted no desea utilizar find-file-noselect? O tal vez estaba pensando find-file;)

Mathias Dahl
fuente
3
Si se está haciendo algo de forma no interactiva, no puedo ver ningún escenario en el que desee que "el contenido del búfer esté cerca de lo que produciría el archivo de búsqueda" . find-file es lento porque hace un montón de cosas innecesarias, incluidos todo tipo de ganchos. La única "característica" de find-file que puede desear es el modo mayor, pero debe activarlo usted mismo (ni siquiera puede garantizar que find-file active el modo que desea de todos modos).
Malabarba
Malabarba: si tiene la intención de que el búfer permanezca disponible para que el usuario lo edite, es muy posible que desee imitar el find-fileproceso.
phils