Hoàn nguyên tất cả các bộ đệm mở (và bỏ qua lỗi)


12

Khi làm việc với một dự án dưới sự kiểm soát phiên bản với git, tôi thường muốn thực hiện một số thứ trong trình bao có ảnh hưởng đến nhiều tệp đang mở của mình, sau đó hoàn nguyên mọi bộ đệm mà tôi đã mở để đảm bảo rằng tôi không vô tình làm tắc phiên bản mới với bất cứ điều gì tôi đã mở. Tôi biết magitcó thể hữu ích ở đây, nhưng tôi đã quen với quy trình làm việc của mình trong vỏ và tôi muốn giữ nó ngay bây giờ. Vì vậy, thay vào đó, tôi muốn hoàn nguyên tất cả các bộ đệm đang mở và có thể đóng bất kỳ bộ đệm nào đã ngừng tồn tại (ví dụ: do git checkoutmột nhánh không còn có tệp đó).

Tôi có đoạn trích sau đây mà tôi đã lấy từ một tìm kiếm Google:

(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"))

Nhưng phá vỡ này nếu nó chạm một lỗi trong một file mở của tôi, tức là khi quay trở lại B1, B2, B3, ..., Bnmột lỗi trong khi cố gắng để trở lại B2ngăn chặn B3- Bnkhông bị quay trở.

Làm thế nào tôi có thể nói với emacs để bỏ qua bất kỳ lỗi nào bật lên trong trường hợp này? Tôi không muốn sử dụng global-auto-revert-modevì mỗi lần hoàn nguyên kích hoạt một số nội dung nặng như tự động hoàn thành và trình kiểm tra cú pháp của tôi phân tích lại tệp, treo emacs trong một giây hoặc lâu hơn.


Loại lỗi nào ngăn việc hoàn nguyên B2bộ đệm trong ví dụ của bạn. Tôi sử dụng một chức năng rất giống nhau (rất có thể xuất phát từ đoạn trích này) và nó đã hoạt động tốt.
Kaushal Modi

@Kaushal: có vẻ như "tập tin không còn tồn tại", và / hoặc lỗi được ném bởi các gói tôi có bộ đệm đó chạy lại hoàn nguyên. Hầu như tôi đã nhận thấy rằng sau khi chạy nó, tôi vẫn sẽ nhận được "Tệp đã thay đổi kể từ lần truy cập trước!" vàoC-x s
Patrick Collins

"file no longer exists".. aha! phiên bản của tôi sửa nó :) Sẽ đăng nó trong thời gian ngắn.
Kaushal Modi

Câu trả lời:


12

Nguyên

Đây là phiên bản cải tiến một chút của đoạn trích trong câu hỏi. Xem lại lịch sử VC của tôi, tôi xác nhận rằng đoạn trích dưới đây bắt đầu là đoạn trích được đăng bởi OP. Vì vậy, tôi phải trả thuộc tính cho điều đó.

Đây là mã đã ổn định với tôi:

(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.")))

Cập nhật

Đây là phiên bản cải tiến và được ghi lại tốt hơn ở trên sau khi xem giải pháp của @ Drew .

(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."))

Tài liệu tham khảo


5

Khác:

(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)))))))

Cảm ơn. Tôi đang ăn cắp dolistphong cách để thay thế carpop. Thật hài hước khi bạn có thể tiếp tục cải thiện cấu hình của mình khi bạn tìm hiểu thêm elisp :)
Kaushal Modi

@KaushalModi Đó là lý do tại sao tôi đăng nó, một phần. ;-)
vẽ

1

Tôi đã chấp nhận câu trả lời của Kausal vì nó gần nhất với những gì tôi muốn, nhưng tôi cũng đã nắm được một phần giải pháp của Drew. Tôi được bao bọc revert-buffertrong with-demoted-errorsvà giảm các :preserve-modesthông số để kiểm tra cú pháp của tôi sẽ tái phân tích tất cả các tập tin mở của tôi. Tôi cũng để nó giết các tệp đã sửa đổi cũng như không sửa đổi, vì tôi thường gặp rắc rối do vô tình C-x s-ing sau khi git checkoutmở tệp đã sửa đổi.

Phiên bản cuối cùng là:

(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."))

Đã thêm thông báo tiến trình vì điều này có thể xuất hiện treo với nhiều tệp đang mở: emacs.stackexchange.com/a/50730/2418
ideaman42

1

Tôi sẽ sửa lỗi này bằng một condition-casehoặc ignore-errors(tài liệu ở đây ). Tôi không biết chính xác những gì bạn sẽ muốn nó làm ; nếu bạn muốn làm điều gì đó có lỗi, nếu bạn có thể sử dụng condition-caseđể chỉ định kết quả hoặc bạn có thể sử dụng ignore-errorsđể tiếp tục. Cái gì đó như:

(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

Dựa trên câu trả lời của @ Drew, với các bổ sung:

  • Báo cáo tiến độ (vì nó có thể chậm với nhiều tệp được mở) .
  • Xóa trạng thái hoàn tác (với sự hỗ trợ cho các gói tải lịch sử hoàn tác khi tải lại bộ đệm - ví dụ như hoàn tác phiên làm việc) .
(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)'.
          (let ((temp-list nil))
            (dolist (buf (buffer-list))
              (let ((filename (buffer-file-name buf)))
                (when filename
                  (push (cons filename buf) temp-list))))
            temp-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))))))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.