Alle geöffneten Puffer zurücksetzen (und Fehler ignorieren)


12

Wenn ich mit git an einem Projekt unter Versionskontrolle arbeite, möchte ich häufig einige Dinge in einer Shell tun, die sich auf viele meiner geöffneten Dateien auswirken, und dann jeden geöffneten Puffer zurücksetzen, um sicherzustellen, dass ich die neue Version nicht versehentlich überfalle mit was auch immer ich offen hatte. Ich weiß, magitdass dies hier hilfreich sein kann, aber ich bin an meinen Workflow in der Shell gewöhnt und möchte ihn vorerst behalten. Stattdessen möchte ich alle geöffneten Puffer zurücksetzen und möglicherweise alle schließen, die nicht mehr vorhanden sind (z. B. aufgrund git checkouteines Zweigs, in dem diese Datei nicht mehr vorhanden ist).

Ich habe den folgenden Elisp-Ausschnitt, den ich aus einer Google-Suche entnommen habe:

(defun revert-all-buffers ()
  "Refreshes all open buffers from their respective files"
  (interactive)
  (let* ((list (buffer-list))
         (buffer (car list)))
    (while buffer
      (when (and (buffer-file-name buffer) 
                 (not (buffer-modified-p buffer)))
        (set-buffer buffer)
        (revert-buffer t t t))
      (setq list (cdr list))
      (setq buffer (car list))))
  (message "Refreshed open files"))

Aber das bricht , wenn es trifft einen Fehler in einem meiner geöffneten Dateien, dh wenn zurückkehrt B1, B2, B3, ..., Bnwährend ein Fehler versucht , zurückzukehren B2verhindert B3- Bnvon rückgängig gemacht werden.

Wie kann ich emacs anweisen, Fehler zu ignorieren, die in diesem Fall auftreten? Ich möchte es nicht verwenden, global-auto-revert-modeda jedes Zurücksetzen einige schwere Aufgaben auslöst, wie z. B. das automatische Vervollständigen und Syntaxprüfen der Datei, wobei Emacs etwa eine Sekunde lang aufgehängt werden.


Welche Art von Fehler verhindert das Zurücksetzen des B2Puffers in Ihrem Beispiel. Ich benutze eine sehr ähnliche Funktion (höchstwahrscheinlich abgeleitet von diesem Snippet) und sie hat gut funktioniert.
Kaushal Modi

@Kaushal: Es scheint, als ob die "Datei nicht mehr existiert" und / oder Fehler, die von Paketen ausgelöst werden, die ich habe, den Puffer erneut ausführen. Meistens ist mir aufgefallen, dass ich nach dem Ausführen immer noch die Meldung "Datei hat sich seit dem letzten Besuch geändert!" Erhalte. amC-x s
Patrick Collins

"file no longer exists".. aha! Meine Version behebt das :) Wird es in Kürze veröffentlichen.
Kaushal Modi

Antworten:


12

Original

Hier ist meine leicht verbesserte Version des Snippets in der Frage. Wenn ich meinen VC-Verlauf überprüfe, bestätige ich, dass das folgende Snippet als das vom OP veröffentlichte Snippet begann. Also zahle ich dem Attribut.

Hier ist der Code, der für mich stabil war:

(defun modi/revert-all-file-buffers ()
  "Refresh all open buffers from their respective files."
  (interactive)
  (let* ((list (buffer-list))
         (buffer (car list)))
    (while buffer
      (let ((filename (buffer-file-name buffer)))
        ;; Revert only buffers containing files, which are not modified;
        ;; do not try to revert non-file buffers like *Messages*.
        (when (and filename
                   (not (buffer-modified-p buffer)))
          (if (file-exists-p filename)
              ;; If the file exists, revert the buffer.
              (with-current-buffer buffer
                (revert-buffer :ignore-auto :noconfirm :preserve-modes))
            ;; If the file doesn't exist, kill the buffer.
            (let (kill-buffer-query-functions) ; No query done when killing buffer
              (kill-buffer buffer)
              (message "Killed non-existing file buffer: %s" filename)))))
      (setq buffer (pop list)))
    (message "Finished reverting buffers containing unmodified files.")))

