initファイルのエラーを適切に処理する方法


20

initファイルを実行するときにエラーをキャッチし、それを適切に処理する方法が必要です。私の最も重要なカスタマイズとキーバインドの多くは、他の設定がそれらの上に適用されないようにするために、initファイルの最後に表示されます。問題は、初期化が早期に中止されると、馴染みのあるキーバインディングと設定を適用せずに問題をデバッグしようとすると、完全に不自由に感じることです。

エラーが発生したときに初期化プロセスを正常に終了する方法はありますか?

回答:


9

どちらも完璧ではない2つのオプションが思い浮かびます。最初に、初期初期化コードの大部分(つまり、カスタマイズに到達する前)をラップできます(ignore-errors ...)。ただし、エラーがある場合、多くのフィードバックはありません- ignore-errors単に戻りnilます。

より複雑なオプションは、潜在的にバグのあるコードをunwind-protectand with-demoted-errorsdebug-on-errornilに設定)の組み合わせでラップすることです。後者は、最初に発生したエラーで優雅にエラーを出し、エラーメッセージを*Messages*バッファに報告して検査します。その間、unwind-protectボディの残りの部分(おそらくカスタマイズ)が評価されます。したがって、たとえば:

(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
いいですね、私はしませんでしたwith-demoted-errors。文字列引数をのよう"LOOK OVER HERE!!! %s"に追加できます。そのため、メッセージバッファのエラーを見逃す可能性が低くなります。
マラバルバ14年

@Malabarbaこの形式はwith-demoted-errors24.4
lunaryorn

@lunaryornありがとう、知らなかった。
マラバルバ14年

実際、私が使用しているバージョンは24.3.1です。
ダン

8

@Danは、エラーをメッセージに変換する方法を説明しました。また、を使用して、エラーが発生したときに何でもできます condition-case。さらに別のオプションはを使用すること unwind-protectです。

condition-case理由もなく、ここに固執します。

エラーをキャッチする

これにより、内部で何が起こったかに関係なく、常にキー定義が評価されることが保証されますcondition-case。エラーはすべてに保存され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!)

投げ返す

その後、もう一度エラーをスローします。これを行うにはいくつかの方法がありますが、ここに1つあります。

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

unwind-protectレスキュー句に記述したコードを実行した後、エラーが直ちに再発生します。それfinallyは、Java のような言語ではなく、Java のようなものcatchです。
sanityinc 14年

2

他の答えは、このような場合に役立つ低レベルのエラー処理機能を十分にカバーしています。役立つ別のアプローチは、モジュール性です。たとえば、初期化ファイルを(provide必要に応じて)いくつかの異なるファイルに分割し、次の代わりにこの関数を使用してロードします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)))

この方法でファイルをロード中にエラーが発生した場合でもメッセージは出力されますが、実際にエラーが発生したファイルの外部での実行は防止されません。

もちろん、この機能はラップは異なるということは本当にないrequireでコールがwith-demoted-errors(私が知っていた前に、私はそれを書いたwith-demoted-errors)、しかし重要な点は、それはあなたが本質的にダンの組み合わせのようなものを実装できるということであるwith-demoted-errorsunwind-protect(潜在的に非常に長い)ラッピングなしにコードのブロック。


この機能はまさに私が求めていたものでした。エラーを報告したにもかかわらず、emacsが起動するようになりました。その後、initファイルとを読み込むだけですeval-buffer。投稿してくれてありがとう。
ケビン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.