How to find a bug in “.emacs” or “init.el”?

2019-01-21 09:49发布

Sometimes when I open Emacs, Emacs initialization fail.
That is because .emacs or init.el files have a bug. (My bugs often come from just mistyping.)

I want to find the bug in .emacs or init.el. Is there any way to do this?

5条回答
再贱就再见
2楼-- · 2019-01-21 10:16

I've had great success with elisp bug hunter https://github.com/Malabarba/elisp-bug-hunter.

The most common problems are unmatched parenthesis, loading-failed packages.:

Automated error hunting

If your Emacs init file signals an error during startup, but you don’t know why, simply issue

M-x bug-hunter-init-file RET e

and The Bug Hunter will find it for you. Note that your init.el (or .emacs) must be idempotent for this to work.

Interactive hunt

If Emacs starts up without errors but something is not working as it should, invoke the same command, but choose the interactive option:

M-x bug-hunter-init-file RET i

The Bug Hunter will start a separate Emacs instance several times, and then it will ask you each time whether that instance presented the problem you have. After doing this about 5–12 times, you’ll be given the results.

查看更多
仙女界的扛把子
3楼-- · 2019-01-21 10:18

To find out what part of your init file (~/.emacs) is causing the behavior you see, bisect your init file recursively: First comment-out half, to see which half is responsible, then 3/4, to see which quarter is responsible,...

To comment out a region of text (e.g. succession of lines that you have selected), I recommend comment-region (which I bind to C-x C-;). With a numeric prefix arg it uses that many ; comment chars. With a plain prefix arg (C-u) it uncomments the region instead of commenting it.

You can also start Emacs with the command-line switch --debug-init. This will cause the debugger to open when an error is raised during Emacs startup, including while your init file is loaded. The debugger backtrace tells you which evaluation raised the error (which function was called), and it shows you which function called the function where the error was raised, which function called that one, and so on.

When you know which function is the problem, if you need to you can debug its evaluation by putting (debug-on-entry 'THE-FUNCTION) near the start of your init file. That will open the debugger when the function is entered instead of just showing what happened when the error was raised. You can then step through the debugger using d (or c to skip through a step), to see just what went wrong.

If you prefer to step through the function starting at some breakpoint, then copy the source code that defines the function to your init file, and insert (debug) at the position where you want the debugger to open.

As always, the Emacs manuals are your friends. See, for instance, node Checklist in the Emacs manual and node Invoking the Debugger in the Elisp manual.

There is another debugger also, called edebug, which is also documented in the manuals. Some people prefer it to debug. (I prefer debug.) Both are good.

Using the debugger is generally more informative if you have loaded Emacs Lisp source files rather than their byte-compiled versions. If you start investigating a particular problem using the debugger, you might want to first load the *.el (not *.elc) file(s) in question.

查看更多
唯我独甜
4楼-- · 2019-01-21 10:20

I'll add it's good to anticipate. The function below, coming from oremacs.com allows to check the validity of our init file (or any other file) without starting up emacs:

(defun ora-test-emacs ()
  (interactive)
  (require 'async)
  (async-start
   (lambda () (shell-command-to-string
          "emacs --batch --eval \"
(condition-case e
    (progn
      (load \\\"~/.emacs\\\")
      (message \\\"-OK-\\\"))
  (error
   (message \\\"ERROR!\\\")
   (signal (car e) (cdr e))))\""))
   `(lambda (output)
      (if (string-match "-OK-" output)
          (when ,(called-interactively-p 'any)
            (message "All is well"))
        (switch-to-buffer-other-window "*startup error*")
        (delete-region (point-min) (point-max))
        (insert output)
        (search-backward "ERROR!")))))

One can even add a Travis CI test.

ps: solutions summed up on wikemacs.

查看更多
The star\"
5楼-- · 2019-01-21 10:38

You can debug your .emacs file like this: Debugging a customization file

Start Emacs with the ‘-debug-init’ command-line option. This enables the Emacs Lisp debugger before evaluating your .emacs file, and places you in the debugger if something goes wrong. The top line in the trace-back buffer will be the error message, and the second or third line of that buffer will display the Lisp code from your .emacs file that caused the problem.

You can also evaluate an individual function or argument to a function in your .emacs file by moving the cursor to the end of the function or argument and typing C-x C-e (M-x eval-last-sexp).

Use C-h v (M-x describe-variable) to check the value of variables which you are trying to set or use.

查看更多
\"骚年 ilove
6楼-- · 2019-01-21 10:40

Some good advice has already been given. In particular, I think @Drew's response pretty much covers what you need to do.

I wanted to also mention that how you structure your config file can also help in tracking down problems. For example, grouping similar or related configuration options together can be very helpful.

However, the one thing which I found to be the most helpful was to break up my configuration into separate files. Essentially, my init.el file does nothing but setup some load-path settings so that my actual configuration code can be found and then just calls '''require to load each of the files.

In my .emacs.d directory, I have a directory called lisp and in that directory, I have a bunch of *.el files with names like init-org.el, init-clojure.el, init-javascript.el etc. In each of those files, I have the config settings relevant to the name i.e. org setup stuff in init-org.el, javascript stuff in init-javascript.el etc.

Each of these files ends with a 'provide' form i.e.

(provide 'init-org)

at the end of init-org.el and

(provide 'init-javascript)

at the end of init-javascript.el etc.

In my init.el file, I just have lines like

(add-to-list 'load-path (expand-file-name "lisp" user-emacs-directory))

(require 'init-org)
(require 'init-javascript)
(require 'init-clojre)

The benefit of doing this is that it is now even easier to bisect my init file. I can just comment out the first half of the require statements - many fewer lines.

the other benefit is that sometimes, if I'm having problems with some config, but it isn't really related to the work I need to do now, I can just comment out that require and get back to work. For example, if I am doing some clojure coding, but having some error when starting emacs due to a problem in my javascript setup, then I can just comment out the (require 'init-javascript) line and I'm good to go.

查看更多
登录 后发表回答