Aktualisieren

Hier ist eine verbesserte und besser dokumentierte Version von oben, nachdem Sie sich die Lösung von @ Drew angesehen haben .

(defun modi/revert-all-file-buffers ()
  "Refresh all open file buffers without confirmation.
Buffers in modified (not yet saved) state in emacs will not be reverted. They
will be reverted though if they were modified outside emacs.
Buffers visiting files which do not exist any more or are no longer readable
will be killed."
  (interactive)
  (dolist (buf (buffer-list))
    (let ((filename (buffer-file-name buf)))
      ;; Revert only buffers containing files, which are not modified;
      ;; do not try to revert non-file buffers like *Messages*.
      (when (and filename
                 (not (buffer-modified-p buf)))
        (if (file-readable-p filename)
            ;; If the file exists and is readable, revert the buffer.
            (with-current-buffer buf
              (revert-buffer :ignore-auto :noconfirm :preserve-modes))
          ;; Otherwise, kill the buffer.
          (let (kill-buffer-query-functions) ; No query done when killing buffer
            (kill-buffer buf)
            (message "Killed non-existing/unreadable file buffer: %s" filename))))))
  (message "Finished reverting buffers containing unmodified files."))

Referenz


5

Ein weiterer:

(defun revert-all-no-confirm ()
  "Revert all file buffers, without confirmation.
Buffers visiting files that no longer exist are ignored.
Files that are not readable (including do not exist) are ignored.
Other errors while reverting a buffer are reported only as messages."
  (interactive)
  (let (file)
    (dolist (buf  (buffer-list))
      (setq file  (buffer-file-name buf))
      (when (and file  (file-readable-p file))
        (with-current-buffer buf
          (with-demoted-errors "Error: %S" (revert-buffer t t)))))))

Vielen Dank. Ich stehle den dolistStil zu ersetzen carund pop. Lustig, wie Sie Ihre Konfiguration weiter verbessern können, wenn Sie mehr über Elisp erfahren :)
Kaushal Modi

@KaushalModi Deshalb habe ich es teilweise gepostet. ;-)
Drew

1

Ich akzeptierte Kausals Antwort, da sie dem am nächsten kam, was ich wollte, aber ich griff auch nach einem Teil von Drews Lösung. Ich wickelte revert-bufferin with-demoted-errorsund ließ den :preserve-modesParameter so , dass meine Syntaxprüfung würde alle meine offenen Dateien neu analysieren. Ich lasse es auch modifizierte und nicht modifizierte Dateien töten, da ich oft in Schwierigkeiten gerate, wenn ich versehentlich C-x snach dem git checkoutÖffnen einer modifizierten Datei gehe.

Die endgültige Version ist:

(defun revert-all-buffers ()
  "Refresh all open buffers from their respective files."
  (interactive)
  (let* ((list (buffer-list))
         (buffer (car list)))
    (while buffer
      (let ((filename (buffer-file-name buffer)))
        ;; Revert only buffers containing files, which are not modified;
        ;; do not try to revert non-file buffers like *Messages*.
        (when filename
          (if (file-exists-p filename)
              ;; If the file exists, revert the buffer.
              (with-demoted-errors "Error: %S"
                (with-current-buffer buffer
                  (revert-buffer :ignore-auto :noconfirm)))
            ;; If the file doesn't exist, kill the buffer.
            (let (kill-buffer-query-functions) ; No query done when killing buffer
              (kill-buffer buffer)
              (message "Killed non-existing file buffer: %s" buffer))))
        (setq buffer (pop list)))))
  (message "Finished reverting non-file buffers."))

