O que há de errado com `find-file-noselect`?

11

Em uma resposta recente de lunaryorn , ele declarou:

No entanto, eu recomendaria contra a maioria das outras partes da organização, por razões já declaradas nos comentários: É antiga e cheia de práticas legadas e prejudiciais (por exemplo, find-file-noselect para ler arquivos de maneira não interativa).

Alguém pode explicar por que é find-file-noselectuma má idéia ler arquivos nos programas Elisp? Existe uma maneira melhor? Estou perguntando, porque eu estava pensando em usá-lo em um dos meus projetos.

mbork
fonte
Aparentemente, não havia good-practicesetiqueta antes; é uma boa ideia usá-lo?
mbork
Eu acho que isso good-practicesse enquadra na categoria "meta tag", que é desaprovada pela SE.
Nispio 30/10/2014
1
@nispio Eu acho que é uma tag válida, mas podemos levar isso para a meta, é claro.
Malabarba 30/10
1
@nsipio: Examinei esse artigo e não concordo. Mas não sou eu quem decide. ;-)
mbork

Respostas:

14

TL; DR : com find-file-noselectvocê não tem controle sobre o que realmente acontece, e você pode acabar com modos secundários arbitrários ativados no buffer, dependendo do que o usuário ativou nos seus init.el. Além disso, a limpeza é difícil.

Use with-temp-buffere em insert-file-contentsvez disso. Se você precisar de modos principais ou secundários específicos no buffer, ative-os explicitamente . Para gravar arquivos, use em with-temp-filevez disso, o qual, apesar do nome, permite gravar em arquivos arbitrários.

Efeitos colaterais

find-file-noselecttem muitos efeitos colaterais, incluindo

  • fazer perguntas interativamente (isso por si só é proibido no uso não interativo),
  • ativar automaticamente o modo de visualização para arquivos somente leitura,
  • entrando no modo normal, caso contrário,
  • e correndo find-file-hook.

Modo Normal em si

  • seleciona automaticamente um modo principal adequado para o buffer atual,
  • executa todos os ganchos correspondentes dos modos principal e secundário,
  • e lê todas as variáveis ​​locais para o buffer atual, ou seja, variáveis ​​de arquivo e variáveis ​​de diretório, que novamente podem fazer perguntas interativas sobre variáveis ​​locais inseguras.

Como todos os ganchos são executados, você obtém todos os modos secundários e funções de gancho ativados pelo usuário init.el, o que pode causar tudo, desde pequenos inconvenientes (se modos secundários indesejáveis ​​estão ativados) a grandes estragos (se o usuário adicionou uma função de gancho que espera ser chamado de um contexto interativo).

Consulte https://github.com/flycheck/flycheck/issues/366 para obter um exemplo. O uso de find-file-noselectcausou a verificação de sintaxe de um arquivo de dados pelo Flycheck e, como estava acontecendo no desligamento do Emacs, não havia tempo para limpar adequadamente novamente, deixando um arquivo temporário para trás.

Limpar

Com find-file-noselectvocê precisa ter cuidado extra para matar o buffer novamente. find-file-noselectnão faz isso por você.

Você precisa se lembrar do buffer em algum lugar e usá unwind-protect-lo com cuidado para garantir que o buffer seja morto, mesmo no caso de saídas não locais.

Alternativas

Para ler arquivos, use with-temp-buffere insert-file-contents, que faz apenas as coisas mais básicas, por exemplo, conversão do sistema de codificação, mas não faz perguntas, ativa ganchos ou configura variáveis ​​locais:

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

with-temp-buffer cuida para matar adequadamente o buffer temporário no final de seu corpo.

Para gravar arquivos, use with-temp-file, o que cria um buffer temporário e grava o conteúdo no nome do arquivo especificado no final do corpo:

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

Na seção 24.3 do manual Elisp:

Para copiar o conteúdo de um arquivo em um buffer, use a função insert-file-contents. (Não use o comando insert-fileem um programa Lisp, pois isso define a marca.)

Pesquisando na documentação do Elisp find-file-noselect, é óbvio que ele faz muito mais do que apenas ler um arquivo em um buffer. Talvez as pessoas que acham que usar essa função seja uma má idéia estejam pensando nos efeitos colaterais possivelmente indesejados? Eu acho que depende do que você deseja alcançar. Se você deseja ter o conteúdo do buffer o mais limpo / intocado possível, pode ser uma boa ideia usar a combinação antiga e confiável with-temp-buffer+ insert-file-contents. Se você quiser o conteúdo do buffer para ser tão perto do que find-fileproduzir, talvez você não quiser usar find-file-noselect? Ou talvez ele estivesse pensando find-file;)

Mathias Dahl
fonte
3
Se algo está sendo feito de maneira não interativa, não consigo ver nenhum cenário em que você deseje "que o conteúdo do buffer esteja próximo do que o arquivo find produziria" . O find-file é lento porque faz uma tonelada de coisas desnecessárias, incluindo todos os tipos de ganchos. O único "recurso" do arquivo find que você pode querer é o modo principal, mas você deve ativá-lo (você não pode garantir que o arquivo find ativaria o modo que você deseja).
Malabarba 30/10
Malabarba: Se você pretende que o buffer permaneça disponível para edição pelo usuário, é possível que você imite o find-fileprocesso.
Phll