Mercurial > emacs
comparison lisp/progmodes/gdb-mi.el @ 104153:957779ca8cea
* progmodes/gdb-mi.el (gdb-get-buffer, gdb-get-buffer-create):
Argument `key' renamed to `buffer-type'.
(gdb-current-context-buffer-name): Do not add thread info to
buffer name when no thread is selected.
(gdbmi-record-list, gdb-shell): Try to handle GDB `shell'
command (bug 3794).
(gdb-thread-selected): Handle `=thread-selected' notification.
(gdb-wait-for-pending): New macro to deal with congestion problems.
(gdb-breakpoints-list-handler-custom): Don't fail on pending
breakpoints.
(gdb-invalidate-disassembly): Use 'fullname instead of 'file. This
fixes problem similar to one described in bug 3947.
(gud-menu-map): More menu items.
(gdb-init-1): Reset `gdb-thread-number' to nil.
author | Dmitry Dzhus <dima@sphinx.net.ru> |
---|---|
date | Tue, 04 Aug 2009 15:51:58 +0000 |
parents | 22070e4cdf2a |
children | 87373993f3bd |
comparison
equal
deleted
inserted
replaced
104152:0727b216c5bf | 104153:957779ca8cea |
---|---|
231 `(member ,item gdb-pending-triggers)) | 231 `(member ,item gdb-pending-triggers)) |
232 (defmacro gdb-delete-pending (item) | 232 (defmacro gdb-delete-pending (item) |
233 `(setq gdb-pending-triggers | 233 `(setq gdb-pending-triggers |
234 (delete ,item gdb-pending-triggers))) | 234 (delete ,item gdb-pending-triggers))) |
235 | 235 |
236 (defvar gdb-wait-for-pending-timeout 0.5) | |
237 | |
238 (defmacro gdb-wait-for-pending (&rest body) | |
239 "Wait until `gdb-pending-triggers' is empty and execute BODY. | |
240 | |
241 This function checks `gdb-pending-triggers' value every | |
242 `gdb-wait-for-pending' seconds." | |
243 (run-with-timer | |
244 gdb-wait-for-pending-timeout nil | |
245 `(lambda () | |
246 (if (not gdb-pending-triggers) | |
247 (progn | |
248 ,@body) | |
249 (gdb-wait-for-pending ,@body))))) | |
250 | |
236 (defcustom gdb-debug-log-max 128 | 251 (defcustom gdb-debug-log-max 128 |
237 "Maximum size of `gdb-debug-log'. If nil, size is unlimited." | 252 "Maximum size of `gdb-debug-log'. If nil, size is unlimited." |
238 :group 'gdb | 253 :group 'gdb |
239 :type '(choice (integer :tag "Number of elements") | 254 :type '(choice (integer :tag "Number of elements") |
240 (const :tag "Unlimited" nil)) | 255 (const :tag "Unlimited" nil)) |
617 | 632 |
618 (defun gdb-init-1 () | 633 (defun gdb-init-1 () |
619 ;; (re-)initialise | 634 ;; (re-)initialise |
620 (setq gdb-selected-frame nil | 635 (setq gdb-selected-frame nil |
621 gdb-frame-number nil | 636 gdb-frame-number nil |
637 gdb-thread-number nil | |
622 gdb-var-list nil | 638 gdb-var-list nil |
623 gdb-pending-triggers nil | 639 gdb-pending-triggers nil |
624 gdb-output-sink 'user | 640 gdb-output-sink 'user |
625 gdb-location-alist nil | 641 gdb-location-alist nil |
626 gdb-source-file-list nil | 642 gdb-source-file-list nil |
1086 | 1102 |
1087 (defun gdb-current-buffer-frame () | 1103 (defun gdb-current-buffer-frame () |
1088 "Get current stack frame object for thread of current buffer." | 1104 "Get current stack frame object for thread of current buffer." |
1089 (gdb-get-field (gdb-current-buffer-thread) 'frame)) | 1105 (gdb-get-field (gdb-current-buffer-thread) 'frame)) |
1090 | 1106 |
1091 (defun gdb-get-buffer (key &optional thread) | 1107 (defun gdb-get-buffer (buffer-type &optional thread) |
1092 "Get a specific GDB buffer. | 1108 "Get a specific GDB buffer. |
1093 | 1109 |
1094 In that buffer, `gdb-buffer-type' must be equal to KEY and | 1110 In that buffer, `gdb-buffer-type' must be equal to BUFFER-TYPE |
1095 `gdb-thread-number' (if provided) must be equal to THREAD." | 1111 and `gdb-thread-number' (if provided) must be equal to THREAD." |
1096 (catch 'found | 1112 (catch 'found |
1097 (dolist (buffer (buffer-list) nil) | 1113 (dolist (buffer (buffer-list) nil) |
1098 (with-current-buffer buffer | 1114 (with-current-buffer buffer |
1099 (when (and (eq gdb-buffer-type key) | 1115 (when (and (eq gdb-buffer-type buffer-type) |
1100 (or (not thread) | 1116 (or (not thread) |
1101 (equal gdb-thread-number thread))) | 1117 (equal gdb-thread-number thread))) |
1102 (throw 'found buffer)))))) | 1118 (throw 'found buffer)))))) |
1103 | 1119 |
1104 (defun gdb-get-buffer-create (key &optional thread) | 1120 (defun gdb-get-buffer-create (buffer-type &optional thread) |
1105 "Create a new GDB buffer of the type specified by KEY. | 1121 "Create a new GDB buffer of the type specified by BUFFER-TYPE. |
1106 The key should be one of the cars in `gdb-buffer-rules'. | 1122 The buffer-type should be one of the cars in `gdb-buffer-rules'. |
1107 | 1123 |
1108 If THREAD is non-nil, it is assigned to `gdb-thread-number' | 1124 If THREAD is non-nil, it is assigned to `gdb-thread-number' |
1109 buffer-local variable of the new buffer. | 1125 buffer-local variable of the new buffer. |
1110 | 1126 |
1111 If buffer's mode returns a symbol, it's used to register " | 1127 If buffer's mode returns a symbol, it's used to register " |
1112 (or (gdb-get-buffer key thread) | 1128 (or (gdb-get-buffer buffer-type thread) |
1113 (let ((rules (assoc key gdb-buffer-rules)) | 1129 (let ((rules (assoc buffer-type gdb-buffer-rules)) |
1114 (new (generate-new-buffer "limbo"))) | 1130 (new (generate-new-buffer "limbo"))) |
1115 (with-current-buffer new | 1131 (with-current-buffer new |
1116 (let ((mode (gdb-rules-buffer-mode rules)) | 1132 (let ((mode (gdb-rules-buffer-mode rules)) |
1117 (trigger (gdb-rules-update-trigger rules))) | 1133 (trigger (gdb-rules-update-trigger rules))) |
1118 (when mode (funcall mode)) | 1134 (when mode (funcall mode)) |
1119 (setq gdb-buffer-type key) | 1135 (setq gdb-buffer-type buffer-type) |
1120 (when thread | 1136 (when thread |
1121 (set (make-local-variable 'gdb-thread-number) thread)) | 1137 (set (make-local-variable 'gdb-thread-number) thread)) |
1122 (set (make-local-variable 'gud-minor-mode) | 1138 (set (make-local-variable 'gud-minor-mode) |
1123 (buffer-local-value 'gud-minor-mode gud-comint-buffer)) | 1139 (buffer-local-value 'gud-minor-mode gud-comint-buffer)) |
1124 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map) | 1140 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map) |
1428 (if gdb-thread-number | 1444 (if gdb-thread-number |
1429 (concat command " --thread " gdb-thread-number " ") | 1445 (concat command " --thread " gdb-thread-number " ") |
1430 command)) | 1446 command)) |
1431 | 1447 |
1432 (defun gdb-current-context-buffer-name (name) | 1448 (defun gdb-current-context-buffer-name (name) |
1433 "Add thread information and asterisks to string NAME." | 1449 "Add thread information and asterisks to string NAME. |
1450 | |
1451 If `gdb-thread-number' is nil, just wrap NAME in asterisks." | |
1434 (concat "*" name | 1452 (concat "*" name |
1435 (if (local-variable-p 'gdb-thread-number) | 1453 (format |
1436 " (bound to thread " | 1454 (cond ((local-variable-p 'gdb-thread-number) " (bound to thread %s)") |
1437 " (current thread ") | 1455 (gdb-thread-number " (current thread %s)") |
1438 gdb-thread-number ")*")) | 1456 (t "")) |
1457 gdb-thread-number) | |
1458 "*")) | |
1439 | 1459 |
1440 | 1460 |
1441 (defcustom gud-gdb-command-name "gdb -i=mi" | 1461 (defcustom gud-gdb-command-name "gdb -i=mi" |
1442 "Default command to execute an executable under the GDB debugger." | 1462 "Default command to execute an executable under the GDB debugger." |
1443 :type 'string | 1463 :type 'string |
1515 cannot be reliably used to determine whether or not execution | 1535 cannot be reliably used to determine whether or not execution |
1516 control buttons should be shown in menu or toolbar. Use | 1536 control buttons should be shown in menu or toolbar. Use |
1517 `gdb-running-threads-count' and `gdb-stopped-threads-count' | 1537 `gdb-running-threads-count' and `gdb-stopped-threads-count' |
1518 instead. | 1538 instead. |
1519 | 1539 |
1520 For all-stop mode, thread information is unavailable while target is running" | 1540 For all-stop mode, thread information is unavailable while target |
1541 is running." | |
1521 (setq gud-running | 1542 (setq gud-running |
1522 (string= (gdb-get-field (gdb-current-buffer-thread) 'state) | 1543 (string= (gdb-get-field (gdb-current-buffer-thread) 'state) |
1523 "running"))) | 1544 "running"))) |
1524 | 1545 |
1525 ;; GUD displays the selected GDB frame. This might might not be the current | 1546 ;; GUD displays the selected GDB frame. This might might not be the current |
1549 (gdb-console . "~\\(\".*?\"\\)\n") | 1570 (gdb-console . "~\\(\".*?\"\\)\n") |
1550 (gdb-internals . "&\\(\".*?\"\\)\n") | 1571 (gdb-internals . "&\\(\".*?\"\\)\n") |
1551 (gdb-stopped . "\\*stopped,?\\(.*?\\)\n") | 1572 (gdb-stopped . "\\*stopped,?\\(.*?\\)\n") |
1552 (gdb-running . "\\*running,\\(.*?\n\\)") | 1573 (gdb-running . "\\*running,\\(.*?\n\\)") |
1553 (gdb-thread-created . "=thread-created,\\(.*?\n\\)") | 1574 (gdb-thread-created . "=thread-created,\\(.*?\n\\)") |
1554 (gdb-thread-exited . "=thread-exited,\\(.*?\n\\)"))) | 1575 (gdb-thread-selected . "=thread-selected,\\(.*?\\)\n") |
1576 (gdb-thread-exited . "=thread-exited,\\(.*?\n\\)") | |
1577 (gdb-ignored-notification . "=[-[:alpha:]]+,?\\(.*?\\)\n") | |
1578 (gdb-shell . "\\(\\(?:^.+\n\\)+\\)"))) | |
1555 | 1579 |
1556 (defun gud-gdbmi-marker-filter (string) | 1580 (defun gud-gdbmi-marker-filter (string) |
1557 "Filter GDB/MI output." | 1581 "Filter GDB/MI output." |
1558 | 1582 |
1559 ;; Record transactions if logging is enabled. | 1583 ;; Record transactions if logging is enabled. |
1608 | 1632 |
1609 gdb-filter-output)) | 1633 gdb-filter-output)) |
1610 | 1634 |
1611 (defun gdb-gdb (output-field)) | 1635 (defun gdb-gdb (output-field)) |
1612 | 1636 |
1637 (defun gdb-shell (output-field) | |
1638 (let ((gdb-output-sink gdb-output-sink)) | |
1639 (setq gdb-filter-output | |
1640 (concat output-field gdb-filter-output)))) | |
1641 | |
1642 (defun gdb-ignored-notification (output-field)) | |
1643 | |
1613 ;; gdb-invalidate-threads is defined to accept 'update-threads signal | 1644 ;; gdb-invalidate-threads is defined to accept 'update-threads signal |
1614 (defun gdb-thread-created (output-field)) | 1645 (defun gdb-thread-created (output-field)) |
1615 (defun gdb-thread-exited (output-field) | 1646 (defun gdb-thread-exited (output-field) |
1616 (gdb-emit-signal gdb-buf-publisher 'update-threads)) | 1647 (gdb-emit-signal gdb-buf-publisher 'update-threads)) |
1648 | |
1649 (defun gdb-thread-selected (output-field) | |
1650 "Handler for =thread-selected MI output record. | |
1651 | |
1652 Sets `gdb-thread-number' to new id." | |
1653 (let* ((result (gdb-json-string output-field)) | |
1654 (thread-id (gdb-get-field result 'id))) | |
1655 (gdb-setq-thread-number thread-id) | |
1656 (gdb-wait-for-pending | |
1657 (gdb-update)))) | |
1617 | 1658 |
1618 (defun gdb-running (output-field) | 1659 (defun gdb-running (output-field) |
1619 (setq gdb-inferior-status "running") | 1660 (setq gdb-inferior-status "running") |
1620 (gdb-force-mode-line-update | 1661 (gdb-force-mode-line-update |
1621 (propertize gdb-inferior-status 'face font-lock-type-face)) | 1662 (propertize gdb-inferior-status 'face font-lock-type-face)) |
1953 (if (string-equal flag "y") | 1994 (if (string-equal flag "y") |
1954 (propertize "y" 'face font-lock-warning-face) | 1995 (propertize "y" 'face font-lock-warning-face) |
1955 (propertize "n" 'face font-lock-comment-face))) "\t" | 1996 (propertize "n" 'face font-lock-comment-face))) "\t" |
1956 (gdb-get-field breakpoint 'times) "\t" | 1997 (gdb-get-field breakpoint 'times) "\t" |
1957 (gdb-get-field breakpoint 'addr))) | 1998 (gdb-get-field breakpoint 'addr))) |
1958 (let ((at (gdb-get-field breakpoint 'at))) | 1999 (let ((at (gdb-get-field breakpoint 'at)) |
1959 (cond ((not at) | 2000 (pending (gdb-get-field breakpoint 'pending))) |
2001 (cond (pending (insert " " pending)) | |
2002 (at (insert " " at)) | |
2003 (t | |
1960 (progn | 2004 (progn |
1961 (insert | 2005 (insert |
1962 (concat " in " | 2006 (concat " in " |
1963 (propertize (gdb-get-field breakpoint 'func) | 2007 (propertize (gdb-get-field breakpoint 'func) |
1964 'face font-lock-function-name-face))) | 2008 'face font-lock-function-name-face))) |
1965 (gdb-insert-frame-location breakpoint) | 2009 (gdb-insert-frame-location breakpoint) |
1966 (add-text-properties (line-beginning-position) | 2010 (add-text-properties (line-beginning-position) |
1967 (line-end-position) | 2011 (line-end-position) |
1968 '(mouse-face highlight | 2012 '(mouse-face highlight |
1969 help-echo "mouse-2, RET: visit breakpoint")))) | 2013 help-echo "mouse-2, RET: visit breakpoint"))))) |
1970 (at (insert (concat " " at))) | |
1971 (t (insert (gdb-get-field breakpoint 'original-location))))) | |
1972 (add-text-properties (line-beginning-position) | 2014 (add-text-properties (line-beginning-position) |
1973 (line-end-position) | 2015 (line-end-position) |
1974 `(gdb-breakpoint ,breakpoint)) | 2016 `(gdb-breakpoint ,breakpoint)) |
1975 (newline)) | 2017 (newline)) |
1976 (gdb-place-breakpoints))) | 2018 (gdb-place-breakpoints)))) |
1977 | 2019 |
1978 ;; Put breakpoint icons in relevant margins (even those set in the GUD buffer). | 2020 ;; Put breakpoint icons in relevant margins (even those set in the GUD buffer). |
1979 (defun gdb-place-breakpoints () | 2021 (defun gdb-place-breakpoints () |
1980 (let ((flag) (bptno)) | 2022 (let ((flag) (bptno)) |
1981 ;; Remove all breakpoint-icons in source buffers but not assembler buffer. | 2023 ;; Remove all breakpoint-icons in source buffers but not assembler buffer. |
2158 (let ((map (make-sparse-keymap))) | 2200 (let ((map (make-sparse-keymap))) |
2159 (define-key map (vector 'header-line mouse) function) | 2201 (define-key map (vector 'header-line mouse) function) |
2160 (define-key map (vector 'header-line 'down-mouse-1) 'ignore) | 2202 (define-key map (vector 'header-line 'down-mouse-1) 'ignore) |
2161 map)) | 2203 map)) |
2162 | 2204 |
2205 | |
2206 ;; uses "-thread-info". Needs GDB 7.0 onwards. | |
2207 ;;; Threads view | |
2208 | |
2209 (defun gdb-jump-to (file line) | |
2210 (find-file-other-window file) | |
2211 (goto-line line)) | |
2212 | |
2213 (define-button-type 'gdb-file-button | |
2214 'help-echo "Push to jump to source code" | |
2215 ; 'face 'bold | |
2216 'action | |
2217 (lambda (b) | |
2218 (gdb-jump-to (button-get b 'file) | |
2219 (button-get b 'line)))) | |
2220 | |
2221 (defun gdb-insert-file-location-button (file line) | |
2222 "Insert text button which allows jumping to FILE:LINE. | |
2223 | |
2224 FILE is a full path." | |
2225 (insert-text-button | |
2226 (format "%s:%d" (file-name-nondirectory file) line) | |
2227 :type 'gdb-file-button | |
2228 'file file | |
2229 'line line)) | |
2230 | |
2231 (defun gdb-threads-buffer-name () | |
2232 (concat "*threads of " (gdb-get-target-string) "*")) | |
2233 | |
2234 (def-gdb-display-buffer | |
2235 gdb-display-threads-buffer | |
2236 'gdb-threads-buffer | |
2237 "Display GDB threads.") | |
2238 | |
2239 (def-gdb-frame-for-buffer | |
2240 gdb-frame-threads-buffer | |
2241 'gdb-threads-buffer | |
2242 "Display GDB threads in a new frame.") | |
2243 | |
2244 (def-gdb-trigger-and-handler | |
2245 gdb-invalidate-threads "-thread-info" | |
2246 gdb-thread-list-handler gdb-thread-list-handler-custom | |
2247 '(update update-threads)) | |
2248 | |
2249 (gdb-set-buffer-rules | |
2250 'gdb-threads-buffer | |
2251 'gdb-threads-buffer-name | |
2252 'gdb-threads-mode | |
2253 'gdb-invalidate-threads) | |
2254 | |
2255 (defvar gdb-threads-font-lock-keywords | |
2256 '(("in \\([^ ]+\\) (" (1 font-lock-function-name-face)) | |
2257 (" \\(stopped\\) in " (1 font-lock-warning-face)) | |
2258 (" \\(running\\)" (1 font-lock-string-face)) | |
2259 ("\\(\\(\\sw\\|[_.]\\)+\\)=" (1 font-lock-variable-name-face))) | |
2260 "Font lock keywords used in `gdb-threads-mode'.") | |
2261 | |
2262 (defvar gdb-threads-mode-map | |
2263 (let ((map (make-sparse-keymap))) | |
2264 (define-key map "\r" 'gdb-select-thread) | |
2265 (define-key map "f" 'gdb-display-stack-for-thread) | |
2266 (define-key map "F" 'gdb-frame-stack-for-thread) | |
2267 (define-key map "l" 'gdb-display-locals-for-thread) | |
2268 (define-key map "L" 'gdb-frame-locals-for-thread) | |
2269 (define-key map "r" 'gdb-display-registers-for-thread) | |
2270 (define-key map "R" 'gdb-frame-registers-for-thread) | |
2271 (define-key map "d" 'gdb-display-disassembly-for-thread) | |
2272 (define-key map "D" 'gdb-frame-disassembly-for-thread) | |
2273 (define-key map "i" 'gdb-interrupt-thread) | |
2274 (define-key map "c" 'gdb-continue-thread) | |
2275 (define-key map "s" 'gdb-step-thread) | |
2276 map)) | |
2277 | |
2163 (defmacro gdb-propertize-header (name buffer help-echo mouse-face face) | 2278 (defmacro gdb-propertize-header (name buffer help-echo mouse-face face) |
2164 `(propertize ,name | 2279 `(propertize ,name |
2165 'help-echo ,help-echo | 2280 'help-echo ,help-echo |
2166 'mouse-face ',mouse-face | 2281 'mouse-face ',mouse-face |
2167 'face ',face | 2282 'face ',face |
2174 (set-window-dedicated-p (selected-window) nil) | 2289 (set-window-dedicated-p (selected-window) nil) |
2175 (switch-to-buffer | 2290 (switch-to-buffer |
2176 (gdb-get-buffer-create ',buffer)) | 2291 (gdb-get-buffer-create ',buffer)) |
2177 (setq header-line-format(gdb-set-header ',buffer)) | 2292 (setq header-line-format(gdb-set-header ',buffer)) |
2178 (set-window-dedicated-p (selected-window) t)))))) | 2293 (set-window-dedicated-p (selected-window) t)))))) |
2294 | |
2295 (defvar gdb-breakpoints-header | |
2296 (list | |
2297 (gdb-propertize-header "Breakpoints" gdb-breakpoints-buffer | |
2298 nil nil mode-line) | |
2299 " " | |
2300 (gdb-propertize-header "Threads" gdb-threads-buffer | |
2301 "mouse-1: select" mode-line-highlight mode-line-inactive))) | |
2302 (define-derived-mode gdb-threads-mode gdb-parent-mode "Threads" | |
2303 "Major mode for GDB threads. | |
2304 | |
2305 \\{gdb-threads-mode-map}" | |
2306 (setq gdb-thread-position (make-marker)) | |
2307 (add-to-list 'overlay-arrow-variable-list 'gdb-thread-position) | |
2308 (setq header-line-format gdb-breakpoints-header) | |
2309 (set (make-local-variable 'font-lock-defaults) | |
2310 '(gdb-threads-font-lock-keywords)) | |
2311 (run-mode-hooks 'gdb-threads-mode-hook) | |
2312 'gdb-invalidate-threads) | |
2313 | |
2314 (defun gdb-thread-list-handler-custom () | |
2315 (let* ((res (gdb-json-partial-output)) | |
2316 (threads-list (gdb-get-field res 'threads))) | |
2317 (setq gdb-threads-list nil) | |
2318 (setq gdb-running-threads-count 0) | |
2319 (setq gdb-stopped-threads-count 0) | |
2320 (set-marker gdb-thread-position nil) | |
2321 | |
2322 (dolist (thread (reverse threads-list)) | |
2323 (let ((running (string-equal (gdb-get-field thread 'state) "running"))) | |
2324 (add-to-list 'gdb-threads-list | |
2325 (cons (gdb-get-field thread 'id) | |
2326 thread)) | |
2327 (if running | |
2328 (incf gdb-running-threads-count) | |
2329 (incf gdb-stopped-threads-count)) | |
2330 | |
2331 (insert (apply 'format `("%s (%s) %s" | |
2332 ,@(gdb-get-many-fields thread 'id 'target-id 'state)))) | |
2333 ;; Include frame information for stopped threads | |
2334 (when (not running) | |
2335 (insert (concat " in " (gdb-get-field thread 'frame 'func))) | |
2336 (insert " (") | |
2337 (let ((args (gdb-get-field thread 'frame 'args))) | |
2338 (dolist (arg args) | |
2339 (insert (apply 'format `("%s=%s," ,@(gdb-get-many-fields arg 'name 'value))))) | |
2340 (when args (kill-backward-chars 1))) | |
2341 (insert ")") | |
2342 (gdb-insert-frame-location (gdb-get-field thread 'frame)) | |
2343 (insert (format " at %s" (gdb-get-field thread 'frame 'addr)))) | |
2344 (add-text-properties (line-beginning-position) | |
2345 (line-end-position) | |
2346 `(gdb-thread ,thread)) | |
2347 ;; We assume that gdb-thread-number is non-nil by this time | |
2348 (when (string-equal gdb-thread-number | |
2349 (gdb-get-field thread 'id)) | |
2350 (set-marker gdb-thread-position (line-beginning-position)))) | |
2351 (newline)) | |
2352 ;; We update gud-running here because we need to make sure that | |
2353 ;; gdb-threads-list is up-to-date | |
2354 (gdb-update-gud-running))) | |
2355 | |
2356 (defmacro def-gdb-thread-buffer-command (name custom-defun &optional doc) | |
2357 "Define a NAME command which will act upon thread on the current line. | |
2358 | |
2359 CUSTOM-DEFUN may use locally bound `thread' variable, which will | |
2360 be the value of 'gdb-thread property of the current line. If | |
2361 'gdb-thread is nil, error is signaled." | |
2362 `(defun ,name () | |
2363 ,(when doc doc) | |
2364 (interactive) | |
2365 (save-excursion | |
2366 (beginning-of-line) | |
2367 (let ((thread (get-text-property (point) 'gdb-thread))) | |
2368 (if thread | |
2369 ,custom-defun | |
2370 (error "Not recognized as thread line")))))) | |
2371 | |
2372 (defmacro def-gdb-thread-buffer-simple-command (name buffer-command &optional doc) | |
2373 "Define a NAME which will call BUFFER-COMMAND with id of thread | |
2374 on the current line." | |
2375 `(def-gdb-thread-buffer-command ,name | |
2376 (,buffer-command (gdb-get-field thread 'id)) | |
2377 ,doc)) | |
2378 | |
2379 (def-gdb-thread-buffer-command gdb-select-thread | |
2380 (let ((new-id (gdb-get-field thread 'id))) | |
2381 (gdb-setq-thread-number new-id) | |
2382 (gdb-input (list (concat "-thread-select " new-id) 'ignore)) | |
2383 (gdb-update)) | |
2384 "Select the thread at current line of threads buffer.") | |
2385 | |
2386 (def-gdb-thread-simple-buffer-command | |
2387 gdb-display-stack-for-thread | |
2388 gdb-display-stack-buffer | |
2389 "Display stack buffer for the thread at current line.") | |
2390 | |
2391 (def-gdb-thread-simple-buffer-command | |
2392 gdb-display-locals-for-thread | |
2393 gdb-display-locals-buffer | |
2394 "Display locals buffer for the thread at current line.") | |
2395 | |
2396 (def-gdb-thread-simple-buffer-command | |
2397 gdb-display-registers-for-thread | |
2398 gdb-display-registers-buffer | |
2399 "Display registers buffer for the thread at current line.") | |
2400 | |
2401 (def-gdb-thread-buffer-simple-command | |
2402 gdb-display-disassembly-for-thread | |
2403 gdb-display-disassembly-buffer | |
2404 "Display disassembly buffer for the thread at current line.") | |
2405 | |
2406 (def-gdb-thread-simple-buffer-command | |
2407 gdb-frame-stack-for-thread | |
2408 gdb-frame-stack-buffer | |
2409 "Display a new frame with stack buffer for the thread at | |
2410 current line.") | |
2411 | |
2412 (def-gdb-thread-simple-buffer-command | |
2413 gdb-frame-locals-for-thread | |
2414 gdb-frame-locals-buffer | |
2415 "Display a new frame with locals buffer for the thread at | |
2416 current line.") | |
2417 | |
2418 (def-gdb-thread-simple-buffer-command | |
2419 gdb-frame-registers-for-thread | |
2420 gdb-frame-registers-buffer | |
2421 "Display a new frame with registers buffer for the thread at | |
2422 current line.") | |
2423 | |
2424 (def-gdb-thread-buffer-simple-command | |
2425 gdb-frame-disassembly-for-thread | |
2426 gdb-frame-disassembly-buffer | |
2427 "Display a new frame with disassembly buffer for the thread at | |
2428 current line.") | |
2429 | |
2430 (defmacro def-gdb-thread-buffer-gdb-command (name gdb-command &optional doc) | |
2431 "Define a NAME which will execute send GDB-COMMAND with | |
2432 `gdb-thread-number' locally bound to id of thread on the current | |
2433 line." | |
2434 `(def-gdb-thread-buffer-command ,name | |
2435 (if gdb-non-stop | |
2436 (let ((gdb-thread-number (gdb-get-field thread 'id))) | |
2437 (gdb-input (list (gdb-current-context-command ,gdb-command) | |
2438 'ignore))) | |
2439 (error "Available in non-stop mode only, customize gdb-non-stop.")) | |
2440 ,doc)) | |
2441 | |
2442 ;; Does this make sense in all-stop mode? | |
2443 (def-gdb-thread-buffer-gdb-command | |
2444 gdb-interrupt-thread | |
2445 "-exec-interrupt" | |
2446 "Interrupt thread at current line.") | |
2447 | |
2448 (def-gdb-thread-buffer-gdb-command | |
2449 gdb-continue-thread | |
2450 "-exec-continue" | |
2451 "Continue thread at current line.") | |
2452 | |
2453 (def-gdb-thread-buffer-gdb-command | |
2454 gdb-step-thread | |
2455 "-exec-step" | |
2456 "Step thread at current line.") | |
2179 | 2457 |
2180 (defun gdb-set-header (buffer) | 2458 (defun gdb-set-header (buffer) |
2181 (cond ((eq buffer 'gdb-locals-buffer) | 2459 (cond ((eq buffer 'gdb-locals-buffer) |
2182 (list | 2460 (list |
2183 (gdb-propertize-header "Locals" gdb-locals-buffer | 2461 (gdb-propertize-header "Locals" gdb-locals-buffer |
2204 (gdb-propertize-header "Breakpoints" gdb-breakpoints-buffer | 2482 (gdb-propertize-header "Breakpoints" gdb-breakpoints-buffer |
2205 "mouse-1: select" mode-line-highlight mode-line-inactive) | 2483 "mouse-1: select" mode-line-highlight mode-line-inactive) |
2206 " " | 2484 " " |
2207 (gdb-propertize-header "Threads" gdb-threads-buffer | 2485 (gdb-propertize-header "Threads" gdb-threads-buffer |
2208 nil nil mode-line))))) | 2486 nil nil mode-line))))) |
2209 | |
2210 | |
2211 ;; uses "-thread-info". Needs GDB 7.0 onwards. | |
2212 ;;; Threads view | |
2213 | |
2214 (defun gdb-jump-to (file line) | |
2215 (find-file-other-window file) | |
2216 (goto-line line)) | |
2217 | |
2218 (define-button-type 'gdb-file-button | |
2219 'help-echo "Push to jump to source code" | |
2220 ; 'face 'bold | |
2221 'action | |
2222 (lambda (b) | |
2223 (gdb-jump-to (button-get b 'file) | |
2224 (button-get b 'line)))) | |
2225 | |
2226 (defun gdb-insert-file-location-button (file line) | |
2227 "Insert text button which allows jumping to FILE:LINE. | |
2228 | |
2229 FILE is a full path." | |
2230 (insert-text-button | |
2231 (format "%s:%d" (file-name-nondirectory file) line) | |
2232 :type 'gdb-file-button | |
2233 'file file | |
2234 'line line)) | |
2235 | |
2236 (defun gdb-threads-buffer-name () | |
2237 (concat "*threads of " (gdb-get-target-string) "*")) | |
2238 | |
2239 (def-gdb-display-buffer | |
2240 gdb-display-threads-buffer | |
2241 'gdb-threads-buffer | |
2242 "Display GDB threads.") | |
2243 | |
2244 (def-gdb-frame-for-buffer | |
2245 gdb-frame-threads-buffer | |
2246 'gdb-threads-buffer | |
2247 "Display GDB threads in a new frame.") | |
2248 | |
2249 (def-gdb-trigger-and-handler | |
2250 gdb-invalidate-threads "-thread-info" | |
2251 gdb-thread-list-handler gdb-thread-list-handler-custom | |
2252 '(update update-threads)) | |
2253 | |
2254 (gdb-set-buffer-rules | |
2255 'gdb-threads-buffer | |
2256 'gdb-threads-buffer-name | |
2257 'gdb-threads-mode | |
2258 'gdb-invalidate-threads) | |
2259 | |
2260 (defvar gdb-threads-font-lock-keywords | |
2261 '(("in \\([^ ]+\\) (" (1 font-lock-function-name-face)) | |
2262 (" \\(stopped\\) in " (1 font-lock-warning-face)) | |
2263 (" \\(running\\)" (1 font-lock-string-face)) | |
2264 ("\\(\\(\\sw\\|[_.]\\)+\\)=" (1 font-lock-variable-name-face))) | |
2265 "Font lock keywords used in `gdb-threads-mode'.") | |
2266 | |
2267 (defvar gdb-threads-mode-map | |
2268 (let ((map (make-sparse-keymap))) | |
2269 (define-key map "\r" 'gdb-select-thread) | |
2270 (define-key map "f" 'gdb-display-stack-for-thread) | |
2271 (define-key map "F" 'gdb-frame-stack-for-thread) | |
2272 (define-key map "l" 'gdb-display-locals-for-thread) | |
2273 (define-key map "L" 'gdb-frame-locals-for-thread) | |
2274 (define-key map "r" 'gdb-display-registers-for-thread) | |
2275 (define-key map "R" 'gdb-frame-registers-for-thread) | |
2276 (define-key map "d" 'gdb-display-disassembly-for-thread) | |
2277 (define-key map "D" 'gdb-frame-disassembly-for-thread) | |
2278 (define-key map "i" 'gdb-interrupt-thread) | |
2279 (define-key map "c" 'gdb-continue-thread) | |
2280 (define-key map "s" 'gdb-step-thread) | |
2281 map)) | |
2282 | |
2283 (defvar gdb-breakpoints-header | |
2284 (list | |
2285 (gdb-propertize-header "Breakpoints" gdb-breakpoints-buffer | |
2286 nil nil mode-line) | |
2287 " " | |
2288 (gdb-propertize-header "Threads" gdb-threads-buffer | |
2289 "mouse-1: select" mode-line-highlight mode-line-inactive))) | |
2290 (define-derived-mode gdb-threads-mode gdb-parent-mode "Threads" | |
2291 "Major mode for GDB threads. | |
2292 | |
2293 \\{gdb-threads-mode-map}" | |
2294 (setq gdb-thread-position (make-marker)) | |
2295 (add-to-list 'overlay-arrow-variable-list 'gdb-thread-position) | |
2296 (setq header-line-format gdb-breakpoints-header) | |
2297 (set (make-local-variable 'font-lock-defaults) | |
2298 '(gdb-threads-font-lock-keywords)) | |
2299 (run-mode-hooks 'gdb-threads-mode-hook) | |
2300 'gdb-invalidate-threads) | |
2301 | |
2302 (defun gdb-thread-list-handler-custom () | |
2303 (let* ((res (gdb-json-partial-output)) | |
2304 (threads-list (gdb-get-field res 'threads))) | |
2305 (setq gdb-threads-list nil) | |
2306 (setq gdb-running-threads-count 0) | |
2307 (setq gdb-stopped-threads-count 0) | |
2308 (set-marker gdb-thread-position nil) | |
2309 | |
2310 (dolist (thread (reverse threads-list)) | |
2311 (let ((running (string-equal (gdb-get-field thread 'state) "running"))) | |
2312 (add-to-list 'gdb-threads-list | |
2313 (cons (gdb-get-field thread 'id) | |
2314 thread)) | |
2315 (if running | |
2316 (incf gdb-running-threads-count) | |
2317 (incf gdb-stopped-threads-count)) | |
2318 | |
2319 (insert (apply 'format `("%s (%s) %s" | |
2320 ,@(gdb-get-many-fields thread 'id 'target-id 'state)))) | |
2321 ;; Include frame information for stopped threads | |
2322 (when (not running) | |
2323 (insert (concat " in " (gdb-get-field thread 'frame 'func))) | |
2324 (insert " (") | |
2325 (let ((args (gdb-get-field thread 'frame 'args))) | |
2326 (dolist (arg args) | |
2327 (insert (apply 'format `("%s=%s," ,@(gdb-get-many-fields arg 'name 'value))))) | |
2328 (when args (kill-backward-chars 1))) | |
2329 (insert ")") | |
2330 (gdb-insert-frame-location (gdb-get-field thread 'frame)) | |
2331 (insert (format " at %s" (gdb-get-field thread 'frame 'addr)))) | |
2332 (add-text-properties (line-beginning-position) | |
2333 (line-end-position) | |
2334 `(gdb-thread ,thread)) | |
2335 ;; We assume that gdb-thread-number is non-nil by this time | |
2336 (when (string-equal gdb-thread-number | |
2337 (gdb-get-field thread 'id)) | |
2338 (set-marker gdb-thread-position (line-beginning-position)))) | |
2339 (newline)) | |
2340 ;; We update gud-running here because we need to make sure that | |
2341 ;; gdb-threads-list is up-to-date | |
2342 (gdb-update-gud-running))) | |
2343 | |
2344 (defmacro def-gdb-thread-buffer-command (name custom-defun &optional doc) | |
2345 "Define a NAME command which will act upon thread on the current line. | |
2346 | |
2347 CUSTOM-DEFUN may use locally bound `thread' variable, which will | |
2348 be the value of 'gdb-thread property of the current line. If | |
2349 'gdb-thread is nil, error is signaled." | |
2350 `(defun ,name () | |
2351 ,(when doc doc) | |
2352 (interactive) | |
2353 (save-excursion | |
2354 (beginning-of-line) | |
2355 (let ((thread (get-text-property (point) 'gdb-thread))) | |
2356 (if thread | |
2357 ,custom-defun | |
2358 (error "Not recognized as thread line")))))) | |
2359 | |
2360 (defmacro def-gdb-thread-buffer-simple-command (name buffer-command &optional doc) | |
2361 "Define a NAME which will call BUFFER-COMMAND with id of thread | |
2362 on the current line." | |
2363 `(def-gdb-thread-buffer-command ,name | |
2364 (,buffer-command (gdb-get-field thread 'id)) | |
2365 ,doc)) | |
2366 | |
2367 (def-gdb-thread-buffer-command gdb-select-thread | |
2368 (let ((new-id (gdb-get-field thread 'id))) | |
2369 (gdb-setq-thread-number new-id) | |
2370 (gdb-input (list (concat "-thread-select " new-id) 'ignore)) | |
2371 (gdb-update)) | |
2372 "Select the thread at current line of threads buffer.") | |
2373 | |
2374 (def-gdb-thread-simple-buffer-command | |
2375 gdb-display-stack-for-thread | |
2376 gdb-display-stack-buffer | |
2377 "Display stack buffer for the thread at current line.") | |
2378 | |
2379 (def-gdb-thread-simple-buffer-command | |
2380 gdb-display-locals-for-thread | |
2381 gdb-display-locals-buffer | |
2382 "Display locals buffer for the thread at current line.") | |
2383 | |
2384 (def-gdb-thread-simple-buffer-command | |
2385 gdb-display-registers-for-thread | |
2386 gdb-display-registers-buffer | |
2387 "Display registers buffer for the thread at current line.") | |
2388 | |
2389 (def-gdb-thread-buffer-simple-command | |
2390 gdb-display-disassembly-for-thread | |
2391 gdb-display-disassembly-buffer | |
2392 "Display disassembly buffer for the thread at current line.") | |
2393 | |
2394 (def-gdb-thread-simple-buffer-command | |
2395 gdb-frame-stack-for-thread | |
2396 gdb-frame-stack-buffer | |
2397 "Display a new frame with stack buffer for the thread at | |
2398 current line.") | |
2399 | |
2400 (def-gdb-thread-simple-buffer-command | |
2401 gdb-frame-locals-for-thread | |
2402 gdb-frame-locals-buffer | |
2403 "Display a new frame with locals buffer for the thread at | |
2404 current line.") | |
2405 | |
2406 (def-gdb-thread-simple-buffer-command | |
2407 gdb-frame-registers-for-thread | |
2408 gdb-frame-registers-buffer | |
2409 "Display a new frame with registers buffer for the thread at | |
2410 current line.") | |
2411 | |
2412 (def-gdb-thread-buffer-simple-command | |
2413 gdb-frame-disassembly-for-thread | |
2414 gdb-frame-disassembly-buffer | |
2415 "Display a new frame with disassembly buffer for the thread at | |
2416 current line.") | |
2417 | |
2418 (defmacro def-gdb-thread-buffer-gdb-command (name gdb-command &optional doc) | |
2419 "Define a NAME which will execute send GDB-COMMAND with | |
2420 `gdb-thread-number' locally bound to id of thread on the current | |
2421 line." | |
2422 `(def-gdb-thread-buffer-command ,name | |
2423 (if gdb-non-stop | |
2424 (let ((gdb-thread-number (gdb-get-field thread 'id))) | |
2425 (gdb-input (list (gdb-current-context-command ,gdb-command) | |
2426 'ignore))) | |
2427 (error "Available in non-stop mode only, customize gdb-non-stop.")) | |
2428 ,doc)) | |
2429 | |
2430 ;; Does this make sense in all-stop mode? | |
2431 (def-gdb-thread-buffer-gdb-command | |
2432 gdb-interrupt-thread | |
2433 "-exec-interrupt" | |
2434 "Interrupt thread at current line.") | |
2435 | |
2436 (def-gdb-thread-buffer-gdb-command | |
2437 gdb-continue-thread | |
2438 "-exec-continue" | |
2439 "Continue thread at current line.") | |
2440 | |
2441 (def-gdb-thread-buffer-gdb-command | |
2442 gdb-step-thread | |
2443 "-exec-step" | |
2444 "Step thread at current line.") | |
2445 | 2487 |
2446 | 2488 |
2447 ;;; Memory view | 2489 ;;; Memory view |
2448 | 2490 |
2449 (defcustom gdb-memory-rows 8 | 2491 (defcustom gdb-memory-rows 8 |
2849 'gdb-disassembly-buffer | 2891 'gdb-disassembly-buffer |
2850 "Display disassembly in a new frame.") | 2892 "Display disassembly in a new frame.") |
2851 | 2893 |
2852 (def-gdb-auto-update-trigger gdb-invalidate-disassembly | 2894 (def-gdb-auto-update-trigger gdb-invalidate-disassembly |
2853 (let* ((frame (gdb-current-buffer-frame)) | 2895 (let* ((frame (gdb-current-buffer-frame)) |
2854 (file (gdb-get-field frame 'file)) | 2896 (file (gdb-get-field frame 'fullname)) |
2855 (line (gdb-get-field frame 'line))) | 2897 (line (gdb-get-field frame 'line))) |
2856 (when file | 2898 (when file |
2857 (format "-data-disassemble -f %s -l %s -n -1 -- 0" file line))) | 2899 (format "-data-disassemble -f %s -l %s -n -1 -- 0" file line))) |
2858 gdb-disassembly-handler) | 2900 gdb-disassembly-handler) |
2859 | 2901 |
3373 ;; Insert first prompt. | 3415 ;; Insert first prompt. |
3374 (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name))) | 3416 (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name))) |
3375 | 3417 |
3376 ;;;; Window management | 3418 ;;;; Window management |
3377 (defun gdb-display-buffer (buf dedicated &optional frame) | 3419 (defun gdb-display-buffer (buf dedicated &optional frame) |
3420 "Show buffer BUF. | |
3421 | |
3422 If BUF is already displayed in some window, show it, deiconifying | |
3423 the frame if necessary. Otherwise, find least recently used | |
3424 window and show BUF there, if the window is not used for GDB | |
3425 already, in which case that window is splitted first." | |
3378 (let ((answer (get-buffer-window buf (or frame 0)))) | 3426 (let ((answer (get-buffer-window buf (or frame 0)))) |
3379 (if answer | 3427 (if answer |
3380 (display-buffer buf nil (or frame 0)) ;Deiconify the frame if necessary. | 3428 (display-buffer buf nil (or frame 0)) ;Deiconify the frame if necessary. |
3381 (let ((window (get-lru-window))) | 3429 (let ((window (get-lru-window))) |
3382 (if (eq (buffer-local-value 'gud-minor-mode (window-buffer window)) | 3430 (if (eq (buffer-local-value 'gud-minor-mode (window-buffer window)) |
3424 (define-key menu [locals] '("Locals" . gdb-frame-locals-buffer)) | 3472 (define-key menu [locals] '("Locals" . gdb-frame-locals-buffer)) |
3425 (define-key menu [frames] '("Stack" . gdb-frame-stack-buffer)) | 3473 (define-key menu [frames] '("Stack" . gdb-frame-stack-buffer)) |
3426 (define-key menu [breakpoints] | 3474 (define-key menu [breakpoints] |
3427 '("Breakpoints" . gdb-frame-breakpoints-buffer))) | 3475 '("Breakpoints" . gdb-frame-breakpoints-buffer))) |
3428 | 3476 |
3429 (let ((menu (make-sparse-keymap "GDB-MI")) | 3477 (let ((menu (make-sparse-keymap "GDB-MI"))) |
3430 (submenu (make-sparse-keymap "GUD thread control mode"))) | |
3431 (define-key menu [gdb-customize] | 3478 (define-key menu [gdb-customize] |
3432 '(menu-item "Customize" (lambda () (interactive) (customize-group 'gdb)) | 3479 '(menu-item "Customize" (lambda () (interactive) (customize-group 'gdb)) |
3433 :help "Customize Gdb Graphical Mode options.")) | 3480 :help "Customize Gdb Graphical Mode options.")) |
3434 (define-key menu [gdb-many-windows] | 3481 (define-key menu [gdb-many-windows] |
3435 '(menu-item "Display Other Windows" gdb-many-windows | 3482 '(menu-item "Display Other Windows" gdb-many-windows |
3438 (define-key menu [gdb-restore-windows] | 3485 (define-key menu [gdb-restore-windows] |
3439 '(menu-item "Restore Window Layout" gdb-restore-windows | 3486 '(menu-item "Restore Window Layout" gdb-restore-windows |
3440 :help "Restore standard layout for debug session.")) | 3487 :help "Restore standard layout for debug session.")) |
3441 (define-key menu [sep1] | 3488 (define-key menu [sep1] |
3442 '(menu-item "--")) | 3489 '(menu-item "--")) |
3443 (define-key submenu [all-threads] | 3490 (define-key menu [all-threads] |
3444 '(menu-item "All threads" | 3491 '(menu-item "GUD controls all threads" |
3445 (lambda () | 3492 (lambda () |
3446 (interactive) | 3493 (interactive) |
3447 (setq gdb-gud-control-all-threads t)) | 3494 (setq gdb-gud-control-all-threads t)) |
3448 :help "GUD start/stop commands apply to all threads" | 3495 :help "GUD start/stop commands apply to all threads" |
3449 :button (:radio . gdb-gud-control-all-threads))) | 3496 :button (:radio . gdb-gud-control-all-threads))) |
3450 (define-key submenu [current-thread] | 3497 (define-key menu [current-thread] |
3451 '(menu-item "Current thread" | 3498 '(menu-item "GUD controls current thread" |
3452 (lambda () | 3499 (lambda () |
3453 (interactive) | 3500 (interactive) |
3454 (setq gdb-gud-control-all-threads nil)) | 3501 (setq gdb-gud-control-all-threads nil)) |
3455 :help "GUD start/stop commands apply to current thread only" | 3502 :help "GUD start/stop commands apply to current thread only" |
3456 :button (:radio . (not gdb-gud-control-all-threads)))) | 3503 :button (:radio . (not gdb-gud-control-all-threads)))) |
3457 (define-key menu [thread-control] | 3504 (define-key menu [sep2] |
3458 `("GUD thread control mode" . ,submenu)) | 3505 '(menu-item "--")) |
3459 (define-key gud-menu-map [mi] | 3506 (define-key menu [gdb-customize-reasons] |
3460 `(menu-item "GDB-MI" ,menu :visible (eq gud-minor-mode 'gdbmi))) | 3507 '(menu-item "Customize switching..." |
3508 (lambda () | |
3509 (interactive) | |
3510 (customize-option 'gdb-switch-reasons)))) | |
3461 (define-key menu [gdb-switch-when-another-stopped] | 3511 (define-key menu [gdb-switch-when-another-stopped] |
3462 (menu-bar-make-toggle gdb-toggle-switch-when-another-stopped gdb-switch-when-another-stopped | 3512 (menu-bar-make-toggle gdb-toggle-switch-when-another-stopped gdb-switch-when-another-stopped |
3463 "Automatically switch to stopped thread" | 3513 "Automatically switch to stopped thread" |
3464 "GDB thread switching %s" | 3514 "GDB thread switching %s" |
3465 "Switch to stopped thread")) | 3515 "Switch to stopped thread")) |
3466 (define-key menu [gdb-non-stop] | 3516 (define-key gud-menu-map [mi] |
3467 (menu-bar-make-toggle gdb-toggle-non-stop gdb-non-stop | 3517 `(menu-item "GDB-MI" ,menu :visible (eq gud-minor-mode 'gdbmi)))) |
3468 "Non-stop mode" | |
3469 "GDB non-stop mode %s" | |
3470 "Allow examining stopped threads while others continue to execute"))) | |
3471 | 3518 |
3472 (defun gdb-frame-gdb-buffer () | 3519 (defun gdb-frame-gdb-buffer () |
3473 "Display GUD buffer in a new frame." | 3520 "Display GUD buffer in a new frame." |
3474 (interactive) | 3521 (interactive) |
3475 (let ((special-display-regexps (append special-display-regexps '(".*"))) | 3522 (let ((special-display-regexps (append special-display-regexps '(".*"))) |