Es wurden Fortschrittsmeldungen hinzugefügt, da dies bei vielen geöffneten Dateien hängen bleiben
ideasman42

1

Ich würde dies mit einem condition-caseoder beheben ignore-errors(Dokumente hier ). Ich weiß nicht genau , was Sie wollen , es zu tun ; Wenn Sie etwas mit Fehlern tun möchten, wenn Sie condition-casedas Ergebnis angeben oder ignore-errorseinfach fortfahren können. So etwas wie:

(defun revert-all-buffers ()
  "Refreshes all open buffers from their respective files"
  (interactive)
  (let* ((list (buffer-list))
         (buffer (car list)))
    (while buffer
      (when (and (buffer-file-name buffer) 
                 (not (buffer-modified-p buffer)))
        (set-buffer buffer)
        (ignore-errors (revert-buffer t t t)))
      (setq list (cdr list))
      (setq buffer (car list))))
  (message "Refreshed open files"))

0

Basierend auf der Antwort von @ Drew mit Ergänzungen:

  • Fortschrittsberichterstattung (da dies bei vielen geöffneten Dateien langsam sein kann) .
  • Löschen Sie den Rückgängig-Status (mit Unterstützung für Pakete, die beim erneuten Laden des Puffers den Rückgängig-Verlauf laden - z . B. Undo-Fu-Sitzung ) .
(defun revert-all-buffers ()
  "Refresh all open buffers from their respective files.

Buffers which no longer exist are closed.

This can be useful when updating or checking out branches outside of Emacs."
  (interactive)
  (let* ((filename-and-buffer-list ;; pairs of (filename, buf)
          (mapcar
           (lambda (buf) (list (buffer-file-name buf) buf))
           (seq-filter 'buffer-file-name (buffer-list))))

         (count (length filename-and-buffer-list))
         (count-final 0)
         (count-close 0)
         (count-error 0)
         ;; Keep text at a fixed width when redrawing.
         (format-count
          (format "%%%dd" (length (number-to-string count))))
         (format-text
          (concat "Reverting [" format-count " of " format-count "] %3d%%: %s"))
         (index 1))

    (message "Begin reverting %d buffers..." count)
    (while filename-and-buffer-list
      (pcase-let ((`(,filename ,buf) (pop filename-and-buffer-list)))
        ;; Revert only buffers containing files, which are not modified;
        ;; do not try to revert non-file buffers such as '*Messages*'.
        (message format-text index count (round (* 100 (/ (float index) count))) filename)
        (if (file-exists-p filename)
            ;; If the file exists, revert the buffer.
            (if (with-demoted-errors "Error: %S"
                  (with-current-buffer buf
                    (let ((no-undo (eq buffer-undo-list t)))

                      ;; Disable during revert.
                      (unless no-undo
                        (setq buffer-undo-list t)
                        (setq pending-undo-list nil))

                      (unwind-protect
                          (revert-buffer :ignore-auto :noconfirm)

                        ;; Enable again (always run).
                        (unless no-undo
                          ;; It's possible a plugin loads undo data from disk,
                          ;; check if this is still unset.
                          (when (and (eq buffer-undo-list t) (null pending-undo-list))
                            (setq buffer-undo-list nil))))))
                  t)
                (setq count-final (1+ count-final))
              (setq count-error (1+ count-error)))

          ;; If the file doesn't exist, kill the buffer.
          (let (kill-buffer-query-functions) ; No query done when killing buffer.
            (message "Closing non-existing file buffer: %s" buf)
            (kill-buffer buf)
            (setq count-close (1+ count-close))))
        (setq index (1+ index))))
    (message
     (concat
      "Finished Revert All: " (format "%d buffer(s)" count-final)
      (if (zerop count-close)
          ""
        (format ", %d closed" count-close))
      (if (zerop count-error)
          ""
        (format ", %d error (see message buffer)" count-error))))))
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.