Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

947 lines
37 KiB

  1. ;; Copyright (C) 2015-2019 Free Software Foundation, Inc
  2. ;; Author: Rocky Bernstein <rocky@gnu.org>
  3. ;; This program is free software; you can redistribute it and/or modify
  4. ;; it under the terms of the GNU General Public License as published by
  5. ;; the Free Software Foundation, either version 3 of the License, or
  6. ;; (at your option) any later version.
  7. ;; This program is distributed in the hope that it will be useful,
  8. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. ;; GNU General Public License for more details.
  11. ;; You should have received a copy of the GNU General Public License
  12. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. (declare-function realgud:terminate &optional cmdbuf)
  14. (defconst realgud-track-char-range 10000
  15. "Max number of characters from end of buffer to search for stack entry.")
  16. ;; Shell process buffers that we can hook into:
  17. (require 'esh-mode)
  18. (require 'ansi-color)
  19. (require 'comint)
  20. (require 'load-relative)
  21. (require-relative-list
  22. '("core" "file" "fringe"
  23. "helper" "init" "loc" "lochist"
  24. "regexp" "shortkey" "window" "utils"
  25. "bp"
  26. ) "realgud-")
  27. (require-relative-list
  28. '("buffer/command" "buffer/helper" "buffer/source") "realgud-buffer-")
  29. (defcustom realgud-short-key-on-tracing? nil
  30. "If non-nil, set short-key mode for any source buffer that is traced into"
  31. :type 'symbolp
  32. :group 'realgud)
  33. (defcustom realgud-eval-message-print-length 1000
  34. "If non-nil, truncate eval output into the echo area"
  35. :type 'symbolp
  36. :group 'realgud)
  37. (declare-function buffer-killed? 'realgud-helper)
  38. (declare-function fn-p-to-fn?-alias 'realgud-helper)
  39. (declare-function realgud-bp-add-info 'realgud-bp)
  40. (declare-function realgud-bp-del-info 'realgud-bp)
  41. (declare-function realgud-bp-enable-disable-info 'realgud-bp)
  42. (declare-function realgud-cmdbuf-add-srcbuf 'realgud-buffer-command)
  43. (declare-function realgud-cmdbuf-debugger-name 'realgud-buffer-command)
  44. (declare-function realgud-cmdbuf-info-bp-list= 'realgud-buffer-command)
  45. (declare-function realgud-cmdbuf-info-divert-output?= 'realgud-buffer-command)
  46. (declare-function realgud-cmdbuf-info-in-debugger? 'realgud-buffer-command)
  47. (declare-function realgud-cmdbuf-info-in-debugger?= 'realgud-buffer-command)
  48. (declare-function realgud-cmdbuf-info-last-input-end= 'realgud-buffer-command)
  49. (declare-function realgud-cmdbuf-init 'realgud-buffer-command)
  50. (declare-function realgud-cmdbuf-loc-hist 'realgud-buffer-command)
  51. (declare-function realgud-cmdbuf-mode-line-update 'realgud-buffer-command)
  52. (declare-function realgud-cmdbuf-mode-line-update 'realgud-buffer-command)
  53. (declare-function realgud-cmdbuf-pat 'realgud-buffer-command)
  54. (declare-function realgud-cmdbuf? 'realgud-buffer-command)
  55. (declare-function realgud-cmdbuf-info-in-srcbuf?= 'realgud-buffer-command)
  56. (declare-function realgud:debugger-name-transform 'realgud-helper)
  57. (declare-function realgud:terminate 'realgud-core)
  58. (declare-function realgud:file-loc-from-line 'realgud-file)
  59. (declare-function realgud-fringe-history-set 'realgud-fringe)
  60. (declare-function realgud-get-cmdbuf 'realgud-buffer-command)
  61. (declare-function realgud-get-srcbuf-from-cmdbuf 'realgud-buffer-helper)
  62. (declare-function realgud-loc-goto 'realgud-loc)
  63. (declare-function realgud-loc-hist-add 'realgud-lochist)
  64. (declare-function realgud-loc-hist-index 'realgud-lochist)
  65. (declare-function realgud-loc-hist-item 'realgud-lochist)
  66. (declare-function realgud-loc? 'realgud-loc)
  67. (declare-function realgud-short-key-mode-setup 'realgud-shortkey)
  68. (declare-function realgud-srcbuf-init-or-update 'realgud-source)
  69. (declare-function realgud-srcbuf-loc-hist 'realgud-source)
  70. (declare-function realgud-window-src 'realgud-window)
  71. (declare-function realgud-window-src-undisturb-cmd 'realgud-window)
  72. (declare-function realgud-window-update-position 'realgud-window)
  73. (declare-function realgud:join-string 'realgud-utils)
  74. (make-variable-buffer-local (defvar realgud-track-mode))
  75. (fn-p-to-fn?-alias 'realgud-loc-p)
  76. (defvar realgud-track-divert-string
  77. ""
  78. "Some commands need information from the debugger to perform certain actions, such as show what breapoints exist, give back trace information. The output of debugger commands which need to be captured, are stored in this buffer-local string variable.")
  79. (defvar starting-directory
  80. nil
  81. "When set this indicates the base directory that source code path should be based off of when the path is a relative path."
  82. )
  83. (defvar realgud-command-name-hash
  84. nil
  85. "This buffer-local hash maps a debugger, like `gdb', or `pdb', to a hash table which describes how to implement generic debugger functions into the commands of that debugger. This information is set up by individual `init' function of the debugger. The keys at any given time will be those debuggers that have been used so far in the Emacs session.")
  86. (defun realgud-track-comint-output-filter-hook(text)
  87. "An output-filter hook custom for comint shells. Find
  88. location/s, if any, and run the action(s) associated with
  89. finding a new location/s. The parameter TEXT appears because it
  90. is part of the comint-output-filter-functions API. Instead we use
  91. marks set in buffer-local variables to extract text"
  92. ;; Instead of trying to piece things together from partial text
  93. ;; (which can be almost useless depending on Emacs version), we
  94. ;; monitor to the point where we have the next dbgr prompt, and then
  95. ;; check all text from comint-last-input-end to process-mark.
  96. ;; FIXME: Add unwind-protect?
  97. (if (and realgud-track-mode (realgud-cmdbuf? (current-buffer)))
  98. (let* ((cmd-buff (current-buffer))
  99. (cmd-mark (point-marker))
  100. (shortkey
  101. (realgud-cmdbuf-info-src-shortkey?
  102. realgud-cmdbuf-info))
  103. (curr-proc (get-buffer-process cmd-buff))
  104. (cmdbuf-last-output-end
  105. (realgud-cmdbuf-info-last-input-end realgud-cmdbuf-info))
  106. (last-output-end
  107. (if curr-proc
  108. (process-mark curr-proc)
  109. cmdbuf-last-output-end))
  110. (last-output-start (max comint-last-input-start
  111. (- last-output-end realgud-track-char-range))))
  112. ;; Sometimes we get called twice and the second time nothing
  113. ;; changes. Guard against this.
  114. (unless (= last-output-start last-output-end)
  115. (unless (= last-output-end cmdbuf-last-output-end)
  116. (setq last-output-start (max last-output-start
  117. cmdbuf-last-output-end))
  118. )
  119. ;; Done with using old command buffer's last-input-end.
  120. ;; Update that for next time.
  121. (realgud-cmdbuf-info-last-input-end= last-output-start)
  122. (realgud:track-from-region last-output-start
  123. last-output-end cmd-mark cmd-buff
  124. shortkey 't))
  125. )
  126. )
  127. )
  128. (defun realgud-track-eshell-output-filter-hook()
  129. "An output-filter hook custom for eshell shells. Find
  130. location(s), if any, and run the action(s) associated with We use
  131. marks set in buffer-local variables to extract text"
  132. ;; FIXME: Add unwind-protect?
  133. (if realgud-track-mode
  134. (let* ((cmd-buff (current-buffer))
  135. (cmd-mark (point-marker))
  136. (shortkey
  137. (realgud-cmdbuf-info-src-shortkey?
  138. realgud-cmdbuf-info))
  139. (loc (realgud:track-from-region
  140. eshell-last-output-start
  141. eshell-last-output-end cmd-mark cmd-buff
  142. shortkey)))
  143. (realgud-track-loc-action loc cmd-buff 't shortkey))
  144. ))
  145. (defun realgud-track-term-output-filter-hook(text)
  146. "An output-filter hook custom for ansi-term shells. Find
  147. location/s, if any, and run the action(s) associated with
  148. finding a new location/s. The parameter TEXT appears because it
  149. is part of the comint-output-filter-functions API. Instead we use
  150. marks set in buffer-local variables to extract text"
  151. (if (and realgud-track-mode (realgud-cmdbuf? (current-buffer)))
  152. (realgud-track-loc text (point-marker))
  153. ))
  154. (defun realgud:track-complain-if-not-in-cmd-buffer (&optional buf errorp)
  155. "Complain if BUF (default: current buffer) is not a command buffer.
  156. With non-nil ERRORP, raise an exception. Otherwise, print a
  157. message."
  158. (setq buf (or buf (current-buffer)))
  159. (unless (realgud-cmdbuf? buf)
  160. (funcall (if errorp #'error #'message)
  161. "Buffer %s is not a debugger command buffer" buf)
  162. t))
  163. (defun realgud:get-output-command(text)
  164. "Splits the TEXT by newline."
  165. (car (split-string text "\n")))
  166. (defun realgud:get-eval-output(text)
  167. "Gets the output stripping the command and debugger prompt from the TEXT."
  168. (realgud:join-string (butlast (cdr (split-string text "\n"))) "\n"))
  169. (defun realgud:get-command-name(command-name)
  170. "Gets the COMMAND-NAME for this particular debugger."
  171. (gethash command-name (buffer-local-value 'realgud-command-name-hash (current-buffer))))
  172. (defun realgud:eval-command-p(text)
  173. "Checks the TEXT if the command that was ran was an eval command."
  174. (let ((cmd-name (realgud:get-command-name "eval")))
  175. (and (stringp cmd-name) (string-prefix-p (realgud:get-command-name "eval") (realgud:get-output-command text)))))
  176. (defun realgud:truncate-eval-message(text)
  177. "Truncates the TEXT to the size of realgud-eval-message-print-length."
  178. (if (< realgud-eval-message-print-length (length text))
  179. (substring text 0 realgud-eval-message-print-length)
  180. text))
  181. (defun realgud:message-eval-results(text)
  182. "Output the TEXT to the message area."
  183. (message (realgud:truncate-eval-message (realgud:get-eval-output text))))
  184. (defun realgud:track-from-region(from to &optional cmd-mark opt-cmdbuf
  185. shortkey-on-tracing? no-warn-if-no-match?)
  186. "Find and position a buffer at the location found in the marked region.
  187. You might want to use this function interactively after marking a
  188. region in a debugger-tracked shell buffer (see `realgud-track-mode')
  189. or a more dedicated debugger command buffer.
  190. The marked region location should match the regexp found in the
  191. buffer-local variable `realgud-cmdbuf-info' structure under the
  192. field loc-regexp. You can see what this is by
  193. evaluating (realgud-cmdbuf-info-loc-regexp realgud-cmdbuf-info)"
  194. (interactive "r")
  195. (if (> from to) (cl-psetq to from from to))
  196. (let* ((text (buffer-substring-no-properties from to))
  197. (loc (realgud-track-loc text cmd-mark))
  198. ;; If we see a selected frame number, it is stored
  199. ;; in frame-num. Otherwise, nil.
  200. (frame-num)
  201. (text-sans-loc)
  202. (cmdbuf (or opt-cmdbuf (current-buffer)))
  203. )
  204. (unless (realgud:track-complain-if-not-in-cmd-buffer cmdbuf t)
  205. (if (realgud:eval-command-p text)
  206. (realgud:message-eval-results text))
  207. (if (not (equal "" text))
  208. (with-current-buffer cmdbuf
  209. (if (realgud-sget 'cmdbuf-info 'divert-output?)
  210. (realgud-track-divert-prompt text cmdbuf to))
  211. ;; FIXME: instead of these fixed filters,
  212. ;; put into a list and iterate over that.
  213. (realgud-track-termination? text)
  214. (setq text-sans-loc (or (realgud-track-loc-remaining text) text))
  215. (setq frame-num (realgud-track-selected-frame text))
  216. (if (and frame-num (not loc))
  217. (setq loc (realgud-track-loc-from-selected-frame
  218. text cmd-mark)))
  219. (realgud:track-handle-breakpoints text-sans-loc cmd-mark cmdbuf)
  220. (if loc
  221. (let ((selected-frame
  222. (or (not frame-num)
  223. (eq frame-num (realgud-cmdbuf-pat "top-frame-num")))))
  224. (realgud-track-loc-action loc cmdbuf (not selected-frame)
  225. shortkey-on-tracing?)
  226. (realgud-cmdbuf-info-in-debugger?= 't)
  227. (realgud-cmdbuf-mode-line-update)))
  228. )
  229. )
  230. )
  231. )
  232. )
  233. (defun realgud:track-handle-breakpoints (text-sans-loc cmd-mark cmdbuf)
  234. (realgud:track-add-breakpoint text-sans-loc cmd-mark cmdbuf)
  235. (realgud:track-remove-breakpoints text-sans-loc cmd-mark cmdbuf))
  236. (defun realgud:track-add-breakpoint (text-sans-loc cmd-mark cmdbuf)
  237. "Add a breakpoint fringe in source window if BP-LOC."
  238. (realgud-track-bp-enable-disable text-sans-loc
  239. (realgud-cmdbuf-pat "brkpt-enable")
  240. 't)
  241. (let ((bp-loc (realgud-track-bp-loc text-sans-loc cmd-mark cmdbuf)))
  242. (if bp-loc
  243. (let ((src-buffer (realgud-loc-goto bp-loc)))
  244. (realgud-cmdbuf-add-srcbuf src-buffer cmdbuf)
  245. (with-current-buffer src-buffer
  246. (realgud-bp-add-info bp-loc))))))
  247. (defun realgud:track-remove-breakpoints (text-sans-loc cmd-mark cmdbuf)
  248. "Remove all breakpoints in source window found in BP-LOCS."
  249. (realgud-track-bp-enable-disable text-sans-loc
  250. (realgud-cmdbuf-pat "brkpt-disable")
  251. nil)
  252. (dolist (bp-loc (realgud-track-bp-delete text-sans-loc cmd-mark cmdbuf))
  253. (let ((src-buffer (realgud-loc-goto bp-loc)))
  254. (realgud-cmdbuf-add-srcbuf src-buffer cmdbuf)
  255. (with-current-buffer src-buffer
  256. (realgud-bp-del-info bp-loc)))))
  257. (defun realgud-track-hist-fn-internal(fn)
  258. "Update both command buffer and a source buffer to reflect the
  259. selected location in the location history. If we started in a
  260. command buffer, we stay in a command buffer. Moving inside a
  261. command buffer always shows the corresponding source
  262. file. However it is possible in shortkey mode to show only the
  263. source code window, even the commmand buffer is updated albeit
  264. unshown."
  265. (let ((cmdbuf (realgud-get-cmdbuf (current-buffer))))
  266. (if cmdbuf
  267. (let* ((loc-hist (realgud-cmdbuf-loc-hist cmdbuf))
  268. (window (selected-window))
  269. (position (funcall fn loc-hist))
  270. (stay-in-cmdbuf?
  271. (or (eq (current-buffer) cmdbuf)
  272. (with-current-buffer cmdbuf
  273. (not (realgud-sget 'cmdbuf-info 'in-srcbuf?)))))
  274. (loc (realgud-loc-hist-item loc-hist))
  275. (srcbuf (realgud-get-srcbuf-from-cmdbuf cmdbuf loc))
  276. )
  277. (set-buffer (realgud-loc-goto loc))
  278. ;; Make sure command buffer is updated
  279. (realgud-window-update-position cmdbuf
  280. (realgud-loc-cmd-marker loc))
  281. ;; FIXME turn into fn. combine with realgud-track-loc-action.
  282. (if stay-in-cmdbuf?
  283. (let ((cmd-window (realgud-window-src-undisturb-cmd srcbuf)))
  284. (if cmd-window (select-window cmd-window)))
  285. (realgud-window-src srcbuf)
  286. )
  287. ;; Make sure source buffer is updated
  288. (realgud-window-update-position srcbuf
  289. (realgud-loc-marker loc))
  290. (message "history position %s line %s"
  291. (realgud-loc-hist-index loc-hist)
  292. (realgud-loc-line-number loc))
  293. (select-window window)))
  294. ))
  295. ;; FIXME: Can we dry code more via a macro?
  296. (defun realgud-track-hist-newer()
  297. (interactive)
  298. (realgud-track-hist-fn-internal 'realgud-loc-hist-newer))
  299. (defun realgud-track-hist-newest()
  300. (interactive)
  301. (realgud-track-hist-fn-internal 'realgud-loc-hist-newest))
  302. (defun realgud-track-hist-older()
  303. (interactive)
  304. (realgud-track-hist-fn-internal 'realgud-loc-hist-older))
  305. (defun realgud-track-hist-oldest()
  306. (interactive)
  307. (realgud-track-hist-fn-internal 'realgud-loc-hist-oldest))
  308. (defun realgud-track-loc-action (loc cmdbuf &optional not-selected-frame
  309. shortkey-on-tracing?)
  310. "If loc is valid, show loc and do whatever actions we do for
  311. encountering a new loc."
  312. (if (realgud-loc? loc)
  313. (let*
  314. ((cmdbuf-loc-hist (realgud-cmdbuf-loc-hist cmdbuf))
  315. (cmdbuf-local-overlay-arrow?
  316. (with-current-buffer cmdbuf
  317. (local-variable-p 'overlay-arrow-variable-list)))
  318. (stay-in-cmdbuf?
  319. (with-current-buffer cmdbuf
  320. (not (realgud-sget 'cmdbuf-info 'in-srcbuf?))))
  321. (shortkey-mode?
  322. (with-current-buffer cmdbuf
  323. (realgud-sget 'cmdbuf-info 'src-shortkey?)))
  324. (srcbuf)
  325. (srcbuf-loc-hist)
  326. )
  327. (setq srcbuf (realgud-loc-goto loc))
  328. (realgud-srcbuf-init-or-update srcbuf cmdbuf)
  329. (setq srcbuf-loc-hist (realgud-srcbuf-loc-hist srcbuf))
  330. (realgud-cmdbuf-add-srcbuf srcbuf cmdbuf)
  331. (with-current-buffer srcbuf
  332. (realgud-short-key-mode-setup
  333. (and shortkey-on-tracing?
  334. (or realgud-short-key-on-tracing? shortkey-mode?))
  335. ))
  336. ;; Do we need to go back to the process/command buffer because other
  337. ;; output-filter hooks run after this may assume they are in that
  338. ;; buffer? If so, we may have to use set-buffer rather than
  339. ;; switch-to-buffer in some cases.
  340. (set-buffer cmdbuf)
  341. (unless (realgud-sget 'cmdbuf-info 'no-record?)
  342. (realgud-loc-hist-add srcbuf-loc-hist loc)
  343. (realgud-loc-hist-add cmdbuf-loc-hist loc)
  344. (realgud-fringe-history-set cmdbuf-loc-hist cmdbuf-local-overlay-arrow?)
  345. )
  346. ;; FIXME turn into fn. combine with realgud-track-hist-fn-internal
  347. (if stay-in-cmdbuf?
  348. (let ((cmd-window (realgud-window-src-undisturb-cmd srcbuf)))
  349. (with-current-buffer srcbuf
  350. (if (and (boundp 'realgud-overlay-arrow1)
  351. (markerp realgud-overlay-arrow1))
  352. (progn
  353. ;; Doesn't work
  354. ;; (if not-selected-frame
  355. ;; (set-fringe-bitmap-face 'hollow-right-triangle
  356. ;; 'realgud-overlay-arrow1)
  357. ;; ; else
  358. ;; (set-fringe-bitmap-face 'realgud-right-triangle1
  359. ;; 'realgud-overlay-arrow1)
  360. ;; )
  361. (realgud-window-update-position srcbuf realgud-overlay-arrow1)))
  362. )
  363. (if cmd-window (select-window cmd-window)))
  364. ; else
  365. (with-current-buffer srcbuf
  366. (realgud-window-src srcbuf)
  367. (realgud-window-update-position srcbuf realgud-overlay-arrow1))
  368. ;; reset 'in-srcbuf' to allow the command buffer to keep point focus
  369. ;; when used directly. 'in-srcbuf' is set 't' early in the stack
  370. ;; (prior to common command code, e.g. this) when any command is run
  371. ;; from a source buffer
  372. (with-current-buffer cmdbuf
  373. (realgud-cmdbuf-info-in-srcbuf?= nil))
  374. )
  375. ))
  376. )
  377. (defun realgud-track-loc(text cmd-mark &optional opt-regexp opt-file-group
  378. opt-line-group no-warn-on-no-match?)
  379. "Do regular-expression matching to find a file name and line number inside
  380. string TEXT. If we match, we will turn the result into a realgud-loc struct.
  381. Otherwise return nil."
  382. ;; NOTE: realgud-cmdbuf-info is a buffer variable local to the process running
  383. ;; the debugger. It contains a realgud-cmdbuf-info "struct". In that struct are
  384. ;; the fields loc-regexp, file-group, line-group, alt-file-group, and alt-line-group.
  385. ;;
  386. ;; By setting the the fields of realgud-cmdbuf-info appropriately, we
  387. ;; can accomodate a family of debuggers -- one at a time -- for the
  388. ;; buffer process.
  389. (unless (realgud:track-complain-if-not-in-cmd-buffer)
  390. (let
  391. ((loc-regexp (or opt-regexp
  392. (realgud-sget 'cmdbuf-info 'loc-regexp)))
  393. (file-group (or opt-file-group
  394. (realgud-sget 'cmdbuf-info 'file-group)))
  395. (line-group (or opt-line-group
  396. (realgud-sget 'cmdbuf-info 'line-group)))
  397. (alt-file-group (realgud-sget 'cmdbuf-info 'alt-file-group))
  398. (alt-line-group (realgud-sget 'cmdbuf-info 'alt-line-group))
  399. (text-group (realgud-sget 'cmdbuf-info 'text-group))
  400. (callback-loc-fn (realgud-sget 'cmdbuf-info 'callback-loc-fn))
  401. )
  402. (if loc-regexp
  403. (if (string-match loc-regexp text)
  404. (let* ((filename (or (match-string file-group text)
  405. (match-string alt-file-group text)))
  406. (line-str (or (match-string line-group text)
  407. (match-string alt-line-group text)))
  408. (source-str (and text-group
  409. (match-string text-group text)))
  410. (lineno (string-to-number (or line-str "1")))
  411. (directory
  412. (cond ((boundp 'starting-directory) starting-directory)
  413. (t nil)))
  414. )
  415. (when source-str
  416. (setq source-str (ansi-color-filter-apply
  417. source-str)))
  418. (cond ((and nil callback-loc-fn)
  419. (funcall callback-loc-fn text
  420. filename lineno source-str
  421. cmd-mark directory))
  422. ('t
  423. (unless line-str
  424. (message "line number not found -- using 1"))
  425. (if (and filename lineno)
  426. (realgud:file-loc-from-line filename lineno
  427. cmd-mark
  428. source-str nil
  429. nil
  430. directory
  431. )
  432. ;; else
  433. nil)))))
  434. ;; else
  435. (and (message
  436. (concat "Buffer variable for regular expression pattern not"
  437. " given and not passed as a parameter"))
  438. nil)))
  439. )
  440. )
  441. (defun realgud-track-bp-loc(text &optional cmd-mark cmdbuf opt-ignore-re-file-list)
  442. "Do regular-expression matching to find a file name and line number inside
  443. string TEXT. If we match, we will turn the result into a realgud-loc struct.
  444. Otherwise return nil. CMD-MARK is set in the realgud-loc object created.
  445. "
  446. ; NOTE: realgud-cmdbuf-info is a buffer variable local to the process
  447. ; running the debugger. It contains a realgud-cmdbuf-info "struct". In
  448. ; that struct is the regexp hash to match positions. By setting the
  449. ; the fields of realgud-cmdbuf-info appropriately we can accomodate a
  450. ; family of debuggers -- one at a time -- for the buffer process.
  451. (setq cmdbuf (or cmdbuf (current-buffer)))
  452. (with-current-buffer cmdbuf
  453. (unless (realgud:track-complain-if-not-in-cmd-buffer cmdbuf t)
  454. (let* ((loc-pat (realgud-cmdbuf-pat "brkpt-set"))
  455. (shortkey-mode? (realgud-sget 'cmdbuf-info 'src-shortkey?))
  456. (found-loc nil)
  457. (loc-pat-list loc-pat))
  458. (unless (listp loc-pat-list)
  459. (setq loc-pat-list (list loc-pat)))
  460. (while loc-pat-list
  461. (setq loc-pat (car loc-pat-list))
  462. (setq loc-pat-list (cdr loc-pat-list))
  463. (let ((bp-num-group (realgud-loc-pat-num loc-pat))
  464. (loc-regexp (realgud-loc-pat-regexp loc-pat))
  465. (file-group (realgud-loc-pat-file-group loc-pat))
  466. (line-group (realgud-loc-pat-line-group loc-pat))
  467. (text-group (realgud-loc-pat-text-group loc-pat))
  468. (column-group (realgud-loc-pat-column-group loc-pat))
  469. (ignore-re-file-list (or opt-ignore-re-file-list
  470. (realgud-sget 'cmdbuf-info 'ignore-re-file-list)))
  471. (callback-loc-fn (realgud-sget 'cmdbuf-info 'callback-loc-fn))
  472. )
  473. (if loc-regexp
  474. (if (string-match loc-regexp text)
  475. (let* ((bp-num (and bp-num-group (match-string bp-num-group text)))
  476. (filename
  477. (if file-group
  478. (match-string file-group text)
  479. (realgud-sget 'cmdbuf-info 'source-path)
  480. ))
  481. (line-str (match-string line-group text))
  482. (source-str (and text-group (match-string text-group text)))
  483. (lineno (string-to-number (or line-str "1")))
  484. (column-str (and column-group (match-string column-group text)))
  485. (column (string-to-number (or column-str "1")))
  486. (directory
  487. (cond ((boundp 'starting-directory) starting-directory)
  488. (t nil)))
  489. )
  490. (cond (callback-loc-fn
  491. (if (setq found-loc (funcall callback-loc-fn text
  492. filename lineno source-str
  493. cmd-mark directory column))
  494. ;; FIXME: dry with code in realgud-track-bp-file-line
  495. (let ((bp-list (realgud-sget 'cmdbuf-info 'bp-list))
  496. srcbuf)
  497. ;; Add src buffer mentioned and set it possibly to go into shortkey mode
  498. (setq srcbuf (realgud-loc-goto found-loc))
  499. (realgud-cmdbuf-add-srcbuf srcbuf cmdbuf)
  500. (realgud-srcbuf-init-or-update srcbuf cmdbuf)
  501. (with-current-buffer srcbuf
  502. (realgud-short-key-mode-setup
  503. (or realgud-short-key-on-tracing? shortkey-mode?)
  504. ))
  505. ;; Add breakpoint to list of breakpoints
  506. (with-current-buffer-safe (marker-buffer (realgud-loc-marker found-loc))
  507. (realgud-bp-add-info found-loc))
  508. (unless (member found-loc bp-list)
  509. (realgud-cmdbuf-info-bp-list= (cons found-loc bp-list)))
  510. )
  511. (setq loc-pat-list nil)))
  512. (t
  513. (unless line-str
  514. (message "line number not found -- using 1"))
  515. (if (setq found-loc
  516. (realgud-track-bp-file-line cmd-mark cmdbuf filename lineno source-str bp-num directory column shortkey-mode?))
  517. (setq loc-pat-list nil)))
  518. )
  519. )
  520. ))))
  521. found-loc)
  522. )))
  523. (defun realgud-track-bp-file-line(cmd-mark cmdbuf filename lineno source-str bp-num directory column shortkey-mode?)
  524. (if (and filename lineno)
  525. (let* ((directory
  526. (cond ((boundp 'starting-directory) starting-directory)
  527. (t nil)))
  528. (srcbuf)
  529. (found-loc nil)
  530. (loc-or-error
  531. (realgud:file-loc-from-line
  532. filename lineno
  533. cmd-mark
  534. source-str
  535. (string-to-number bp-num)
  536. nil directory
  537. )))
  538. (if (stringp loc-or-error)
  539. (progn
  540. (message loc-or-error)
  541. ;; set to return nil
  542. (setq found-loc nil))
  543. ;; else
  544. (let ((loc loc-or-error)
  545. (bp-list (realgud-sget 'cmdbuf-info 'bp-list)))
  546. ;; Add src buffer mentioned and set it possibly to go into shortkey mode
  547. (setq srcbuf (realgud-loc-goto loc))
  548. (realgud-cmdbuf-add-srcbuf srcbuf cmdbuf)
  549. (realgud-srcbuf-init-or-update srcbuf cmdbuf)
  550. (with-current-buffer srcbuf
  551. (realgud-short-key-mode-setup
  552. (or realgud-short-key-on-tracing? shortkey-mode?)
  553. ))
  554. ;; Add breakpoint to list of breakpoints
  555. (with-current-buffer-safe (marker-buffer (realgud-loc-marker loc))
  556. (realgud-bp-add-info loc))
  557. (realgud-cmdbuf-info-bp-list= (delete-dups (cl-adjoin loc bp-list :test #'equal)))
  558. ;; Set to return location
  559. (setq found-loc loc-or-error)
  560. ))
  561. found-loc
  562. )))
  563. (defun realgud-track-bp-delete(text &optional cmd-mark cmdbuf ignore-re-file-list)
  564. "Do regular-expression matching to see if a breakpoint has been
  565. deleted inside string TEXT. Return a list of breakpoint locations
  566. of the breakpoints found in command buffer."
  567. ; NOTE: realgud-cmdbuf-info is a buffer variable local to the process
  568. ; running the debugger. It contains a realgud-cmdbuf-info "struct". In
  569. ; that struct is the regexp hash to match positions. By setting the
  570. ; the fields of realgud-cmdbuf-info appropriately we can accomodate a
  571. ; family of debuggers -- one at a time -- for the buffer process.
  572. (setq cmdbuf (or cmdbuf (current-buffer)))
  573. (with-current-buffer cmdbuf
  574. (unless (realgud:track-complain-if-not-in-cmd-buffer cmdbuf t)
  575. (let* ((loc-pat (realgud-cmdbuf-pat "brkpt-del")))
  576. (when loc-pat
  577. (let ((bp-num-group (realgud-loc-pat-num loc-pat))
  578. (loc-regexp (realgud-loc-pat-regexp loc-pat)))
  579. (when (and loc-regexp (string-match loc-regexp text))
  580. (let* ((bp-nums-str (match-string bp-num-group text))
  581. (bp-num-strs (split-string bp-nums-str "[^0-9]+" t))
  582. (bp-nums (mapcar #'string-to-number bp-num-strs))
  583. (info realgud-cmdbuf-info)
  584. (all-bps (realgud-cmdbuf-info-bp-list info))
  585. (found-locs nil))
  586. (dolist (loc all-bps)
  587. (when (memq (realgud-loc-num loc) bp-nums)
  588. (push loc found-locs)
  589. ;; Remove loc from breakpoint list
  590. (realgud-cmdbuf-info-bp-list=
  591. (remove loc (realgud-cmdbuf-info-bp-list info)))))
  592. ;; return the locations
  593. found-locs))))))))
  594. (defun realgud-track-bp-enable-disable(text loc-pat enable? &optional cmdbuf)
  595. "Do regular-expression matching see if a breakpoint has been enabled or disabled inside
  596. string TEXT. If we match, we will do the action to the breakpoint found and return the
  597. breakpoint location. Otherwise return nil.
  598. "
  599. (setq cmdbuf (or cmdbuf (current-buffer)))
  600. (with-current-buffer cmdbuf
  601. (if (realgud-cmdbuf?)
  602. (let* ((found-loc nil))
  603. (if loc-pat
  604. (let ((bp-num-group (realgud-loc-pat-num loc-pat))
  605. (loc-regexp (realgud-loc-pat-regexp loc-pat)))
  606. (if (and loc-regexp (string-match loc-regexp text))
  607. (let* ((bp-num (string-to-number (match-string bp-num-group text)))
  608. (info realgud-cmdbuf-info)
  609. (bp-list (realgud-cmdbuf-info-bp-list info))
  610. (loc)
  611. )
  612. (while (and (not found-loc) (setq loc (car-safe bp-list)))
  613. (setq bp-list (cdr bp-list))
  614. (when (eq (realgud-loc-num loc) bp-num)
  615. (setq found-loc loc)
  616. (let ((src-buffer (realgud-loc-goto loc)))
  617. (realgud-cmdbuf-add-srcbuf src-buffer cmdbuf)
  618. (with-current-buffer src-buffer
  619. (realgud-bp-enable-disable-info bp-num enable? loc src-buffer)
  620. )))
  621. )
  622. ;; return the location:
  623. found-loc)
  624. nil))
  625. nil))
  626. (and (message "Current buffer %s is not a debugger command buffer"
  627. (current-buffer)) nil)
  628. )
  629. )
  630. )
  631. (defun realgud-track-loc-remaining(text)
  632. "Return the portion of TEXT starting with the part after the
  633. loc-regexp pattern"
  634. (if (realgud-cmdbuf?)
  635. (let* ((loc-pat (realgud-cmdbuf-pat "loc"))
  636. (loc-regexp (realgud-loc-pat-regexp loc-pat))
  637. )
  638. (if loc-regexp
  639. (if (string-match loc-regexp text)
  640. (substring text (match-end 0))
  641. nil)
  642. nil))
  643. nil)
  644. )
  645. (defun realgud-track-selected-frame(text)
  646. "Return a selected frame number found in TEXT or nil if none found."
  647. (if (realgud-cmdbuf?)
  648. (let ((selected-frame-pat (realgud-cmdbuf-pat "selected-frame"))
  649. (frame-num-regexp)
  650. )
  651. (if (and selected-frame-pat
  652. (setq frame-num-regexp (realgud-loc-pat-regexp
  653. selected-frame-pat)))
  654. (if (string-match frame-num-regexp text)
  655. (let ((frame-num-group (realgud-loc-pat-num selected-frame-pat)))
  656. (string-to-number (match-string frame-num-group text)))
  657. nil)
  658. nil))
  659. nil)
  660. )
  661. (defun realgud-track-loc-from-selected-frame(text cmd-mark &optional
  662. opt-regexp opt-ignore-re-file-list)
  663. "Return a selected frame number found in TEXT or nil if none found."
  664. (if (realgud-cmdbuf?)
  665. (let ((selected-frame-pat (realgud-cmdbuf-pat "selected-frame"))
  666. (frame-num-regexp)
  667. (ignore-re-file-list (or opt-ignore-re-file-list
  668. (realgud-sget 'cmdbuf-info 'ignore-re-file-list))))
  669. (if (and selected-frame-pat
  670. (setq frame-num-regexp (realgud-loc-pat-regexp
  671. selected-frame-pat)))
  672. (if (string-match frame-num-regexp text)
  673. (let* ((file-group (realgud-loc-pat-file-group selected-frame-pat))
  674. (line-group (realgud-loc-pat-line-group selected-frame-pat))
  675. (filename (match-string file-group text))
  676. (lineno (string-to-number (match-string line-group text))))
  677. (if (and filename lineno)
  678. (realgud:file-loc-from-line filename lineno
  679. cmd-mark nil nil)
  680. nil))
  681. nil)
  682. nil))
  683. nil))
  684. (defun realgud-track-termination?(text)
  685. "Return 't and call `realgud:terminate' we we have a termination message"
  686. (if (realgud-cmdbuf?)
  687. (let ((termination-re (realgud-cmdbuf-pat "termination"))
  688. )
  689. (if (and termination-re (string-match termination-re text))
  690. (progn
  691. (realgud:terminate (current-buffer))
  692. 't)
  693. nil)
  694. )
  695. )
  696. )
  697. (defun realgud-track-divert-prompt(text cmdbuf to)
  698. "Return a cons node of the part before the prompt-regexp and the part
  699. after the prompt-regexp-prompt. If not found return nil."
  700. (with-current-buffer cmdbuf
  701. ;; (message "+++3 %s, buf: %s" text (buffer-name))
  702. (if (realgud-cmdbuf?)
  703. (let* ((prompt-pat (realgud-cmdbuf-pat "prompt"))
  704. (prompt-regexp (realgud-loc-pat-regexp prompt-pat))
  705. )
  706. (if prompt-regexp
  707. (if (string-match prompt-regexp text)
  708. (progn
  709. (setq realgud-track-divert-string
  710. (substring text 0 (match-beginning 0)))
  711. ;; We've got desired output, so reset divert output.
  712. (realgud-cmdbuf-info-divert-output?= nil)
  713. (cond ((search-backward-regexp prompt-regexp)
  714. (kill-region realgud-last-output-start (point))
  715. (goto-char (point-max)))
  716. ('t (kill-region realgud-last-output-start to)))
  717. )
  718. ))
  719. )
  720. )
  721. )
  722. )
  723. (defun realgud-goto-line-for-loc-pat (pt &optional opt-realgud-loc-pat)
  724. "Display the location mentioned in line described by
  725. PT. OPT-REALGUD-LOC-PAT is used to get regular-expresion pattern
  726. matching information. If not supplied we use the current buffer's \"location\"
  727. pattern found via realgud-cmdbuf information. nil is returned if we can't
  728. find a location. non-nil if we can find a location.
  729. "
  730. (interactive "d")
  731. (save-excursion
  732. (goto-char pt)
  733. (let*
  734. ((cmdbuf (current-buffer))
  735. (cmd-mark (point-marker))
  736. (curr-proc (get-buffer-process cmdbuf))
  737. (start (line-beginning-position))
  738. (end (line-end-position))
  739. (loc-pat (or opt-realgud-loc-pat (realgud-cmdbuf-pat "loc")))
  740. (loc)
  741. )
  742. (unless (and loc-pat (realgud-loc-pat-p loc-pat))
  743. (error "Can't find location information for %s" cmdbuf))
  744. (setq loc (realgud-track-loc (buffer-substring-no-properties start end)
  745. cmd-mark
  746. (realgud-loc-pat-regexp loc-pat)
  747. (realgud-loc-pat-file-group loc-pat)
  748. (realgud-loc-pat-line-group loc-pat)
  749. nil
  750. ))
  751. (if (stringp loc)
  752. (message loc)
  753. (if loc (or (realgud-track-loc-action loc cmdbuf) 't)
  754. nil))
  755. ))
  756. )
  757. (defun realgud:populate-command-hash(key value)
  758. "Adds a KEY and VALUE to the realgud-command-name-hash the command name to a debugger specific command."
  759. (puthash key
  760. (replace-regexp-in-string "%.*" "" (car (split-string value " ")))
  761. realgud-command-name-hash))
  762. (defun realgud-set-command-name-hash-to-buffer-local (command-hash)
  763. "Sets the eval string as a buffer local variable from the COMMAND-HASH."
  764. (set (make-local-variable 'realgud-command-name-hash) (make-hash-table :test 'equal))
  765. (maphash 'realgud:populate-command-hash command-hash))
  766. (defun realgud:track-set-debugger (debugger-name)
  767. "Set debugger name and information associated with that
  768. debugger for the buffer process. This info is returned or nil if
  769. we can't find a debugger with that information.`.
  770. "
  771. ;; FIXME: turn into fn which can be used by realgud-backtrack-set-debugger
  772. (interactive
  773. (list (completing-read "Debugger name: " realgud-pat-hash)))
  774. (let* ((base-variable-name
  775. (or (gethash debugger-name realgud:variable-basename-hash)
  776. debugger-name))
  777. (regexp-hash (gethash debugger-name realgud-pat-hash))
  778. (command-hash (gethash debugger-name realgud-command-hash))
  779. )
  780. (unless regexp-hash
  781. ;; FIXME: phase out realgud:debugger-name-transform
  782. (setq base-variable-name (realgud:debugger-name-transform debugger-name))
  783. (setq regexp-hash (gethash base-variable-name realgud-pat-hash))
  784. (setq command-hash (gethash base-variable-name realgud-command-hash))
  785. )
  786. (realgud-set-command-name-hash-to-buffer-local command-hash)
  787. (if regexp-hash
  788. (let* (
  789. (mode-name (concat " " (capitalize base-variable-name) "-Track"))
  790. (specific-track-mode (intern (concat base-variable-name "-track-mode")))
  791. )
  792. (realgud-cmdbuf-init (current-buffer)
  793. debugger-name regexp-hash
  794. command-hash base-variable-name)
  795. (if (and (not (eval specific-track-mode))
  796. (functionp specific-track-mode))
  797. (funcall specific-track-mode 't))
  798. )
  799. (progn
  800. (message "I don't have %s listed as a debugger." debugger-name)
  801. nil)
  802. )))
  803. ;; FIXME: need better name for this and next fn.
  804. (defun realgud-goto-line-for-pt-and-type (pt type pat-hash)
  805. "Position the source code at the location that is matched by
  806. PAT-HASH with key TYPE. The line at PT is used as the string
  807. to match against and has location info embedded in it"
  808. (realgud-goto-line-for-loc-pat pt (gethash type pat-hash)))
  809. (defun realgud-goto-line-for-pt (pt pattern-key)
  810. "Position the source code at the location indicated by a
  811. pattern found in the command buffer with pattern-key
  812. PATTERN-KEY. (PATTERN-KEY is something like 'debugger-backtrace'
  813. or 'loc'.) The line at PT is used as the string to match against
  814. and has location info embedded in it"
  815. (interactive "d")
  816. (unless (realgud-cmdbuf?)
  817. (error "You need to be in a debugger command buffer to run this"))
  818. (let* ((debugger-name (realgud-cmdbuf-debugger-name))
  819. (debugger-pat-hash (gethash debugger-name realgud-pat-hash)))
  820. (realgud-goto-line-for-pt-and-type pt pattern-key debugger-pat-hash)
  821. )
  822. )
  823. (defun realgud:goto-debugger-backtrace-line (pt)
  824. "Position the source code at the location indicated by matching a
  825. command buffer's debugger backtrace pattern against the line at PT."
  826. (interactive "d")
  827. (unless (realgud-goto-line-for-pt pt "debugger-backtrace")
  828. (message "Line didn't match a debugger backtrace location.")
  829. ))
  830. (defun realgud:goto-lang-backtrace-line (pt)
  831. "Position the source code at the location indicated by matching a
  832. command buffer's programming-language backtrace pattern against the line at PT."
  833. (interactive "d")
  834. (unless (realgud-goto-line-for-pt pt "lang-backtrace")
  835. (message "Line didn't match a programming-language backtrace location.")
  836. ))
  837. (defun realgud:goto-debugger-loc-line (pt)
  838. "Position the source-code at the location indicated by matching a
  839. command buffer's debugger location pattern against the line at PT."
  840. (interactive "d")
  841. (unless (realgud-goto-line-for-pt pt "loc")
  842. (message "Line didn't match a debugger location indicator line.")
  843. ))
  844. (provide-me "realgud-")
  845. ;; Local Variables:
  846. ;; byte-compile-warnings: (not cl-functions)
  847. ;; End: