Co jest złego w `find-file-noselect`?

11

W niedawnym odpowiedzi przez lunaryorn , stwierdził on:

Odradzałbym jednak większość innych części Organizacji, z powodów już podanych w komentarzach: Jest stary, pełen spuścizny i szkodliwych praktyk (np. Wybierz plik-wybór-nos, aby czytać pliki w sposób nieinteraktywny).

Czy ktoś może wyjaśnić, dlaczego find-file-noselectzłym pomysłem jest odczytywanie plików w programach Elisp? Czy jest lepszy sposób? Pytam, bo myślałem o użyciu go w jednym z moich projektów.

Mbork
źródło
Niby wcześniej nie było good-practicestagu; czy warto go używać?
mbork
Myślę, że good-practicesnależałoby to do kategorii „metatagów”, co jest odrzucone przez SE.
nispio
1
@nispio Myślę, że jest to prawidłowy tag, ale możemy oczywiście przenieść go do meta.
Malabarba
1
@nsipio: Przejrzałem ten artykuł i nie zgadzam się. Ale to nie ja decyduje. ;-)
mbork

Odpowiedzi:

14

TL; DR : Gdy find-file-noselectnie masz kontroli nad tym, co się faktycznie dzieje, możesz skończyć z dowolnymi mniejszymi trybami włączającymi się w buforze, w zależności od tego, co użytkownik w nich włączył init.el. Również czyszczenie jest trudne.

Użyj with-temp-bufferi insert-file-contentszamiast. Jeśli potrzebujesz określonych głównych lub mniejszych trybów w buforze, włącz je jawnie . Aby pisać pliki, użyj with-temp-filezamiast tego, który - pomimo nazwy - pozwala pisać do dowolnych plików.

Skutki uboczne

find-file-noselectma wiele skutków ubocznych, w tym

  • interaktywnie zadawać pytania (to samo w sobie jest nieużywane w nieinteraktywnym użyciu),
  • automatyczne włączanie trybu przeglądania plików tylko do odczytu,
  • wejście w tryb normalny inaczej,
  • i bieganie find-file-hook.

Sam tryb normalny

  • automatycznie wybiera odpowiedni tryb główny dla bieżącego bufora,
  • uruchamia wszystkie odpowiednie zaczepy trybu głównego i pomocniczego,
  • i odczytuje wszystkie zmienne lokalne dla bieżącego bufora, tj. zmienne plikowe i zmienne katalogowe, które ponownie mogą zadawać interaktywne pytania dotyczące niebezpiecznych zmiennych lokalnych.

Ponieważ wszystkie przechwytywania są uruchomione, otrzymujesz wszystkie pomniejsze tryby i funkcje przechwytujące, które użytkownik w nich uruchomił init.el, co może powodować wszystko, od drobnych niedogodności (jeśli włączone są niepożądane tryby pomniejsze) do poważnego spustoszenia (jeśli użytkownik dodał funkcję przechwytującą, która spodziewa się być wywoływanym z kontekstu interaktywnego).

Zobacz https://github.com/flycheck/flycheck/issues/366 dla przykładu. Użycie find-file-noselectpliku Flycheck sprawiło, że plik danych został sprawdzony pod kątem składni, a ponieważ działo się to podczas zamykania Emacsa, nie było czasu na poprawne wyczyszczenie, pozostawiając plik tymczasowy.

Sprzątać

Ze find-file-noselecttrzeba być bardzo ostrożnym, aby ponownie zabić bufor. find-file-noselectnie robi tego dla ciebie.

Musisz pamiętać bufor w pewnym miejscu i ostrożnie go używać, unwind-protectaby upewnić się, że bufor zostanie zabity nawet w przypadku nielokalnych wyjść.

Alternatywy

Aby odczytać pliki, użyj with-temp-bufferi insert-file-contents, który robi tylko najbardziej podstawowe rzeczy, np. Konwersję systemu kodowania, ale nie zadaje pytań, nie włącza haków ani nie konfiguruje zmiennych lokalnych:

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

with-temp-buffer dba o prawidłowe zabicie tymczasowego bufora na końcu jego ciała.

Aby pisać pliki, użyj with-temp-file, który tworzy tymczasowy bufor i zapisuje zawartość pod podaną nazwą pliku na końcu jego treści:

(with-temp-file  (locate-user-emacs-file "foo.el")
  (prin1 (list 'my 'data) (current-buffer)))
księżycowy
źródło
10

Z sekcji 24.3 instrukcji Elisp:

Aby skopiować zawartość pliku do bufora, użyj funkcji insert-file-contents. (Nie używaj polecenia insert-filew programie Lisp, ponieważ ustawia to znak).

Przeszukując dokumentację Elisp find-file-noselect, jest oczywiste, że robi ona znacznie więcej niż tylko odczyt pliku do bufora. Być może ludzie, którzy myślą, że korzystanie z tej funkcji jest złym pomysłem, myślą o potencjalnie niepożądanych skutkach ubocznych? Myślę, że to zależy od tego, co chcesz osiągnąć. Jeśli chcesz mieć możliwie czystą / nietkniętą zawartość bufora, dobrym pomysłem może być użycie starej i sprawdzonej kombinacji with-temp-buffer+ insert-file-contents. Jeśli chcesz, aby zawartość bufora być tak blisko tego, co find-fileprodukują, być może nie chcesz używać find-file-noselect? A może myślał find-file;)

Mathias Dahl
źródło
3
Jeśli coś jest robione nieinteraktywnie, nie widzę żadnego scenariusza, w którym chciałbyś, aby „zawartość bufora była zbliżona do tego, co wytworzyłby plik find” . find-file działa powoli, ponieważ robi mnóstwo niepotrzebnych rzeczy, w tym różnego rodzaju haczyki. Jedyną „funkcją” pliku znalezienia, którego możesz chcieć, jest tryb główny, ale powinieneś po prostu go aktywować (nie możesz nawet zagwarantować, że plik znalezienia włączy tryb, który chcesz).
Malabarba
Malabarba: Jeśli zamierzasz pozostawić bufor do edycji przez użytkownika, możesz bardzo dobrze naśladować ten find-fileproces.
phils