aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/lispref/edebug.texi35
-rw-r--r--etc/NEWS9
-rw-r--r--lisp/emacs-lisp/edebug.el154
3 files changed, 146 insertions, 52 deletions
diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi
index cebf0a3af3d..94d61480f10 100644
--- a/doc/lispref/edebug.texi
+++ b/doc/lispref/edebug.texi
@@ -1690,3 +1690,38 @@ Whether or not to pause for @code{edebug-sit-for-seconds} on reaching
1690a breakpoint. Set to @code{nil} to prevent the pause, non-@code{nil} 1690a breakpoint. Set to @code{nil} to prevent the pause, non-@code{nil}
1691to allow it. 1691to allow it.
1692@end defopt 1692@end defopt
1693
1694@defopt edebug-behavior-alist
1695By default, this alist contains one entry with the key @code{edebug}
1696and a list of three functions, which are the default implementations
1697of the functions inserted in instrumented code: @code{edebug-enter},
1698@code{edebug-before} and @code{edebug-after}. To change Edebug's
1699behavior globally, modify the default entry.
1700
1701Edebug's behavior may also be changed on a per-definition basis by
1702adding an entry to this alist, with a key of your choice and three
1703functions. Then set the @code{edebug-behavior} symbol property of an
1704instrumented definition to the key of the new entry, and Edebug will
1705call the new functions in place of its own for that definition.
1706@end defopt
1707
1708@defopt edebug-new-definition-functions
1709An abnormal hook run by Edebug after it wraps the body of a definition
1710or closure. After Edebug has initialized its own data, each function
1711is called with one argument, the symbol associated with the
1712definition, which may be the actual symbol defined or one generated by
1713Edebug. This hook may be used to set the @code{edebug-behavior}
1714symbol property of each definition instrumented by Edebug.
1715
1716By default @code{edebug-new-definition-functions} contains
1717@code{edebug-announce-definition} which prints a message each time a
1718definition is instrumented. If you are instrumenting a lot of code
1719and find the messages excessive, remove
1720@code{edebug-announce-definition}.
1721@end defopt
1722
1723@defopt edebug-after-instrumentation-functions
1724An abnormal hook run by Edebug after it instruments a form.
1725Each function is called with one argument, a form which has
1726just been instrumented by Edebug.
1727@end defopt
diff --git a/etc/NEWS b/etc/NEWS
index 75a98d15003..adc1085e745 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -56,6 +56,15 @@ replaced by a double typographic quote.
56 56
57* Changes in Specialized Modes and Packages in Emacs 27.1 57* Changes in Specialized Modes and Packages in Emacs 27.1
58 58
59** Edebug
60
61+++
62*** The runtime behavior of Edebug's instrumentation can be changed
63using the new variable 'edebug-behavior-alist' and the new abnormal
64hooks 'edebug-after-instrumentation-functions' and
65'edebug-new-definition-functions'. Edebug's behavior can be changed
66globally or for individual definitions.
67
59** Enhanced xterm support 68** Enhanced xterm support
60 69
61*** New variable 'xterm-set-window-title' controls whether Emacs 70*** New variable 'xterm-set-window-title' controls whether Emacs
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index dbc56e272fd..a070ff25d17 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -1065,6 +1065,31 @@ circular objects. Let `read' read everything else."
1065(defvar edebug-error-point nil) 1065(defvar edebug-error-point nil)
1066(defvar edebug-best-error nil) 1066(defvar edebug-best-error nil)
1067 1067
1068;; Hooks which may be used to extend Edebug's functionality. See
1069;; Testcover for an example.
1070(defvar edebug-after-instrumentation-functions nil
1071 "Abnormal hook run on code after instrumentation for debugging.
1072Each function is called with one argument, a form which has just
1073been instrumented for Edebugging.")
1074
1075(defvar edebug-new-definition-functions '(edebug-announce-definition)
1076 "Abnormal hook run after Edebug wraps a new definition.
1077After Edebug has initialized its own data, each hook function is
1078called with one argument, the symbol associated with the
1079definition, which may be the actual symbol defined or one
1080generated by Edebug.")
1081
1082(defvar edebug-behavior-alist
1083 '((edebug edebug-default-enter edebug-slow-before edebug-slow-after))
1084 "Alist describing the runtime behavior of Edebug's instrumented code.
1085Each definition instrumented by Edebug will have a
1086`edebug-behavior' property which is a key to this alist. When
1087the instrumented code is running, Edebug will look here for the
1088implementations of `edebug-enter', `edebug-before', and
1089`edebug-after'. Edebug's instrumentation may be used for a new
1090purpose by adding an entry to this alist and a hook to
1091`edebug-new-definition-functions' which sets `edebug-behavior'
1092for the definition.")
1068 1093
1069(defun edebug-read-and-maybe-wrap-form () 1094(defun edebug-read-and-maybe-wrap-form ()
1070 ;; Read a form and wrap it with edebug calls, if the conditions are right. 1095 ;; Read a form and wrap it with edebug calls, if the conditions are right.
@@ -1124,47 +1149,48 @@ circular objects. Let `read' read everything else."
1124 (eq 'symbol (edebug-next-token-class))) 1149 (eq 'symbol (edebug-next-token-class)))
1125 (read (current-buffer)))))) 1150 (read (current-buffer))))))
1126;;;(message "all defs: %s all forms: %s" edebug-all-defs edebug-all-forms) 1151;;;(message "all defs: %s all forms: %s" edebug-all-defs edebug-all-forms)
1127 (cond 1152 (let ((result
1128 (defining-form-p 1153 (cond
1129 (if (or edebug-all-defs edebug-all-forms) 1154 (defining-form-p
1130 ;; If it is a defining form and we are edebugging defs, 1155 (if (or edebug-all-defs edebug-all-forms)
1131 ;; then let edebug-list-form start it. 1156 ;; If it is a defining form and we are edebugging defs,
1132 (let ((cursor (edebug-new-cursor 1157 ;; then let edebug-list-form start it.
1133 (list (edebug-read-storing-offsets (current-buffer))) 1158 (let ((cursor (edebug-new-cursor
1134 (list edebug-offsets)))) 1159 (list (edebug-read-storing-offsets (current-buffer)))
1135 (car 1160 (list edebug-offsets))))
1136 (edebug-make-form-wrapper 1161 (car
1137 cursor 1162 (edebug-make-form-wrapper
1138 (edebug-before-offset cursor) 1163 cursor
1139 (1- (edebug-after-offset cursor)) 1164 (edebug-before-offset cursor)
1140 (list (cons (symbol-name def-kind) (cdr spec)))))) 1165 (1- (edebug-after-offset cursor))
1141 1166 (list (cons (symbol-name def-kind) (cdr spec))))))
1142 ;; Not edebugging this form, so reset the symbol's edebug 1167
1143 ;; property to be just a marker at the definition's source code. 1168 ;; Not edebugging this form, so reset the symbol's edebug
1144 ;; This only works for defs with simple names. 1169 ;; property to be just a marker at the definition's source code.
1145 (put def-name 'edebug (point-marker)) 1170 ;; This only works for defs with simple names.
1146 ;; Also nil out dependent defs. 1171 (put def-name 'edebug (point-marker))
1147 '(mapcar (function 1172 ;; Also nil out dependent defs.
1148 (lambda (def) 1173 '(mapcar (function
1149 (put def-name 'edebug nil))) 1174 (lambda (def)
1150 (get def-name 'edebug-dependents)) 1175 (put def-name 'edebug nil)))
1151 (edebug-read-sexp))) 1176 (get def-name 'edebug-dependents))
1152 1177 (edebug-read-sexp)))
1153 ;; If all forms are being edebugged, explicitly wrap it. 1178
1154 (edebug-all-forms 1179 ;; If all forms are being edebugged, explicitly wrap it.
1155 (let ((cursor (edebug-new-cursor 1180 (edebug-all-forms
1156 (list (edebug-read-storing-offsets (current-buffer))) 1181 (let ((cursor (edebug-new-cursor
1157 (list edebug-offsets)))) 1182 (list (edebug-read-storing-offsets (current-buffer)))
1158 (edebug-make-form-wrapper 1183 (list edebug-offsets))))
1159 cursor 1184 (edebug-make-form-wrapper
1160 (edebug-before-offset cursor) 1185 cursor
1161 (edebug-after-offset cursor) 1186 (edebug-before-offset cursor)
1162 nil))) 1187 (edebug-after-offset cursor)
1163 1188 nil)))
1164 ;; Not a defining form, and not edebugging. 1189
1165 (t (edebug-read-sexp))) 1190 ;; Not a defining form, and not edebugging.
1166 )) 1191 (t (edebug-read-sexp)))))
1167 1192 (run-hook-with-args 'edebug-after-instrumentation-functions result)
1193 result)))
1168 1194
1169(defvar edebug-def-args) ; args of defining form. 1195(defvar edebug-def-args) ; args of defining form.
1170(defvar edebug-def-interactive) ; is it an emacs interactive function? 1196(defvar edebug-def-interactive) ; is it an emacs interactive function?
@@ -1332,7 +1358,6 @@ expressions; a `progn' form will be returned enclosing these forms."
1332 1358
1333 ;; (message "defining: %s" edebug-def-name) (sit-for 2) 1359 ;; (message "defining: %s" edebug-def-name) (sit-for 2)
1334 (edebug-make-top-form-data-entry form-data-entry) 1360 (edebug-make-top-form-data-entry form-data-entry)
1335 (message "Edebug: %s" edebug-def-name)
1336 ;;(debug edebug-def-name) 1361 ;;(debug edebug-def-name)
1337 1362
1338 ;; Destructively reverse edebug-offset-list and make vector from it. 1363 ;; Destructively reverse edebug-offset-list and make vector from it.
@@ -1358,9 +1383,15 @@ expressions; a `progn' form will be returned enclosing these forms."
1358 edebug-offset-list 1383 edebug-offset-list
1359 edebug-top-window-data 1384 edebug-top-window-data
1360 )) 1385 ))
1386 (put edebug-def-name 'edebug-behavior 'edebug)
1387 (run-hook-with-args 'edebug-new-definition-functions edebug-def-name)
1361 result 1388 result
1362 ))) 1389 )))
1363 1390
1391(defun edebug-announce-definition (def-name)
1392 "Announce Edebug's processing of DEF-NAME."
1393 (message "Edebug: %s" def-name))
1394
1364 1395
1365(defun edebug-clear-frequency-count (name) 1396(defun edebug-clear-frequency-count (name)
1366 ;; Create initial frequency count vector. 1397 ;; Create initial frequency count vector.
@@ -2167,7 +2198,21 @@ error is signaled again."
2167 2198
2168;;; Entering Edebug 2199;;; Entering Edebug
2169 2200
2170(defun edebug-enter (function args body) 2201(defun edebug-enter (func args body)
2202 "Enter Edebug for a function.
2203FUNC should be the symbol with the Edebug information, ARGS is
2204the list of arguments and BODY is the code.
2205
2206Look up the `edebug-behavior' for FUNC in `edebug-behavior-alist'
2207and run its entry function, and set up `edebug-before' and
2208`edebug-after'."
2209 (cl-letf* ((behavior (get func 'edebug-behavior))
2210 (functions (cdr (assoc behavior edebug-behavior-alist)))
2211 ((symbol-function #'edebug-before) (nth 1 functions))
2212 ((symbol-function #'edebug-after) (nth 2 functions)))
2213 (funcall (nth 0 functions) func args body)))
2214
2215(defun edebug-default-enter (function args body)
2171 ;; Entering FUNC. The arguments are ARGS, and the body is BODY. 2216 ;; Entering FUNC. The arguments are ARGS, and the body is BODY.
2172 ;; Setup edebug variables and evaluate BODY. This function is called 2217 ;; Setup edebug variables and evaluate BODY. This function is called
2173 ;; when a function evaluated with edebug-eval-top-level-form is entered. 2218 ;; when a function evaluated with edebug-eval-top-level-form is entered.
@@ -2198,7 +2243,7 @@ error is signaled again."
2198 edebug-initial-mode 2243 edebug-initial-mode
2199 edebug-execution-mode) 2244 edebug-execution-mode)
2200 edebug-next-execution-mode nil) 2245 edebug-next-execution-mode nil)
2201 (edebug-enter function args body)))) 2246 (edebug-default-enter function args body))))
2202 2247
2203 (let* ((edebug-data (get function 'edebug)) 2248 (let* ((edebug-data (get function 'edebug))
2204 (edebug-def-mark (car edebug-data)) ; mark at def start 2249 (edebug-def-mark (car edebug-data)) ; mark at def start
@@ -2317,22 +2362,27 @@ MSG is printed after `::::} '."
2317 value 2362 value
2318 (edebug-debugger after-index 'after value) 2363 (edebug-debugger after-index 'after value)
2319 ))) 2364 )))
2320
2321(defun edebug-fast-after (_before-index _after-index value) 2365(defun edebug-fast-after (_before-index _after-index value)
2322 ;; Do nothing but return the value. 2366 ;; Do nothing but return the value.
2323 value) 2367 value)
2324 2368
2325(defun edebug-run-slow () 2369(defun edebug-run-slow ()
2326 (defalias 'edebug-before 'edebug-slow-before) 2370 "Set up Edebug's normal behavior."
2327 (defalias 'edebug-after 'edebug-slow-after)) 2371 (setf (cdr (assq 'edebug edebug-behavior-alist))
2372 '(edebug-default-enter edebug-slow-before edebug-slow-after)))
2328 2373
2329;; This is not used, yet. 2374;; This is not used, yet.
2330(defun edebug-run-fast () 2375(defun edebug-run-fast ()
2331 (defalias 'edebug-before 'edebug-fast-before) 2376 "Disable Edebug without de-instrumenting code."
2332 (defalias 'edebug-after 'edebug-fast-after)) 2377 (setf (cdr (assq 'edebug edebug-behavior-alist))
2333 2378 '(edebug-default-enter edebug-fast-before edebug-fast-after)))
2334(edebug-run-slow) 2379
2335 2380(defalias 'edebug-before nil
2381 "Function called by Edebug before a form is evaluated.
2382See `edebug-behavior-alist' for implementations.")
2383(defalias 'edebug-after nil
2384 "Function called by Edebug after a form is evaluated.
2385See `edebug-behavior-alist' for implementations.")
2336 2386
2337(defun edebug--update-coverage (after-index value) 2387(defun edebug--update-coverage (after-index value)
2338 (let ((old-result (aref edebug-coverage after-index))) 2388 (let ((old-result (aref edebug-coverage after-index)))