From 4137d339c0d7edbdc6892e49878d01322038896e Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Wed, 15 Jul 2015 08:00:50 +0200 Subject: [PATCH] new version of bug-hunter. --- elpa/bug-hunter-0.2/bug-hunter-pkg.el | 1 - elpa/bug-hunter-0.5.signed | 1 + .../bug-hunter-autoloads.el | 17 +- elpa/bug-hunter-0.5/bug-hunter-pkg.el | 1 + .../bug-hunter.el | 240 ++++++++++++------ 5 files changed, 174 insertions(+), 86 deletions(-) delete mode 100644 elpa/bug-hunter-0.2/bug-hunter-pkg.el create mode 100644 elpa/bug-hunter-0.5.signed rename elpa/{bug-hunter-0.2 => bug-hunter-0.5}/bug-hunter-autoloads.el (70%) create mode 100644 elpa/bug-hunter-0.5/bug-hunter-pkg.el rename elpa/{bug-hunter-0.2 => bug-hunter-0.5}/bug-hunter.el (68%) diff --git a/elpa/bug-hunter-0.2/bug-hunter-pkg.el b/elpa/bug-hunter-0.2/bug-hunter-pkg.el deleted file mode 100644 index 4b48bf3b..00000000 --- a/elpa/bug-hunter-0.2/bug-hunter-pkg.el +++ /dev/null @@ -1 +0,0 @@ -(define-package "bug-hunter" "0.2" "Hunt down errors in elisp files" (quote ((seq "1.3") (cl-lib "0.5")))) diff --git a/elpa/bug-hunter-0.5.signed b/elpa/bug-hunter-0.5.signed new file mode 100644 index 00000000..f26b6bb4 --- /dev/null +++ b/elpa/bug-hunter-0.5.signed @@ -0,0 +1 @@ +Good signature from 474F05837FBDEF9B GNU ELPA Signing Agent (trust undefined) created at 2015-06-19T11:05:02+0200 using DSA \ No newline at end of file diff --git a/elpa/bug-hunter-0.2/bug-hunter-autoloads.el b/elpa/bug-hunter-0.5/bug-hunter-autoloads.el similarity index 70% rename from elpa/bug-hunter-0.2/bug-hunter-autoloads.el rename to elpa/bug-hunter-0.5/bug-hunter-autoloads.el index a961b2fd..fbc5f62e 100644 --- a/elpa/bug-hunter-0.2/bug-hunter-autoloads.el +++ b/elpa/bug-hunter-0.5/bug-hunter-autoloads.el @@ -1,16 +1,16 @@ ;;; bug-hunter-autoloads.el --- automatically extracted autoloads ;; ;;; Code: - +(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) -;;;### (autoloads (bug-hunter-init-file bug-hunter-file) "bug-hunter" -;;;;;; "bug-hunter.el" (21823 19232 0 0)) +;;;### (autoloads nil "bug-hunter" "bug-hunter.el" (21908 10929 0 +;;;;;; 0)) ;;; Generated autoloads from bug-hunter.el (autoload 'bug-hunter-file "bug-hunter" "\ Bisect FILE while testing ASSERTION. All sexps in FILE are read and passed to `bug-hunter-hunt' as a -list. See `bug-hunter-hunt' for how to use assertion. +list. See `bug-hunter-hunt' for how to use ASSERTION. \(fn FILE &optional ASSERTION)" t nil) @@ -18,22 +18,15 @@ list. See `bug-hunter-hunt' for how to use assertion. Test ASSERTION throughout `user-init-file'. All sexps inside `user-init-file' are read and passed to `bug-hunter-hunt' as a list. See `bug-hunter-hunt' for how to use -assertion. +ASSERTION. \(fn &optional ASSERTION)" t nil) ;;;*** -;;;### (autoloads nil nil ("bug-hunter-pkg.el") (21823 19232 280258 -;;;;;; 0)) - -;;;*** - -(provide 'bug-hunter-autoloads) ;; Local Variables: ;; version-control: never ;; no-byte-compile: t ;; no-update-autoloads: t -;; coding: utf-8 ;; End: ;;; bug-hunter-autoloads.el ends here diff --git a/elpa/bug-hunter-0.5/bug-hunter-pkg.el b/elpa/bug-hunter-0.5/bug-hunter-pkg.el new file mode 100644 index 00000000..79e1d1cd --- /dev/null +++ b/elpa/bug-hunter-0.5/bug-hunter-pkg.el @@ -0,0 +1 @@ +(define-package "bug-hunter" "0.5" "Hunt down errors in elisp files" '((seq "1.3") (cl-lib "0.5")) :url "http://github.com/Malabarba/elisp-bug-hunter" :keywords '("lisp")) diff --git a/elpa/bug-hunter-0.2/bug-hunter.el b/elpa/bug-hunter-0.5/bug-hunter.el similarity index 68% rename from elpa/bug-hunter-0.2/bug-hunter.el rename to elpa/bug-hunter-0.5/bug-hunter.el index b84b2608..8bc8b6f1 100644 --- a/elpa/bug-hunter-0.2/bug-hunter.el +++ b/elpa/bug-hunter-0.5/bug-hunter.el @@ -4,7 +4,7 @@ ;; Author: Artur Malabarba ;; URL: http://github.com/Malabarba/elisp-bug-hunter -;; Version: 0.2 +;; Version: 0.5 ;; Keywords: lisp ;; Package-Requires: ((seq "1.3") (cl-lib "0.5")) @@ -22,27 +22,46 @@ ;; along with this program. If not, see . ;;; Commentary: -;; -;; 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'). +;; 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 don’t ;; know why, simply issue ;; ,---- -;; | M-x bug-hunter-init-file RET RET +;; | 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 give it in an assertion. -;; Essentially, if you can write a snippet that detects the issue and -;; returns non-nil, just provide this snippet as the assertion and the -;; Bug Hunter will do a bisection search for you. +;; 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 frame several times, and +;; then it will ask you each time whether that frame 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 @@ -50,12 +69,12 @@ ;; package is responsible for this outrage? ;; ;; ,---- -;; | M-x bug-hunter-init-file RET (featurep 'cl) RET +;; | 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? +;; - 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? @@ -66,13 +85,26 @@ ;; you! ;; ;; Finally, you can also use `bug-hunter-file' to hunt in other files. - +;; +;; +;; init.org and other literate-style configs +;; ========================================= +;; +;; Please see the full Readme on http://github.com/Malabarba/elisp-bug-hunter ;;; Code: (require 'seq) (require 'cl-lib) -(defvar bug-hunter--assertion-reminder +(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. +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. +5) We will repeat steps up to %s times, so hang tight!") + +(defconst bug-hunter--assertion-reminder "Remember, the assertion must be an expression that returns non-nil in your current (problematic) Emacs state, AND that returns nil on a clean Emacs instance." @@ -133,6 +165,7 @@ R is passed to `format' and inserted." R is passed to `bug-hunter--report-print'." (declare (indent 1)) (apply #'bug-hunter--report-print r) + (redisplay) (apply #'message r)) (defun bug-hunter--report-user-error (&rest r) @@ -140,18 +173,22 @@ R is passed to `bug-hunter--report-print'." R is passed to `bug-hunter--report-print'." (declare (indent 1)) (apply #'bug-hunter--report-print r) - (bug-hunter--report-print "\xc") + (bug-hunter--report-print "\xc\n") (apply #'user-error r)) (defvar compilation-error-regexp-alist) -(defun bug-hunter--init-report-buffer () - "Create and prepare the \"*Bug-Hunter Report*\" buffer." - (or (get-buffer "*Bug-Hunter Report*") - (with-current-buffer (get-buffer-create "*Bug-Hunter Report*") - (compilation-mode "Bug Hunt") - (set (make-local-variable 'compilation-error-regexp-alist) - '(comma)) - (current-buffer)))) +(defun bug-hunter--init-report-buffer (assertion steps) + "Create and prepare the \"*Bug-Hunter Report*\" buffer. +Also add some descriptions depending on ASSERTION." + (with-current-buffer (get-buffer-create "*Bug-Hunter Report*") + (let ((inhibit-read-only t)) + (erase-buffer) + (compilation-mode "Bug Hunt") + (set (make-local-variable 'compilation-error-regexp-alist) + '(comma)) + (pcase assertion + (`interactive (insert (format bug-hunter--interactive-explanation (+ 2 steps)))))) + (current-buffer))) (defun bug-hunter--pretty-format (value padding) "Return a VALUE as a string with PADDING spaces on the left." @@ -207,42 +244,75 @@ the file." (when expression (bug-hunter--report " Caused by the following expression:\n%s" (bug-hunter--pretty-format expression 4))) - (bug-hunter--report "\xc") + (bug-hunter--report "\xc\n") `[,error ,line ,column ,expression]) ;;; Execution functions -(defun bug-hunter--run-form (form) - "Run FORM with \"emacs -Q\" and return the result." +(defun bug-hunter--print-to-temp (sexp) + "Print SEXP to a temp file and return the file name." + (let ((print-length nil) + (print-level nil) + (file (make-temp-file "bug-hunter"))) + (with-temp-file file + (print sexp (current-buffer))) + file)) + +(defun bug-hunter--run-emacs (file &rest args) + "Start an Emacs process to run FILE and return the output buffer. +ARGS are passed before \"-l FILE\"." (let ((out-buf (generate-new-buffer "*Bug-Hunter Command*")) (exec (file-truename (expand-file-name invocation-name - invocation-directory))) - (file-name (make-temp-file "bug-hunter"))) + invocation-directory)))) + (apply #'call-process exec nil out-buf nil + (append args (list "-l" file))) + out-buf)) + +(defun bug-hunter--run-form (form) + "Run FORM with \"emacs -Q\" and return the result." + (let ((file-name (bug-hunter--print-to-temp (list 'prin1 form)))) (unwind-protect - (let ((print-length nil) - (print-level nil)) - (with-temp-file file-name - (print (list 'prin1 form) (current-buffer))) - (call-process exec nil out-buf nil - "-Q" "--batch" "-l" file-name) - (with-current-buffer out-buf - (goto-char (point-max)) - (forward-sexp -1) - (prog1 (read (current-buffer)) - (kill-buffer (current-buffer))))) + (with-current-buffer (bug-hunter--run-emacs file-name "-Q" "--batch") + (goto-char (point-max)) + (forward-sexp -1) + (prog1 (read (current-buffer)) + (kill-buffer (current-buffer)))) (delete-file file-name)))) +(defun bug-hunter--run-form-interactively (form) + "Run FORM in a graphical frame 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") + (delete-file file-name)) + (y-or-n-p "Did you find the problem/bug in this instance? "))) + +(defun bug-hunter--wrap-forms-for-eval (forms) + "Return FORMS wrapped in initialization code." + `(let ((server-name (make-temp-file "bug-hunter-temp-server-file"))) + (delete-file server-name) + (if site-run-file (load site-run-file t t)) + (run-hooks 'before-init-hook) + ,@forms + (package-initialize) + (run-hooks 'after-init-hook))) + (defun bug-hunter--run-and-test (forms assertion) "Execute FORMS in the background and test ASSERTION. -See `bug-hunter' for a description on the ASSERTION." - (bug-hunter--run-form - `(condition-case er - (let ((server-name (make-temp-file "bug-hunter-temp-server-file"))) - (delete-file server-name) - ,@forms - (run-hooks 'after-init-hook) - ,assertion) - (error (cons 'bug-caught er))))) +See `bug-hunter' for a description on the ASSERTION. + +If ASSERTION is 'interactive, the form is run through +`bug-hunter--run-form-interactively'. Otherwise, a slightly +modified version of the form combined with ASSERTION is run +through `bug-hunter--run-form'." + (if (eq assertion 'interactive) + (bug-hunter--run-form-interactively + (bug-hunter--wrap-forms-for-eval forms)) + (bug-hunter--run-form + `(condition-case er + ,(append (bug-hunter--wrap-forms-for-eval forms) + (list assertion)) + (error (cons 'bug-caught er)))))) @@ -290,7 +360,6 @@ ASSERTION's return value. If ASSERTION is nil, n is the position of the first form to signal an error and value is (bug-caught . ERROR-SIGNALED)." (let ((bug-hunter--i 0) - (bug-hunter--estimate (ceiling (log (length forms) 2))) (bug-hunter--current-head nil)) (condition-case-unless-debug nil (apply #'bug-hunter--bisect assertion nil (bug-hunter--split forms)) @@ -318,10 +387,16 @@ Bug hunter will refuse to hunt if (i) an error is signaled or the assertion is triggered while running emacs -Q, or (ii) no errors are signaled and the assertion is not triggered after all EXPRs are evaluated." - (pop-to-buffer (bug-hunter--init-report-buffer)) (let ((expressions (unless (eq (car-safe rich-forms) 'bug-caught) - (mapcar #'car rich-forms)))) + (mapcar #'car rich-forms))) + (bug-hunter--estimate (ceiling (log (length rich-forms) 2)))) + ;; 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))) + (cond + ;; Check for errors when reading the init file. ((not expressions) (apply #'bug-hunter--report-error (cdr rich-forms)) (apply #'vector (cdr rich-forms))) @@ -368,34 +443,49 @@ There's nothing more I can do here.") (list 'assertion-triggered ret) (car linecol) (cadr linecol) expression))))))))) +(defconst bug-hunter--hunt-type-prompt + "To bisect interactively, type i +To use automatic error detection, type e +To provide a lisp assertion, type a +=> ") + (defun bug-hunter--read-from-minibuffer () "Read a list of expressions from the minibuffer. -Wraps them in a progn if necessary." - (require 'simple) - (let ((exprs - (with-temp-buffer - ;; Copied from `read--expression'. - (let ((minibuffer-completing-symbol t)) - (minibuffer-with-setup-hook - (lambda () - (add-hook 'completion-at-point-functions - #'elisp-completion-at-point nil t) - (run-hooks 'eval-expression-minibuffer-setup-hook)) - (insert - (read-from-minibuffer - "Expression that returns nil if all is well (optional): " - nil read-expression-map nil 'read-expression-history)))) - (goto-char (point-min)) - (mapcar #'car (bug-hunter--read-buffer))))) - (if (cdr exprs) - (cons #'progn exprs) - (car exprs)))) +Wraps them in a progn if necessary to always return a single +form. + +The user may decide to not provide input, in which case +'interactive is returned. Note, this is different from the user +typing `RET' at an empty prompt, in which case nil is returned." + (pcase (read-char-choice bug-hunter--hunt-type-prompt '(?i ?e ?a)) + (`?i 'interactive) + (`?e nil) + (_ + (require 'simple) + (let ((exprs + (with-temp-buffer + ;; Copied from `read--expression'. + (let ((minibuffer-completing-symbol t)) + (minibuffer-with-setup-hook + (lambda () + (add-hook 'completion-at-point-functions + #'elisp-completion-at-point nil t) + (run-hooks 'eval-expression-minibuffer-setup-hook)) + (insert + (read-from-minibuffer + "Provide an assertion. This is a lisp expression that returns nil if (and only if) everything is fine:\n => " + nil read-expression-map nil 'read-expression-history)))) + (goto-char (point-min)) + (mapcar #'car (bug-hunter--read-buffer))))) + (if (cdr exprs) + (cons #'progn exprs) + (car exprs)))))) ;;;###autoload (defun bug-hunter-file (file &optional assertion) "Bisect FILE while testing ASSERTION. All sexps in FILE are read and passed to `bug-hunter-hunt' as a -list. See `bug-hunter-hunt' for how to use assertion." +list. See `bug-hunter-hunt' for how to use ASSERTION." (interactive (list (read-file-name "File to bisect: " @@ -411,12 +501,16 @@ list. See `bug-hunter-hunt' for how to use assertion." "Test ASSERTION throughout `user-init-file'. All sexps inside `user-init-file' are read and passed to `bug-hunter-hunt' as a list. See `bug-hunter-hunt' for how to use -assertion." +ASSERTION." (interactive (list (bug-hunter--read-from-minibuffer))) (bug-hunter-file user-init-file assertion)) ;;;; ChangeLog: +;; 2015-06-15 Artur Malabarba +;; +;; packages/bug-hunter: Interactive hunt +;; ;; 2015-04-26 Artur Malabarba ;; ;; * bug-hunter.el: Bump version number -- 2.47.3