คืนค่าบัฟเฟอร์ที่เปิดอยู่ทั้งหมด (และละเว้นข้อผิดพลาด)


12

เมื่อทำงานในโครงการภายใต้การควบคุมเวอร์ชันด้วย git ฉันมักจะต้องการทำบางสิ่งในเชลล์ที่ส่งผลกระทบต่อไฟล์ที่เปิดอยู่ของฉันหลาย ๆ ครั้งจากนั้นย้อนกลับบัฟเฟอร์ทุกอันที่ฉันเปิดไว้เพื่อให้แน่ใจว่าฉันจะไม่ปิดบังเวอร์ชันใหม่โดยไม่ตั้งใจ ด้วยสิ่งที่ฉันได้เปิด ฉันรู้ว่าmagitมีประโยชน์ที่นี่ แต่ฉันคุ้นเคยกับเวิร์กโฟลว์ของฉันในเชลล์และฉันต้องการเก็บไว้ใช้ตอนนี้ ดังนั้นฉันต้องการที่จะคืนค่าบัฟเฟอร์ที่เปิดอยู่ทั้งหมดและอาจปิดรายการที่หยุดอยู่แล้ว (เช่นเนื่องจากgit checkoutสาขาที่ไม่มีไฟล์นั้นอีกต่อไป)

ฉันมีตัวอย่างของ elisp ต่อไปนี้ที่ฉันคว้ามาจากการค้นหาของ 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"))

แต่พักนี้ถ้ามันจะกระทบข้อผิดพลาดในหนึ่งเปิดไฟล์ของฉันคือเมื่อย้อนกลับB1, B2, B3, ... , Bnข้อผิดพลาดขณะพยายามที่จะย้อนกลับไปB2ป้องกันB3- Bnจากการหวนกลับ

ฉันจะบอก emac ให้ละเว้นข้อผิดพลาดที่ปรากฏขึ้นในกรณีนี้ได้อย่างไร ฉันไม่ต้องการใช้global-auto-revert-modeเพราะการย้อนกลับแต่ละครั้งก่อให้เกิดสิ่งที่หนักหน่วงเช่นตัวตรวจสอบการเติมข้อมูลอัตโนมัติและตัวตรวจสอบไวยากรณ์ของฉันทำการแยกวิเคราะห์ไฟล์อีกครั้งการแขวน emacs เป็นครั้งที่สอง


ข้อผิดพลาดประเภทใดที่ป้องกันไม่ให้คืนค่าB2บัฟเฟอร์ในตัวอย่างของคุณ ฉันใช้ฟังก์ชั่นที่คล้ายกันมาก (น่าจะมาจากตัวอย่างนี้) และใช้งานได้ดี
Kaushal Modi

@Kaushal: ดูเหมือนว่า "ไม่มีไฟล์" อีกต่อไปแล้วและ / หรือข้อผิดพลาดที่เกิดจากแพคเกจที่ฉันมีการเรียกใช้บัฟเฟอร์ย้อนกลับ ส่วนใหญ่ฉันสังเกตเห็นว่าหลังจากใช้มันฉันจะยังคงได้รับ "ไฟล์มีการเปลี่ยนแปลงตั้งแต่การเยี่ยมชมครั้งล่าสุด!" บนC-x s
Patrick Collins

"file no longer exists".. aha! เวอร์ชันของฉันแก้ไขได้ที่ :) จะโพสต์ในไม่ช้า
Kaushal Modi

คำตอบ:


12

เป็นต้นฉบับ

นี่คือข้อมูลโค้ดที่ได้รับการปรับปรุงเล็กน้อยของฉันในคำถาม ตรวจสอบประวัติ VC ของฉันฉันยืนยันว่าข้อมูลโค้ดด้านล่างเริ่มต้นจากข้อมูลโค้ดที่โพสต์โดย OP ดังนั้นฉันจะจ่ายแอตทริบิวต์ให้

นี่คือรหัสที่เสถียรสำหรับฉัน:

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

ปรับปรุง

นี่คือการปรับปรุงและรุ่นที่ดีขึ้นของเอกสารดังกล่าวข้างต้นหลังจากที่กำลังมองหาที่@ ดึงของ การแก้ปัญหา

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

การอ้างอิง


5

อื่น ๆ :

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

ขอบคุณ ฉันกำลังขโมยdolistสไตล์ที่จะมาแทนที่และcar popตลกวิธีการที่คุณสามารถเก็บในการปรับปรุงการกำหนดค่าของคุณที่คุณได้เรียนรู้มากขึ้น Elisp :)
Kaushal Modi

@KaushalModi นั่นเป็นสาเหตุที่ฉันโพสต์ไว้บางส่วน ;-)
Drew

1

ฉันยอมรับคำตอบของ Kausal เพราะมันใกล้เคียงกับสิ่งที่ฉันต้องการ แต่ฉันก็คว้าส่วนหนึ่งของโซลูชันของ Drew มาด้วย ฉันห่อrevert-bufferในwith-demoted-errorsและทิ้ง:preserve-modesพารามิเตอร์เพื่อให้ตรวจสอบไวยากรณ์ของฉันจะ re-แยกไฟล์ทั้งหมดของฉันเปิด ฉันยังปล่อยให้มันฆ่าไฟล์ที่ถูกดัดแปลงเช่นเดียวกับที่ไม่ได้แก้ไขเนื่องจากฉันมักจะประสบปัญหาโดยบังเอิญC-x sหลังจากgit checkoutเปิดไฟล์ที่แก้ไขแล้วโดยไม่ตั้งใจ

รุ่นสุดท้ายคือ:

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

เพิ่มข้อความความคืบหน้าเนื่องจากสิ่งนี้สามารถปรากฏค้างกับไฟล์หลายไฟล์ที่เปิดอยู่: emacs.stackexchange.com/a/50730/2418
ideasman42

1

ฉันจะแก้ไขด้วยcondition-caseหรือignore-errors(เอกสารที่นี่ ) ผมไม่ทราบว่าสิ่งที่คุณจะต้องการให้ทำ ; หากคุณต้องการทำบางสิ่งที่มีข้อผิดพลาดหากคุณสามารถใช้condition-caseเพื่อระบุผลลัพธ์หรือคุณสามารถใช้ignore-errorsเพื่อดำเนินการต่อ สิ่งที่ต้องการ:

(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

ตามคำตอบของ @ Drew พร้อมส่วนเพิ่มเติม:

  • รายงานความคืบหน้า(ตั้งแต่มันอาจจะช้ากับไฟล์จำนวนมากเปิด)
  • ล้างยกเลิกรัฐ(ด้วยการสนับสนุนสำหรับแพคเกจที่โหลดยกเลิกประวัติศาสตร์เมื่อโหลดบัฟเฟอร์ - ยกเลิก-Fu เซสชั่นสำหรับเช่น)
(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))))))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.