Commit ee119ab9 authored by Lev Lamberov's avatar Lev Lamberov

New upstream version 1.3.1+repack

#+OPTIONS: toc:nil num:nil
#+TITLE: [[file:hunter.png]] The Bug Hunter [[][file:]]
/Automatically debug and bisect your init (.emacs) file!/
The Bug Hunter is an Emacs library that finds the source of an error
or unexpected behavior inside an elisp configuration file (typically
~init.el~ or ~.emacs~).
* Usage Examples
** Automated error hunting
If your Emacs init file signals an error during startup, but you dont
know why, simply issue
#+BEGIN_SRC text
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:
#+BEGIN_SRC text
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, youll be given
the results.
** Assertion hunt
The Bug Hunter can also find your issue based on an assertion.
Essentially, if you can write a code snippet that returns non-nil when
it detects the issue, just provide this snippet as the assertion and
the Bug Hunter will do the rest.
For example, lets say theres something in your init file thats
loading the ~cl~ library, and you dont want that. You /know/ youre
not loading it yourself, but how can you figure out which external
package is responsible for this outrage?
#+BEGIN_SRC text
M-x bug-hunter-init-file RET a (featurep 'cl) RET
*That’s it!* You’ll be given a nice buffer reporting the results:
- Are you getting obscure errors when trying to open /“.tex”/ files?
- Don’t despair! Just use ~(and (find-file "dummy.tex") nil)~ as the assertion.
- Did ~ox-html~ stop working due to some arcane misconfiguration?
- Just write an assertion that does an export and checks the result.
- Does some random command suddenly bind itself to ~C-j~ and you can’t figure out why?
- ~(eq (key-binding "\n") 'unwanted-command)~ is the assertion for you!
Finally, you can also use ~bug-hunter-file~ to hunt in other files.
* Installation
The Bug Hunter is available from [[][GNU Elpa]] to all Emacs versions since
~24.1~. To install, just issue
#+BEGIN_SRC text
M-x package-install RET bug-hunter
* and other literate-style configs
Some people (me included) like to organize their init files by
writting it in ~org-mode~ instead of Emacs-Lisp. This usually involves
adding something like this to ~init.el~,
#+BEGIN_SRC emacs-lisp
;;; Maybe some code up here ;;;
(require 'org)
(org-babel-tangle-file "~/.emacs.d/"
(load "~/.emacs.d/org-init.el")
At first, this makes the Bug-Hunter essentially useless, for it will
do the hunting in ~init.el~ instead of the much more extensive
~org-init.el~. The name of the second file (~org-init.el~) will vary,
but the point is the same. But fear not! There’s a simple solution:
1. If you have any code above the call to ~org-babel-tangle-file~, copy that to the top of ~org-init.el~ (or whatever is the name of your tangled file). This includes that ~(require 'org)~ over there.
2. Invoke ~M-x~ ~bug-hunter-file~ (instead of ~bug-hunter-init-file~). It will ask you which file to debug, and you need to point it to your tangled output file ~org-init.el~.
(unless (bound-and-true-p package--initialized)
package-user-dir (expand-file-name
(format ".cask/%s/elpa" emacs-version)
(file-name-directory load-file-name)))
(require 'ert)
(require 'cl)
(require 'bug-hunter)
;; (fset 'bug-hunter--report #'ignore)
;; (fset 'bug-hunter--report-end #'ignore)
(ert-deftest bug-hunter-test ()
(equal [(void-variable not-defined) 5 2 not-defined]
'(((setq test 1) 3 0)
((setq test 2) 4 1)
(not-defined 5 2))
(equal [(assertion-triggered t) 2 11 (setq test2 2)]
'(((setq test0 0) 0 9)
((setq test1 1) 1 10)
((setq test2 2) 2 11))
'(ignore-errors (> test2 test1))))))
(ert-deftest bug-hunter-test-nobug ()
(should-error (bug-hunter-hunt
'(((setq test 1) 0 1)
((setq test 2) 0 1))
(ert-deftest bug-hunter-test-volcano ()
(bug-hunter-hunt nil 'not-defined)))
(ert-deftest bug-hunter-test-interactive ()
(cl-letf (((symbol-function #'y-or-n-p) #'ignore)
((symbol-function #'read-char-choice) #'ignore))
(should-error (bug-hunter-hunt
'(((kill-emacs) 0 1))
(ert-deftest bug-hunter-looong-hunt ()
(let* ((size 30)
(forms (make-list size '((setq dummy 1) 12 90))))
(dotimes (n size)
(setcar (elt forms (- size n 1)) 'not-defined)
(equal [(void-variable not-defined) 12 90 not-defined]
(bug-hunter-hunt forms nil)))))
(let* ((size 8)
(forms (make-list size '(setq dummy 1))))
(dotimes (n size)
(let ((pos (- size n 1)))
(setf (elt forms pos) 'not-defined)
(equal (vector pos '(bug-caught void-variable not-defined))
(bug-hunter--bisect-start forms nil)))))))
(ert-deftest bug-hunter-reader-error-test ()
(let ((file (expand-file-name "bug-hunter-test-dummy-file"
(with-temp-file file
(insert "(setq useless 1)\n#\n(setq useless 1)\n"))
(equal (bug-hunter-file file nil)
[(invalid-read-syntax "#") 2 0]))
(equal '(bug-caught (invalid-read-syntax "#") 2 0)
(bug-hunter--read-contents file)))
(with-temp-file file
(insert "(setq useless 1)\n)\n(setq useless 1)\n"))
(equal '(bug-caught (invalid-read-syntax ")") 2 0)
(bug-hunter--read-contents file)))
(with-temp-file file
(insert "(setq useless 1)\n(\n(setq useless 1)\n"))
(equal '(bug-caught (end-of-file) 2 0)
(bug-hunter--read-contents file)))))
(provide 'bug-hunter-test)
;;; bug-hunter-test.el ends here
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment