Cách xử lý lỗi một cách duyên dáng trong tệp init


20

Tôi muốn một cách để bắt lỗi khi chạy tệp init của tôi, và sau đó xử lý chúng một cách duyên dáng. Rất nhiều tùy chỉnh và keybindings quan trọng nhất của tôi hiển thị ở cuối tệp init của tôi để đảm bảo rằng các cài đặt khác không được áp dụng trên đầu chúng. Vấn đề là khi khởi tạo hủy bỏ sớm, tôi cảm thấy hoàn toàn tê liệt khi cố gắng gỡ lỗi mà không áp dụng các ràng buộc và cài đặt khóa quen thuộc.

Có cách nào để kết thúc quá trình khởi tạo một cách duyên dáng khi xảy ra lỗi không?

Câu trả lời:


9

Hai lựa chọn, không phải là hoàn hảo, đến với tâm trí. Đầu tiên, bạn có thể gói hầu hết mã khởi tạo sớm của mình (nghĩa là trước khi nó được tùy chỉnh) (ignore-errors ...). Nếu có những sai sót, tuy nhiên, sẽ không có nhiều thông tin phản hồi - ignore-errorschỉ đơn giản là sẽ trở lại nil.

Một tùy chọn phức tạp hơn sẽ là bọc mã có khả năng bị lỗi trong sự kết hợp của unwind-protectwith-demoted-errors( debug-on-errorđược đặt thành không). Cái sau sẽ báo lỗi một cách duyên dáng ở lỗi đầu tiên nó gặp phải và báo cáo thông báo lỗi cho *Messages*bộ đệm để bạn kiểm tra. Trong khi đó, phần còn lại của unwind-protectcơ thể (có lẽ là các tùy chỉnh của bạn) sẽ được đánh giá. Vì vậy, ví dụ:

(unwind-protect
    (let ((debug-on-error nil))
      (with-demoted-errors
        (message "The world is about to end")
        (sleep-for 2)
        (/ 10 0)                        ; divide by zero signals an error
        (message "This will never evaluate")
        (sleep-for 2)
        (setq some-var 5)))
  (message "Here are the unwind forms that will always evaluate")
  (sleep-for 2)
  (setq some-var 10)
  (setq another-var "puppies")
  (message "All done!"))

1
Đẹp, tôi đã không về with-demoted-errors. Bạn có thể thêm một đối số chuỗi cho nó như thế "LOOK OVER HERE!!! %s", vì vậy bạn sẽ ít có khả năng bỏ sót lỗi trong bộ đệm thư.
Malabarba

@Malabarba Hình thức with-demoted-errorsnày chỉ có sẵn trong 24.4
lunaryorn

@lunaryorn Cảm ơn, không biết điều đó.
Malabarba

Trên thực tế, phiên bản tôi bật là 24.3.1.
Dân

8

@Dan mô tả tốt cách bạn có thể biến lỗi thành tin nhắn. Bạn cũng có thể làm bất cứ điều gì bạn muốn với lỗi bằng cách sử dụng condition-case. Một lựa chọn khác là sử dụng unwind-protect.

Tôi sẽ bám vào condition-caseđây, không vì lý do gì.

Bắt lỗi

Điều này phải luôn đảm bảo các định nghĩa chính của bạn được đánh giá, bất kể điều gì xảy ra bên trong condition-case. Bất kỳ lỗi nào được lưu trữ bên trong init-error.

(defvar init-error nil 
  "The error which happened.")

(condition-case the-error
    (progn
      ;; Do the dangerous stuff here.
      (require 'what-I-want))
  (error
   ;; This is only evaluated if there's an error.
   (setq init-error the-error)))

;;; Do the safe stuff here.
(define-key uncrippling-map "\C-h" 'help!)

Ném nó trở lại

Sau đó, chỉ cần ném lỗi một lần nữa. Có một số cách bạn có thể làm điều đó, đây là một cách.

;;; Throw the error again here.
(when init-error
  (funcall #'signal (car init-error) (cdr init-error)))

unwind-protectlàm cho lỗi được đưa ra ngay lập tức, sau khi thực hiện bất kỳ mã nào bạn đặt trong mệnh đề giải cứu của nó. Nó giống như finallytrong một ngôn ngữ như Java, hơn là catch.
sanityinc

2

Các câu trả lời khác đã bao phủ khá tốt các phương tiện xử lý lỗi cấp thấp sẽ hữu ích trong trường hợp như thế này. Một cách tiếp cận khác có thể giúp đỡ là mô-đun. Chẳng hạn, tôi chia tệp khởi tạo của mình thành nhiều tệp khác nhau (sử dụng providekhi thích hợp) và tôi tải chúng bằng chức năng này thay vì require:

(defun my/require-softly (feature &optional filename)
  "As `require', but instead of an error just print a message.

If there is an error, its message will be included in the message
printed.

Like `require', the return value will be FEATURE if the load was
successful (or unnecessary) and nil if not."
  (condition-case err
      (require feature filename) 
    (error (message "Error loading %s: \"%s\""
                    (if filename (format "%s (%s)" feature filename) feature)
                    (error-message-string err))
           nil)))

Một lỗi trong khi tải tệp theo cách này vẫn sẽ in một thông báo, nhưng nó sẽ không ngăn thực thi bất cứ điều gì bên ngoài tệp nơi xảy ra lỗi.

Tất nhiên, chức năng này không thực sự khác với việc thực hiện requirecuộc gọi with-demoted-errors(tôi đã viết nó trước khi tôi biết with-demoted-errors), nhưng điểm quan trọng là về cơ bản bạn có thể thực hiện một cái gì đó như kết hợp with-demoted-errorsunwind-protectkhông kết thúc của Dan (có khả năng rất dài) khối mã.


Chức năng này là chính xác những gì tôi đã sau. Emacs của tôi khởi động bây giờ mặc dù báo cáo một lỗi. Sau đó, tôi chỉ cần tải tập tin init của tôi và eval-buffer. Cảm ơn đã đăng nó.
Kevin
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.