Troubleshooting techniques for Emacs and Emacs Lisp
I've 开发者_如何学Gobeen a fairly regular emacs user for about 4 years, but I'm still a newbie when it comes to customizing emacs and troubleshooting elisp. Recently, I've started customizing emacs as my ruby development environment and I've learned a few techniques from the folks here in StackOverflow. For example, some one here told me about C-u C-M-x to instrument a function with edebug and then step thru' the code. I also figured out that most commands and modes in emacs provide tons of hooks (either functions or regexps or customizable variables) which will provide most of what any newbie would want.
Now I'm greedy - I'm looking for more techniques and tips you've used and found useful in the past. (setq debug-on-error t)
(setq debug-on-quit t)
Those help when you want to debug arbitrarily deep problems. You've already discovered edebug
(which is my tool of choice for figuring out other people's code). describe-function
usually gives you a link to the .el
file (along with line number) where it was loaded. That's useful to jump to the source of the problem. I often do that, copy out the function, put in some message
calls and re-evaluate C-x C-e
to have that run instead of the original.
Update: This is a little something I picked up from a presentation by John Wiegley.
(global-set-key (kbd "C-c C-d")
(lambda () (interactive)
(setq debug-on-error (if debug-on-error nil t))
(message (format "debug-on-error : %s" debug-on-error))))
Let's you toggle debug-on-error
with a single keystroke.
C-x Esc Esc gives you a browsable history of M-x commands you have run, but shows you the elisp code.
IELM is a repl for emacs lisp.
Speedbar is an excellent way to browse your .el files, alsoI find myself using C-h i frequently (to browse the elisp manual) and using speedbar to browse the node tree of topics.
C-s / C-r incremental search in the info browser will actually search past page breaks.
I often run M-: to test a quick bit of code without having to switch to my *ielm* buffer.
For especially tricky code I make a shortcut on my desktop to run emacs -q -l development-init.el
(this is especially handy with code that deals with low level manipulations on buffers and external processes, the kind of thing that can easily hang emacs or kill it with a segv).
If hacking your .emacs file, always leave an emacs process running, and test the changes (with --debug-init
) by starting a second Emacs process. This way, if there are problems, you still have an editor up that you can work in.
For my part, I prefer (recommend) debug
over edebug
, but it's probably just a question of taste.
In addition to what Noufal mentioned about the debug-on-*
variables, you can enter the debugger for a given function via M-x debug-on-entry
.
And you can put explicit calls to debug
at breakpoints in the code: (debug)
or (debug nil sexp-to-print)
.
My init file comments on debugging facilities:
;;;; * Debugging, Tracing, and Profiling
;; M-: (info "(elisp) Debugging") RET
;; Standard debugger:
;; M-x debug-on-entry FUNCTION
;; M-x cancel-debug-on-entry &optional FUNCTION
;; debug &rest DEBUGGER-ARGS
;; M-x toggle-debug-on-error
;; M-x toggle-debug-on-quit
;; setq debug-on-signal
;; setq debug-on-next-call
;; setq debug-on-event
;; setq debug-on-message REGEXP
;; Edebug -- a source-level debugger for Emacs Lisp
;; M-x edebug-defun (C-u C-M-x) Cancel with eval-defun (C-M-x)
;; M-x edebug-all-defs -- Toggle edebugging of all definitions
;; M-x edebug-all-forms -- Toggle edebugging of all forms
;; M-x edebug-eval-top-level-form
;; Tracing:
;; M-x trace-function FUNCTION &optional BUFFER
;; M-x untrace-function FUNCTION
;; M-x untrace-all
;; Timing and benchmarking:
;; (benchmark-run &optional REPETITIONS &rest FORMS)
;; Emacs Lisp Profiler (ELP)
;; M-x elp-instrument-package
;; M-x elp-instrument-list
;; M-x elp-instrument-function
;; M-x elp-reset-*
;; M-x elp-results
;; M-x elp-restore-all
;;
;; "There's a built-in profiler called ELP. You can try something like
;; M-x elp-instrument-package, enter "vc", and then try finding a file
;; Afterwards, M-x elp-results will show you a profile report.
;; (Note that if the time is instead being spent in non-vc-related
;; functions, this technique will not show it, but you can instrument
;; further packages if you like.)" http://stackoverflow.com/a/6732810/324105
;; CPU & Memory Profiler ('Native Profiler')
;; M-x profiler-start
;; M-x profiler-report
;; M-x profiler-reset
;; M-x profiler-stop
;; M-x profiler-*
;; Dope ("DOtemacs ProfilEr. A per-sexp-evaltime profiler.")
;; https://raw.github.com/emacsmirror/dope/master/dope.el
;; M-x dope-quick-start will show a little introduction tutorial.
;; Spinning:
;; Set debug-on-quit to t
;; When the problem happens, hit C-g for a backtrace.
Welcome to the first few steps of enlightenment. ;)
First off, a few easy quick hits:
(add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
This'll give you little hints on the mini buffer. It is extremely handy! This tip is less about troubleshooting, and more about making it easy to write, but still.
Get the erefactor package from MELPA, and have a look at what it does. I noticed that after doing a C-x C-e
on a function it would run the result through elint. Saves a lot of hassle.
This hook from the emacs starter kit is awesome. It removes any invalid .elc files. Old elc files can be a real thorn in your side if you are not careful. Conversely look at auto-compile.
(add-hook 'emacs-lisp-mode-hook 'starter-kit-remove-elc-on-save)
(defun starter-kit-remove-elc-on-save ()
"If you're saving an elisp file, likely the .elc is no longer valid."
(make-local-variable 'after-save-hook)
(add-hook 'after-save-hook
(lambda ()
(if (file-exists-p (concat buffer-file-name "c"))
(delete-file (concat buffer-file-name "c"))))))
Finally, when editing lisp, emacs-lisp or scheme make sure you give paredit a try. It is awesome.
精彩评论