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.

492 lines
18 KiB

  1. ;; Copyright (C) 2015-2017, 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. (require 'load-relative)
  14. (require 'thingatpt)
  15. (require-relative-list '("send" "core") "realgud-")
  16. (require-relative-list '("buffer/command") "realgud-buffer-")
  17. (require-relative-list '("buffer/source") "realgud-buffer-")
  18. (declare-function buffer-killed? 'helper)
  19. (declare-function realgud-cmdbuf-info-in-srcbuf?= 'realgud-buffer-command)
  20. (declare-function realgud-cmdbuf? 'realgud-buffer-command)
  21. (declare-function realgud-command 'realgud-send)
  22. (declare-function realgud-get-cmdbuf 'realgud-buffer-helper)
  23. (declare-function realgud-get-command 'realgud-buffer-command)
  24. (declare-function realgud-get-bpnum-from-line-num 'realgud-buffer-source)
  25. (declare-function realgud:terminate 'realgud-core)
  26. (declare-function realgud:terminate-srcbuf 'realdgud-core)
  27. (defcustom realgud-safe-mode t
  28. "Confirm certain commands before running them.
  29. Similar to GDB's set confirm."
  30. :type 'boolean
  31. :group 'realgud)
  32. (defun realgud:prompt-if-safe-mode(message)
  33. "Ask use to confirm current command if in safe mode.
  34. Use MESSAGE plus a space as the prompt string. Do not confirm
  35. when command was run from a menu."
  36. (if (and realgud-safe-mode
  37. last-nonmenu-event
  38. (not (equal last-nonmenu-event '(tool-bar))))
  39. (when (y-or-n-p (concat message " "))
  40. (run-with-timer
  41. 0 nil #'message
  42. "Customize `realgud-safe-mode' to disable confirmation prompts.")
  43. t)
  44. t))
  45. (defun realgud:cmd--line-number-from-prefix-arg ()
  46. "Guess or read a line number based on prefix arg.
  47. Returns (nil) for current line, and a list whose car is the line
  48. number otherwise."
  49. (cond
  50. ((numberp current-prefix-arg)
  51. current-prefix-arg)
  52. ((consp current-prefix-arg)
  53. (let* ((min-line (save-excursion
  54. (goto-char (point-min))
  55. (line-number-at-pos)))
  56. (max-line (save-excursion
  57. (goto-char (point-max))
  58. (line-number-at-pos)))
  59. (prompt (format "Line number (%d..%d)? " min-line max-line))
  60. (picked-line 0))
  61. (while (not (<= min-line picked-line max-line))
  62. (setq picked-line (read-number prompt)))
  63. (list picked-line)))))
  64. (defmacro realgud:cmd--with-line-override (line &rest body)
  65. "Run BODY with %l format specifier bound to LINE.
  66. This is needed because going to LINE explicitly would interfere
  67. with other motion initiated by debugger messages."
  68. (declare (indent 1)
  69. (debug t))
  70. (let ((line-var (make-symbol "--line--")))
  71. `(let* ((,line-var ,line)
  72. (realgud-expand-format-overrides
  73. (cons (cons ?l (and ,line-var (number-to-string ,line-var)))
  74. realgud-expand-format-overrides)))
  75. ,@body)))
  76. (defconst realgud-cmd:default-hash
  77. (let ((hash (make-hash-table :test 'equal)))
  78. (puthash "backtrace" "backtrace" hash)
  79. (puthash "break" "break %X:%l" hash)
  80. (puthash "break-fn" "break %s" hash)
  81. (puthash "clear" "clear %l" hash)
  82. (puthash "continue" "continue" hash)
  83. (puthash "delete" "delete %p" hash)
  84. (puthash "delete-all" "delete" hash)
  85. (puthash "disable" "disable %p" hash)
  86. (puthash "disable-all" "disable" hash)
  87. (puthash "down" "down %p" hash)
  88. (puthash "enable" "enable %p" hash)
  89. (puthash "enable-all" "enable" hash)
  90. (puthash "eval" "eval %s" hash)
  91. (puthash "finish" "finish" hash)
  92. (puthash "frame" "frame %p" hash)
  93. (puthash "help" "help" hash)
  94. (puthash "info-breakpoints" "info breakpoints" hash)
  95. (puthash "jump" "jump %l" hash)
  96. (puthash "kill" "kill" hash)
  97. (puthash "next" "next %p" hash)
  98. (puthash "repeat-last" "\n" hash)
  99. (puthash "restart" "run" hash)
  100. (puthash "shell" "shell" hash)
  101. (puthash "step" "step %p" hash)
  102. (puthash "tbreak" "tbreak %X:%l" hash)
  103. (puthash "until" "until" hash)
  104. (puthash "until-here" "until %l" hash)
  105. (puthash "up" "up %p" hash)
  106. hash)
  107. "Default hash of command name → debugger command.
  108. This is used as a fallback when the debugger-specific command
  109. hash does not specify a custom debugger command. The keys of the
  110. hash contain all the debugger commands we know about.
  111. If a value is *not-implemented*, then this command is not available
  112. in a particular debugger.
  113. ")
  114. (defun realgud:cmd-run-command(arg cmd-name &optional
  115. default-cmd-template no-record?
  116. frame-switch? realgud-prompts?)
  117. "Run debugger command CMD-NAME.
  118. If CMD-NAME isn't set in the command buffer's command hash, use
  119. DEFAULT-CMD-TEMPLATE and fall back to looking CMD-NAME up in
  120. `realgud:cmd-get-cmd-hash'."
  121. (let* ((buffer (current-buffer))
  122. (cmdbuf (realgud-get-cmdbuf))
  123. (cmd-hash (with-current-buffer-safe cmdbuf
  124. (realgud-cmdbuf-info-cmd-hash realgud-cmdbuf-info)))
  125. (cmd (or (and (hash-table-p cmd-hash)
  126. (gethash cmd-name cmd-hash))
  127. default-cmd-template
  128. (gethash cmd-name realgud-cmd:default-hash))))
  129. (if (or (null cmd) (equal cmd "*not-implemented*"))
  130. (message "Command %s is not implemented for this debugger" cmd-name)
  131. (progn
  132. ;; Set flag to know which buffer to jump back to
  133. (with-current-buffer-safe cmdbuf
  134. (realgud-cmdbuf-info-in-srcbuf?= (not (realgud-cmdbuf? buffer))))
  135. ;; Run actual command
  136. (realgud-command cmd arg no-record? frame-switch? realgud-prompts?)
  137. ;; FIXME: Figure out how to update the position if the source
  138. ;; buffer is displayed.
  139. ;; (if frame-switch?
  140. ;; (let* ((src-buffer (realgud-get-srcbuf-from-cmdbuf cmdbuf))
  141. ;; (src-window (get-buffer-window src-buffer))
  142. ;; ))
  143. ;; (with-selected-window src-window
  144. ;; (message "recentering...")
  145. ;; (realgud-recenter-arrow)
  146. ;; ))
  147. )
  148. )
  149. ))
  150. (defun realgud:cmd-remap (arg cmd-name default-cmd-template
  151. &optional key no-record? frame-switch?
  152. realgud-prompts?)
  153. "Compatibility alias for `realgud:cmd-run-command'.
  154. ARG, CMD-NAME, DEFAULT-CMD-TEMPLATE are as in `realgud:cmd-run-command'.
  155. KEY is ignored. NO-RECORD?, FRAME-SWITCH?, REALGUD-PROMPTS? are
  156. as in `realgud:cmd-run-command'."
  157. (realgud:cmd-run-command arg cmd-name default-cmd-template
  158. no-record? frame-switch?
  159. realgud-prompts?))
  160. (make-obsolete 'realgud:cmd-remap 'realgud:cmd-run-command "1.3.1")
  161. (defun realgud:cmd-backtrace(arg)
  162. "Show the current call stack."
  163. (interactive "p")
  164. (realgud:cmd-run-command arg "backtrace")
  165. )
  166. (defun realgud:cmd-break (&optional line-number)
  167. "Set a breakpoint at the current line.
  168. With prefix argument LINE-NUMBER, prompt for line number."
  169. (interactive (realgud:cmd--line-number-from-prefix-arg))
  170. ;; Note a file name may be picked up inside realgud:cmd-run-runcmd's stored pattern
  171. (realgud:cmd--with-line-override line-number
  172. (realgud:cmd-run-command line-number "break")))
  173. (defun realgud:cmd-tbreak (&optional line-number)
  174. "Set a temporary breakpoint at the current line.
  175. With prefix argument LINE-NUMBER, prompt for line number."
  176. (interactive (realgud:cmd--line-number-from-prefix-arg))
  177. (realgud:cmd--with-line-override line-number
  178. (realgud:cmd-run-command line-number "tbreak")))
  179. (defun realgud:cmd-until-here (&optional line-number)
  180. "Continue until the current line.
  181. With prefix argument LINE-NUMBER, prompt for line number."
  182. (interactive (realgud:cmd--line-number-from-prefix-arg))
  183. (realgud:cmd--with-line-override line-number
  184. (realgud:cmd-run-command line-number "until-here")))
  185. (defun realgud:cmd-clear(&optional line-number)
  186. "Delete breakpoint at the current line.
  187. With prefix argument LINE-NUMBER, prompt for line number."
  188. (interactive (realgud:cmd--line-number-from-prefix-arg))
  189. (realgud:cmd--with-line-override line-number
  190. (realgud:cmd-run-command line-number "clear")))
  191. (defun realgud:cmd-jump(&optional line-number)
  192. "Jump to current line.
  193. With prefix argument LINE-NUMBER, prompt for line number."
  194. (interactive (realgud:cmd--line-number-from-prefix-arg))
  195. (realgud:cmd--with-line-override line-number
  196. (realgud:cmd-run-command (line-number-at-pos) "jump")))
  197. (defun realgud:cmd-continue(&optional arg)
  198. "Continue execution.
  199. With prefix argument ARG, prompt for argument to \"continue\"
  200. command. In safe mode (or with prefix arg), confirm before
  201. running."
  202. (interactive (when (consp current-prefix-arg)
  203. (list (read-string "Continue args: " nil nil nil t))))
  204. (when (or arg (realgud:prompt-if-safe-mode
  205. "Continue to next breakpoint?"))
  206. (realgud:cmd-run-command arg "continue")))
  207. (defun realgud-get-bp-list()
  208. "Return breakpoint numbers as a list of strings. This can be used for
  209. example in a completing read."
  210. (with-current-buffer (realgud-get-cmdbuf)
  211. ;; Remove duplicates doesn't seem to work on strings so
  212. ;; we need a separate mapcar outside to stringify
  213. ;; Also note that lldb breakpoint numbers can be dotted like
  214. ;; 5.1.
  215. (mapcar (lambda (num) (format "%s" num))
  216. (cl-remove-duplicates
  217. (mapcar (lambda(loc) (realgud-loc-num loc))
  218. (realgud-cmdbuf-info-bp-list realgud-cmdbuf-info))))))
  219. (defun realgud:bpnum-on-current-line()
  220. "Return number of one breakpoint on current line, if any.
  221. If none is found, return nil."
  222. (realgud-get-bpnum-from-line-num (line-number-at-pos)))
  223. (defun realgud:bpnum-from-prefix-arg(action-verb)
  224. "Return number of one breakpoint on current line, if any.
  225. If none is found, or if `current-prefix-arg' is a cons (i.e. a
  226. C-u prefix arg), ask user for a breakpoint number. If
  227. `current-prefix-arg' is a number (i.e. a numeric prefix arg),
  228. return it unmodified."
  229. (let ((must-prompt (consp current-prefix-arg))
  230. (cmd-buffer (realgud-get-cmdbuf))
  231. (current-bp (realgud:bpnum-on-current-line)))
  232. (list
  233. (if (numberp current-prefix-arg)
  234. current-prefix-arg
  235. (or (and (not must-prompt) current-bp)
  236. (string-to-number (completing-read (format "%s breakpoint number: " action-verb)
  237. (realgud-get-bp-list)
  238. nil nil current-bp)))))))
  239. (defun realgud:cmd-delete(bpnum)
  240. "Delete breakpoint by number.
  241. Interactively, find breakpoint on current line, if any. With
  242. numeric prefix argument, delete breakpoint with that number
  243. instead. With prefix argument (C-u), or when no breakpoint can
  244. be found on the current line, prompt for a breakpoint number."
  245. (interactive (realgud:bpnum-from-prefix-arg "Delete"))
  246. (realgud:cmd-run-command bpnum "delete"))
  247. (defun realgud:cmd-disable(bpnum)
  248. "Disable breakpoint BPNUM.
  249. Interactively, find breakpoint on current line, if any. With
  250. numeric prefix argument, disable breakpoint with that number
  251. instead. With prefix argument (C-u), or when no breakpoint can
  252. be found on the current line, prompt for a breakpoint number."
  253. (interactive (realgud:bpnum-from-prefix-arg "Disable"))
  254. (realgud:cmd-run-command bpnum "disable"))
  255. (defun realgud:cmd-enable(bpnum)
  256. "Enable breakpoint BPNUM.
  257. Interactively, find breakpoint on current line, if any. With
  258. numeric prefix argument, enable breakpoint with that number
  259. instead. With prefix argument (C-u), or when no breakpoint can
  260. be found on the current line, prompt for a breakpoint number."
  261. (interactive (realgud:bpnum-from-prefix-arg "Enable"))
  262. (realgud:cmd-run-command bpnum "enable"))
  263. (defun realgud-cmds--add-remove-bp (pos)
  264. "Add or delete breakpoint at POS."
  265. (save-excursion
  266. (goto-char pos)
  267. (let ((existing-bp-num (realgud:bpnum-on-current-line)))
  268. (if existing-bp-num
  269. (realgud:cmd-delete existing-bp-num)
  270. (realgud:cmd-break)))))
  271. (defun realgud-cmds--mouse-add-remove-bp (event)
  272. "Add or delete breakpoint on line pointed to by EVENT.
  273. EVENT should be a mouse click on the left fringe or margin."
  274. (interactive "e")
  275. (let* ((posn (event-end event))
  276. (pos (posn-point posn)))
  277. (when (numberp pos)
  278. (with-current-buffer (window-buffer (posn-window posn))
  279. (realgud-cmds--add-remove-bp pos)))))
  280. (defun realgud:cmd-eval(arg)
  281. "Evaluate an expression."
  282. (interactive "MEval expression: ")
  283. (realgud:cmd-run-command arg "eval")
  284. )
  285. (defun realgud:cmd-eval-region(start end)
  286. "Evaluate current region."
  287. (interactive "r")
  288. (let ((text (buffer-substring-no-properties start end)))
  289. (realgud:cmd-run-command text "eval")))
  290. (defun realgud:cmd-eval-dwim()
  291. "Eval the current region if active; otherwise, prompt."
  292. (interactive)
  293. (call-interactively (if (region-active-p)
  294. #'realgud:cmd-eval-region
  295. #'realgud:cmd-eval)))
  296. (defun realgud:cmd-eval-at-point()
  297. "Eval symbol under point."
  298. (interactive)
  299. (beginning-of-thing 'symbol)
  300. (set-mark-command 'nil)
  301. (end-of-thing 'symbol)
  302. (realgud:cmd-run-command
  303. (read-string "Eval: " (thing-at-point 'symbol))
  304. "eval"))
  305. (defun realgud:cmd-finish(&optional arg)
  306. "Run until the completion of the current stack frame.
  307. This command is often referred to as 'step out' as opposed to
  308. 'step over' or 'step into'."
  309. (interactive "p")
  310. (realgud:cmd-run-command arg "finish")
  311. )
  312. (defun realgud:cmd-frame(arg)
  313. "Change the current frame number to the value of the numeric argument.
  314. If no argument specified use 0 or the most recent frame."
  315. (interactive "p")
  316. (realgud:cmd-run-command arg "frame" nil t t)
  317. )
  318. (defun realgud:cmd-info-breakpoints()
  319. "Show all list of all breakpoints."
  320. (interactive "")
  321. (realgud:cmd-run-command nil "info-breakpoints")
  322. )
  323. (defun realgud:cmd-kill()
  324. "Kill debugger process."
  325. (interactive)
  326. (realgud:cmd-run-command nil "kill" nil nil nil t))
  327. (defun realgud:cmd-newer-frame(&optional arg)
  328. "Move the current frame to a newer (more recent) frame.
  329. With a numeric argument move that many levels forward."
  330. (interactive "p")
  331. (realgud:cmd-run-command arg "down" nil t t)
  332. )
  333. (defun realgud:cmd-next(&optional count)
  334. "Step one source line at current call level.
  335. With numeric argument COUNT, step that many times. This command is
  336. often referred to as `step through' as opposed to `step into' or
  337. `step out'.
  338. The definition of `next' is debugger specific, so see the
  339. documentation of your debugger for a more complete definition of
  340. what is getting stepped."
  341. (interactive "p")
  342. (realgud:cmd-run-command count "next"))
  343. (defun realgud:cmd-next-no-arg()
  344. "Step one source line at current call level.
  345. The definition of 'next' is debugger specific so, see the
  346. debugger documentation for a more complete definition of what is
  347. getting stepped."
  348. (interactive)
  349. (realgud:cmd-next))
  350. (defun realgud:cmd-older-frame(&optional arg)
  351. "Move the current frame to an older (less recent) frame.
  352. With a numeric argument move that many levels back."
  353. (interactive "p")
  354. (realgud:cmd-run-command arg "up" nil t t)
  355. )
  356. (defun realgud:cmd-repeat-last()
  357. "Repeat the last command (or generally what <enter> does."
  358. (interactive)
  359. (realgud:cmd-run-command nil "repeat-last" nil t nil t))
  360. (defun realgud:cmd-restart()
  361. "Restart execution."
  362. (interactive)
  363. (if (realgud:prompt-if-safe-mode
  364. "Restart program?")
  365. (realgud:cmd-run-command nil "restart" nil t nil t)))
  366. (defun realgud:cmd-shell()
  367. "Drop to a shell."
  368. (interactive)
  369. (realgud:cmd-run-command nil "shell"))
  370. (defun realgud:cmd-step(&optional count)
  371. "Step one source line.
  372. With a numeric prefix argument COUNT, step that many times.
  373. This command is often referred to as `step into' as opposed to
  374. `step over' or `step out'.
  375. The definition of `step' is debugger specific, so see the
  376. documentation of your debugger for a more complete definition of
  377. what is getting stepped."
  378. (interactive "p")
  379. (realgud:cmd-run-command count "step"))
  380. (defun realgud:cmd-step-no-arg()
  381. "Step one source line.
  382. The definition of `step' is debugger specific, so see the
  383. documentation of your debugger for a more complete definition of
  384. what is getting stepped."
  385. (interactive)
  386. (realgud:cmd-step))
  387. (defun realgud:cmd-terminate ()
  388. "Gently terminate source and command buffers without possibly
  389. issuing a command to the underlying debuger. Use this if the
  390. underlying debugger has died or you want to get out of all
  391. shortkey modes in the source window and possibly restart
  392. debugging after editing source."
  393. (interactive)
  394. (realgud:terminate (current-buffer))
  395. )
  396. (defun realgud:cmd-until(&optional arg)
  397. "Run until the completion of the current stack frame.
  398. Continue until the current line. In some cases this is really
  399. two commands - setting a temporary breakpoint on the line and
  400. continuing execution."
  401. (interactive "p")
  402. (realgud:cmd-run-command arg "until")
  403. )
  404. (defun realgud:cmd-quit (&optional arg)
  405. "Gently terminate execution of the debugged program."
  406. (interactive "p")
  407. (if (realgud:prompt-if-safe-mode
  408. "Quit debugger?")
  409. (let ((buffer (current-buffer))
  410. (cmdbuf (realgud-get-cmdbuf))
  411. (cmd-hash)
  412. (cmd)
  413. )
  414. (if cmdbuf
  415. (progn
  416. (with-current-buffer cmdbuf
  417. (realgud-cmdbuf-info-in-srcbuf?= (not (realgud-cmdbuf? buffer)))
  418. (setq cmd-hash (realgud-cmdbuf-info-cmd-hash realgud-cmdbuf-info))
  419. (unless (and cmd-hash (setq cmd (gethash "quit" cmd-hash)))
  420. (setq cmd "quit"))
  421. )
  422. (realgud-command cmd arg t)
  423. (if cmdbuf (realgud:terminate cmdbuf))
  424. )
  425. ;; else
  426. (realgud:terminate-srcbuf buffer)
  427. )
  428. )
  429. ))
  430. (provide-me "realgud-")