Quel est le problème avec `find-file-noselect`?

11

Dans une réponse récente de lunaryorn , il a déclaré:

Cependant, je recommande contre la plupart des autres parties d'Org, pour les raisons déjà mentionnées dans les commentaires: il est ancien et plein de pratiques héritées et nuisibles (par exemple, find-file-noselect pour lire les fichiers de manière non interactive).

Quelqu'un peut-il expliquer pourquoi est find-file-noselectune mauvaise idée de lire des fichiers dans les programmes Elisp? Y a-t-il une meilleure façon? Je demande parce que je pensais l'utiliser dans l'un de mes projets.

mbork
la source
Apparemment, il n'y avait pas d' good-practicesétiquette avant; est-ce une bonne idée de l'utiliser?
mbork
Je pense que good-practicescela relèverait de la catégorie des «balises meta», qui est mal vu par SE.
nispio
1
@nispio Je pense que c'est une balise valide, mais nous pouvons bien sûr prendre cela dans la méta.
Malabarba du
1
@nsipio: J'ai parcouru cet article et je ne suis pas d'accord. Mais ce n'est pas moi qui décide. ;-)
mbork

Réponses:

14

TL; DR : Avec find-file-noselectvous n'avez aucun contrôle sur ce qui se passe réellement, et vous pouvez vous retrouver avec des modes mineurs arbitraires activés dans le tampon, selon ce que l'utilisateur a activé dans leur init.el. De plus, le nettoyage est difficile.

Utilisez with-temp-bufferet à la insert-file-contentsplace. Si vous avez besoin de modes majeurs ou mineurs spécifiques dans le tampon, activez-les explicitement . Pour écrire des fichiers, utilisez with-temp-fileplutôt qui, malgré son nom, vous permet d'écrire dans des fichiers arbitraires.

Effets secondaires

find-file-noselecta beaucoup d'effets secondaires, y compris

  • poser des questions de manière interactive (cela seul est un non-usage dans une utilisation non interactive),
  • activation automatique du mode d'affichage pour les fichiers en lecture seule,
  • autrement en mode normal,
  • et en cours d'exécution find-file-hook.

Mode normal lui-même

  • sélectionne automatiquement un mode majeur approprié pour le tampon actuel,
  • exécute tous les crochets correspondants des modes majeur et mineur,
  • et lit toutes les variables locales pour le tampon actuel, c'est-à-dire les variables de fichier et les variables de répertoire, qui peuvent à nouveau poser des questions interactives sur les variables locales dangereuses.

Étant donné que tous les hooks sont exécutés, vous obtenez tous les modes mineurs et les fonctions de hook que l'utilisateur a activés dans leur init.el, ce qui peut tout causer, des inconvénients mineurs (si les modes mineurs indésirables sont activés) aux ravages majeurs (si l'utilisateur a ajouté une fonction de hook qui s'attend à être appelé à partir d'un contexte interactif).

Voir https://github.com/flycheck/flycheck/issues/366 pour un exemple. L'utilisation de a find-file-noselectprovoqué la vérification de la syntaxe d'un fichier de données par Flycheck, et comme cela se produisait lors de l'arrêt d'Emacs, il n'y avait pas de temps pour nettoyer correctement à nouveau, laissant un fichier temporaire derrière.

Nettoyer

Avec find-file-noselectvous devez être extrêmement prudent pour tuer à nouveau le tampon. find-file-noselectne fait pas cela pour vous.

Vous devez vous souvenir du tampon à un certain endroit et utiliser soigneusement unwind-protectpour vous assurer que le tampon est tué même en cas de sorties non locales.

Alternatives

Pour lire des fichiers, utilisez with-temp-bufferet insert-file-contents, qui ne fait que les choses les plus élémentaires, par exemple la conversion du système de codage, mais sans poser de questions, activer les hooks ou configurer des 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 prend soin de bien tuer le tampon temporaire au bout de son corps.

Pour écrire des fichiers, utilisez with-temp-file, qui crée un tampon temporaire et écrit le contenu dans le nom de fichier donné à la fin de son corps:

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

De la section 24.3 du manuel Elisp:

Pour copier le contenu d'un fichier dans un tampon, utilisez la fonction insert-file-contents. (N'utilisez pas la commande insert-filedans un programme Lisp, car cela définit la marque.)

find-file-noselectIl est évident que la recherche dans la documentation Elisp fait bien plus que la simple lecture d'un fichier dans un tampon. Peut-être que les gens qui pensent que l'utilisation de cette fonction est une mauvaise idée réfléchissent aux effets secondaires, éventuellement indésirables,? Je suppose que cela dépend de ce que vous voulez réaliser. Si vous voulez avoir un contenu de tampon aussi propre / intact que possible, ce pourrait être une bonne idée d'utiliser la combinaison ancienne et fidèle with-temp-buffer+ insert-file-contents. Si vous voulez le contenu du tampon d'être aussi proche de ce find-fileproduire, peut - être vous ne voulez utiliser find-file-noselect? Ou peut-être qu'il réfléchissait find-file;)

Mathias Dahl
la source
3
Si quelque chose est fait de manière non interactive, je ne vois aucun scénario dans lequel vous voudriez que "le contenu du tampon soit proche de ce que le fichier de recherche produirait" . find-file est lent car il fait une tonne de choses inutiles, y compris toutes sortes de crochets. La seule "fonctionnalité" de find-file que vous voudrez peut-être est le mode principal, mais alors vous devez simplement l'activer vous-même (vous ne pouvez même pas garantir que find-file activerait le mode que vous voulez de toute façon).
Malabarba du
Malabarba: Si vous avez l'intention que le tampon reste disponible pour l'édition par l'utilisateur, alors vous pouvez très bien imiter le find-fileprocessus.
phils