├── README.md └── edebug-x.el /README.md: -------------------------------------------------------------------------------- 1 | # Edebug-X -- Extensions for Edebug 2 | 3 | Extension to Edebug to make it a little nicer to work with. 4 | 5 | Currently this is a **WIP** but please feel free to test it out and provide some feedback. This package provides the following 6 | functions: 7 | ``` 8 | edebug-x-modify-breakpoint-wrapper - toggle breakpoints in Elisp buffer, C-x SPC 9 | edebug-x-show-breakpoints - show a tabulated list of all breakpoints, C-c C-x b 10 | edebug-x-show-instrumented - show a tabulated list of instrumented functions, C-c C-x i 11 | edebug-x-show-data - show both the breakpoints and instrumented functions buffer, C-c C-x s 12 | ``` 13 | 14 | From the tabulated list buffer the following commands are available: 15 | ``` 16 | edebug-x-kill-breakpoint - bound to K, clear breakpoint 17 | edebug-x-visit-breakpoint - bound to RET, visit breakpoint location 18 | ``` 19 | 20 | The instrumented functions buffer has these commands: 21 | ``` 22 | edebug-x-evaluate-function - bound to E, evaluate function, clearing breakpoints within it 23 | edebug-x-find-function bound to - bound to RET, jump to function 24 | ``` 25 | 26 | Executing Q after `edebug-x-show-data` will remove both buffers and remove the split. 27 | -------------------------------------------------------------------------------- /edebug-x.el: -------------------------------------------------------------------------------- 1 | ;;; edebug-x.el --- extensions for Edebug 2 | 3 | ;; Copyright (C) 2013 Scott Barnett 4 | 5 | ;; Author: Scott Barnett 6 | ;; Keywords: extensions 7 | 8 | ;; This program is free software; you can redistribute it and/or modify 9 | ;; it under the terms of the GNU General Public License as published by 10 | ;; the Free Software Foundation, either version 3 of the License, or 11 | ;; (at your option) any later version. 12 | 13 | ;; This program is distributed in the hope that it will be useful, 14 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | ;; GNU General Public License for more details. 17 | 18 | ;; You should have received a copy of the GNU General Public License 19 | ;; along with this program. If not, see . 20 | 21 | ;;; Commentary: 22 | 23 | ;; Extension to Edebug to make it a little nicer to work with. 24 | 25 | ;; Breakpoints can now be toggled from an Elisp buffer without first 26 | ;; running Edebug with `edebug-x-modify-breakpoint-wrapper', bound to 27 | ;; `C-x SPC'. If the function isn't instrumented already then it will 28 | ;; instrument it and then set the breakpoint. 29 | 30 | ;; The list of current break points can be viewed with 31 | ;; `edebug-x-show-breakpoints', bound to `C-c C-x b'. From the 32 | ;; tabulated list buffer the following commands are available: 33 | 34 | ;; `edebug-x-kill-breakpoint' bound to `K': clear breakpoint 35 | ;; `edebug-x-visit-breakpoint' bound to `RET': visit breakpoint location 36 | 37 | ;; To view a list of instrumented functions execute `C-c C-x i', 38 | ;; `edebug-x-show-instrumented'. The instrumented functions buffer has 39 | ;; these commands: 40 | 41 | ;; `edebug-x-evaluate-function' bound to `E': evaluate function, 42 | ;; clearing breakpoints within it. 43 | ;; `edebug-x-find-function' bound to `RET': jump to function. 44 | 45 | ;; There is also a convenience command, `edebug-x-show-data' (bound to 46 | ;; `C-c C-x s') which will split the window into two showing both the 47 | ;; breakpoints and instrumented function buffers. Executing `Q' will 48 | ;; remove both these buffers. 49 | 50 | ;;; Code: 51 | 52 | (require 'which-func) 53 | (require 'dash) 54 | (require 'cl) 55 | 56 | (defface hi-edebug-x-stop 57 | '((((background dark)) (:background "plum1" :foreground "black")) 58 | (t (:background "wheat"))) 59 | "Face for Edebug breakpoints.") 60 | 61 | (defvar instrumented-forms '() 62 | "Stores all instrumented forms. Format is (symbol name . buffer position).") 63 | 64 | (defun edebug-x-highlight-line () 65 | "Create an overlay at line." 66 | (interactive) 67 | (setq overlay (make-overlay (line-beginning-position) (line-end-position))) 68 | (overlay-put overlay 'face 'hi-edebug-x-stop) 69 | (overlay-put overlay 'edebug-x-hi-lock-overlay t)) 70 | 71 | (defun edebug-x-remove-highlight () 72 | "Remove overlay at point if present." 73 | (interactive) 74 | (if (find-if (lambda (elt) (equal (car (overlay-properties elt)) 'edebug-x-hi-lock-overlay)) 75 | (overlays-at (point))) 76 | (progn 77 | (remove-overlays (overlay-start overlay) 78 | (overlay-end overlay) 'edebug-x-hi-lock-overlay t)))) 79 | 80 | (defadvice edebug-make-form-wrapper (after edebug-x-make-form-wrapper 81 | (cursor form-begin form-end 82 | &optional speclist) 83 | activate) 84 | "Highlight the form being wrapped and save it to a list." 85 | (save-excursion 86 | (let* ((func (which-function))) 87 | (beginning-of-defun) 88 | (if (not (-contains? instrumented-forms func)) 89 | (add-to-list 'instrumented-forms `(,func . ,(point)))) 90 | (edebug-x-highlight-line)))) 91 | 92 | (defadvice edebug-read-sexp (before edebug-x-read-sexp activate) 93 | "Stores forms instrumented and removes overlay if present." 94 | (let* ((func (which-function))) 95 | (setq instrumented-forms 96 | (-remove (lambda (elemt) (equal (car elemt) func)) instrumented-forms)) 97 | (save-excursion 98 | (remove-overlays (point) 99 | (progn (forward-sexp 1) (point)) 'edebug-x-hi-lock-overlay t)))) 100 | 101 | (defun instrumentedp (fun-symbol) 102 | (unless (functionp fun-symbol) 103 | (error "FUN-SYMBOL is not a function")) 104 | (let ((data (get fun-symbol 'edebug))) 105 | (unless (markerp data) 106 | data))) 107 | 108 | (defun edebug-x-modify-breakpoint-wrapper () 109 | "Set a breakpoint from an Elisp file. 110 | The current function that pointer is in will be instrumented if 111 | not already." 112 | (interactive) 113 | (save-excursion 114 | (beginning-of-line) 115 | (let* ((func-symbol (intern (which-function))) 116 | (edebug-data (get func-symbol 'edebug)) 117 | (breakpoints (and (not (markerp edebug-data)) (car (cdr edebug-data)))) 118 | (removed (-remove (lambda (elt) (= (cdr (edebug-find-stop-point)) (car elt))) 119 | breakpoints))) 120 | (if (not (instrumentedp func-symbol)) 121 | (edebug-eval-top-level-form)) 122 | (if (= (length breakpoints) (length removed)) 123 | (progn 124 | (edebug-x-highlight-line) 125 | (edebug-modify-breakpoint t)) 126 | (edebug-x-remove-highlight) 127 | (edebug-modify-breakpoint nil))))) 128 | 129 | (defadvice edebug-set-breakpoint (before edebug-x-set-breakpoint-highlight 130 | (arg) 131 | activate) 132 | "Highlights the current line." 133 | (edebug-x-highlight-line)) 134 | 135 | (defadvice edebug-unset-breakpoint (before edebug-x-unset-breakpoint-highlight 136 | activate) 137 | "Remove highlights from the current line." 138 | (edebug-x-remove-highlight)) 139 | 140 | (defun edebug-x-visit-breakpoint () 141 | "Navigate to breakpoint at line." 142 | (interactive) 143 | (destructuring-bind (func-name pos &optional condition temporary) 144 | (split-string (buffer-substring-no-properties 145 | (line-beginning-position) 146 | (line-end-position))) 147 | (find-function (intern func-name)) 148 | (goto-char (string-to-number pos)))) 149 | 150 | (defun edebug-x-clear-data () 151 | "Delete the window setup after `edebug-show-data'." 152 | (interactive) 153 | (delete-other-windows) 154 | (switch-to-prev-buffer)) 155 | 156 | (defun edebug-x-kill-breakpoint () 157 | "Remove breakpoint at line." 158 | (interactive) 159 | (destructuring-bind (func-name pos &optional condition temporary) 160 | (split-string (buffer-substring-no-properties 161 | (line-beginning-position) 162 | (line-end-position))) 163 | (when (y-or-n-p (format "Edebug breakpoints: delete breakpoint %s?" func-name)) 164 | (save-excursion 165 | (edebug-x-visit-breakpoint) 166 | (edebug-x-modify-breakpoint-wrapper))) 167 | (switch-to-prev-buffer) 168 | (revert-buffer))) 169 | 170 | (defun edebug-x-list-breakpoints () 171 | "Checks all the instrumented functions for any breakpoints. 172 | Returns a tablulated list friendly result to be displayed in 173 | edebug-breakpoint-list-mode." 174 | (let ((results)) 175 | (-each instrumented-forms 176 | (lambda (form) 177 | (let* ((edebug-data (get (intern (car form)) 'edebug)) 178 | (pos (cdr form)) 179 | (func-name (car form)) 180 | (breakpoints (car (cdr edebug-data))) 181 | (stop-points (nth 2 edebug-data))) 182 | (loop for i in breakpoints do 183 | (add-to-list 184 | 'results 185 | (list form 186 | (vconcat `(,func-name) 187 | (list (number-to-string (+ pos (aref stop-points (car i))))) 188 | ;; FIXME: need to check values for last two elements stored as a breakpoint 189 | (mapcar (lambda (ele) (if ele else "")) (cdr i))))))))) 190 | results)) 191 | 192 | (define-derived-mode 193 | edebug-x-breakpoint-list-mode tabulated-list-mode "Edebug Breakpoints" 194 | "Major mode for listing Edebug breakpoints" 195 | (setq tabulated-list-entries 'edebug-x-list-breakpoints) 196 | (setq tabulated-list-format 197 | [("Function name" 50 nil) 198 | ("Position" 20 nil) 199 | ("Condition" 20 nil) 200 | ("Temporary" 20 nil)]) 201 | (define-key edebug-x-breakpoint-list-mode-map (kbd "RET") 'edebug-x-visit-breakpoint) 202 | (define-key edebug-x-breakpoint-list-mode-map (kbd "K") 'edebug-x-kill-breakpoint) 203 | (define-key edebug-x-breakpoint-list-mode-map (kbd "Q") 'edebug-x-clear-data) 204 | (tabulated-list-init-header)) 205 | 206 | (defun edebug-x-evaluate-function () 207 | "Evaluate function on line. 208 | This removes all breakpoints in this function." 209 | (interactive) 210 | (let ((function-name (car (split-string (buffer-substring-no-properties 211 | (line-beginning-position) 212 | (line-end-position)))))) 213 | (when (y-or-n-p (format "Edebug instrumented functions: evaluate function %s?" function-name)) 214 | (find-function (intern function-name)) 215 | (eval-defun nil) 216 | (switch-to-prev-buffer) 217 | (revert-buffer)))) 218 | 219 | (defun edebug-x-find-function () 220 | "Navigate to function from the instrumented function buffer." 221 | (interactive) 222 | (let ((function-name (car (split-string (buffer-substring-no-properties 223 | (line-beginning-position) 224 | (line-end-position)))))) 225 | (find-function (intern function-name)))) 226 | 227 | (defun edebug-x-list-instrumented-functions () 228 | "Return the list of instrumented functions. 229 | Tabulated buffer ready." 230 | (-map (lambda (item) (list (car item) (vector (car item)))) instrumented-forms)) 231 | 232 | (define-derived-mode 233 | edebug-x-instrumented-function-list-mode tabulated-list-mode "Edebug Instrumented functions" 234 | "Major mode for listing instrumented functions" 235 | (setq tabulated-list-entries 'edebug-x-list-instrumented-functions) 236 | (setq tabulated-list-format 237 | [("Instrumented Functions" 50 nil)]) 238 | (define-key edebug-x-instrumented-function-list-mode-map (kbd "E") 'edebug-x-evaluate-function) 239 | (define-key edebug-x-instrumented-function-list-mode-map (kbd "Q") 'edebug-x-clear-data) 240 | (define-key edebug-x-instrumented-function-list-mode-map (kbd "RET") 'edebug-x-find-function) 241 | (tabulated-list-init-header)) 242 | 243 | (defun edebug-x-show-data () 244 | "Display instrumented functions and edebug breakpoints. 245 | Frame is split into two vertically showing the tabluated buffers 246 | for each." 247 | (interactive) 248 | (delete-other-windows) 249 | (let ((buff-breakpoints (get-buffer-create "*Edebug Breakpoints*")) 250 | (buff-instrumented (get-buffer-create "*Instrumented Functions*"))) 251 | (with-current-buffer buff-breakpoints 252 | (edebug-x-breakpoint-list-mode) 253 | (tabulated-list-print)) 254 | (with-current-buffer buff-instrumented 255 | (edebug-x-instrumented-function-list-mode) 256 | (tabulated-list-print)) 257 | (switch-to-buffer buff-breakpoints) 258 | (set-window-buffer (split-window-vertically) 259 | buff-instrumented))) 260 | 261 | (defun edebug-x-show-breakpoints () 262 | "Display breakpoints in a tabulated list buffer." 263 | (interactive) 264 | (switch-to-buffer (get-buffer-create "*Edebug Breakpoints*")) 265 | (edebug-x-breakpoint-list-mode) 266 | (tabulated-list-print)) 267 | 268 | (defun edebug-x-show-instrumented () 269 | "Display instrumented functions in a tabluated list buffer." 270 | (interactive) 271 | (switch-to-buffer (get-buffer-create "*Instrumented Functions*")) 272 | (edebug-x-instrumented-function-list-mode) 273 | (tabulated-list-print)) 274 | 275 | (define-key emacs-lisp-mode-map (kbd "C-x SPC") 'edebug-x-modify-breakpoint-wrapper) 276 | (define-key emacs-lisp-mode-map (kbd "C-c C-x s") 'edebug-x-show-data) 277 | (define-key emacs-lisp-mode-map (kbd "C-c C-x b") 'edebug-x-show-breakpoints) 278 | (define-key emacs-lisp-mode-map (kbd "C-c C-x i") 'edebug-x-show-instrumented) 279 | 280 | (provide 'edebug-x) 281 | 282 | ;;; edebug-x.el ends here 283 | --------------------------------------------------------------------------------