From 81c4839bb368b5cf4201885827b525585b9ad498 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sun, 16 Aug 2015 11:04:40 +0100 Subject: [PATCH] bug-hunter: Indentation and documentation --- packages/bug-hunter/README.org | 91 +++++++++++++++++++++++++++++++ packages/bug-hunter/bug-hunter.el | 30 +++++----- 2 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 packages/bug-hunter/README.org diff --git a/packages/bug-hunter/README.org b/packages/bug-hunter/README.org new file mode 100644 index 000000000..78c622e7e --- /dev/null +++ b/packages/bug-hunter/README.org @@ -0,0 +1,91 @@ +#+OPTIONS: toc:nil num:nil +#+TITLE: [[file:hunter.png]] The Bug Hunter [[https://travis-ci.org/Malabarba/elisp-bug-hunter][file:https://travis-ci.org/Malabarba/elisp-bug-hunter.svg?branch=master]] + + +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~). + +[[file:hunter-screencast.gif]] + +* Usage Examples + +** Automated error hunting +If your Emacs init file signals an error during startup, but you don’t +know why, simply issue +#+BEGIN_SRC text +M-x bug-hunter-init-file RET e +#+END_SRC +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 +#+END_SRC +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. + +** 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, let’s say there’s something in your init file that’s +loading the ~cl~ library, and you don’t want that. You /know/ you’re +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 +#+END_SRC + +*That’s it!* You’ll be given a nice buffer reporting the results: + +[[file:cl-example.png]] +- Are you getting obscure errors when trying to open /“.tex”/ files? + - Don’t despair! Just use ~(find-file "dummy.tex")~ 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 [[https://elpa.gnu.org/packages/bug-hunter.html][GNU Elpa]] to all Emacs versions since +~24.1~. To install, just issue + +#+BEGIN_SRC text +M-x package-install RET bug-hunter +#+END_SRC + +* init.org 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/org-init.org" + "~/.emacs.d/org-init.el") +(load "~/.emacs.d/org-init.el") +#+END_SRC + +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~. diff --git a/packages/bug-hunter/bug-hunter.el b/packages/bug-hunter/bug-hunter.el index 0538ac6fa..e52897108 100644 --- a/packages/bug-hunter/bug-hunter.el +++ b/packages/bug-hunter/bug-hunter.el @@ -49,8 +49,8 @@ ;; ,---- ;; | M-x bug-hunter-init-file RET i ;; `---- -;; The Bug Hunter will start a separate Emacs frame several times, and -;; then it will ask you each time whether that frame presented the +;; 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. ;; @@ -98,7 +98,7 @@ (defconst bug-hunter--interactive-explanation "You have asked to do an interactive hunt, here's how it goes. -1) I will start a new Emacs frame. +1) I will start a new Emacs instance, which opens a new frame. 2) You will try to reproduce your problem on the new frame. 3) When you’re done, close that frame. 4) I will ask you if you managed to reproduce the problem. @@ -232,7 +232,7 @@ the file." "") (when (> size 16) (format "\n ... %s omitted expressions ...\n\n" - (- size 14))) + (- size 14))) (when (> size 16) (mapconcat (lambda (x) (bug-hunter--pretty-format x 4)) (seq-drop forms (- size 7)) ""))))) @@ -240,7 +240,7 @@ the file." (concat "The assertion returned the following value here:\n" (bug-hunter--pretty-format (cadr error) 4))) (t (format "The following error was signaled here:\n %S" - error)))) + error)))) (when expression (bug-hunter--report " Caused by the following expression:\n%s" (bug-hunter--pretty-format expression 4))) @@ -280,7 +280,7 @@ ARGS are passed before \"-l FILE\"." (delete-file file-name)))) (defun bug-hunter--run-form-interactively (form) - "Run FORM in a graphical frame and ask user about the outcome." + "Run FORM in a graphical instance and ask user about the outcome." (let ((file-name (bug-hunter--print-to-temp (list 'prin1 form)))) (unwind-protect (bug-hunter--run-emacs file-name "-Q") @@ -340,16 +340,16 @@ which will be inspected if HEAD doesn't match ASSERTION." (vector (length safe) ret-val)) (ret-val (apply #'bug-hunter--bisect - assertion - safe - (bug-hunter--split head))) + assertion + safe + (bug-hunter--split head))) ;; Issue in the tail. (t (apply #'bug-hunter--bisect - assertion - (append safe head) - ;; If tail has length 1, we already know where the issue is, - ;; but we still do this to get the return value. - (bug-hunter--split tail)))))) + assertion + (append safe head) + ;; If tail has length 1, we already know where the issue is, + ;; but we still do this to get the return value. + (bug-hunter--split tail)))))) (defun bug-hunter--bisect-start (forms assertion) "Run a bisection search on list of FORMS using ASSERTION. @@ -393,7 +393,7 @@ are evaluated." ;; Prepare buffer, and make sure they've seen it. (switch-to-buffer (bug-hunter--init-report-buffer assertion bug-hunter--estimate)) (when (eq assertion 'interactive) - (read-char-choice "Please the instructions above and type 6 when ready. " '(?6))) + (read-char-choice "Please read the instructions above and type 6 when ready. " '(?6))) (cond ;; Check for errors when reading the init file. -- 2.39.2