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.

291 lines
11 KiB

  1. ;; Copyright (C) 2015-2016, 2018 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 'comint)
  14. (require 'eshell)
  15. (require 'load-relative)
  16. (require-relative-list '("utils" "window") "realgud-")
  17. (require-relative-list '("buffer/helper") "realgud-buffer-")
  18. (declare-function realgud-get-cmdbuf 'realgud-buffer-helper)
  19. (declare-function realgud-get-srcbuf 'realgud-buffer-helper)
  20. (declare-function realgud-cmdbuf-info-in-debugger?= 'realgud-command)
  21. (declare-function realgud-window-cmd-undisturb-src 'realgud-window)
  22. (declare-function comint-goto-process-mark 'comint)
  23. (declare-function comint-send-input 'comint)
  24. (declare-function realgud:canonic-major-mode 'realgud-utils)
  25. (defun realgud:send-input ()
  26. "Sends command buffer line either to comint or eshell"
  27. (interactive)
  28. (let ((mode (realgud:canonic-major-mode)))
  29. (ignore-errors
  30. (cond ((eq mode 'eshell)
  31. (eshell-send-input))
  32. ((eq mode 'comint)
  33. (comint-send-input))
  34. ))))
  35. (defun realgud:send-command-common (process command-str)
  36. "Assume we are in a comint buffer. Insert COMMAND-STR and
  37. send that input onto the process."
  38. (if (eq 'run (process-status process))
  39. (let ((mode (realgud:canonic-major-mode)))
  40. (cond ((eq mode 'eshell)
  41. (goto-char eshell-last-output-end)
  42. (setq eshell-last-output-start
  43. (setq realgud-last-output-start (point-marker))))
  44. ((eq mode 'comint)
  45. (comint-check-proc (current-buffer))
  46. (comint-goto-process-mark)
  47. (setq comint-last-output-start
  48. (setq realgud-last-output-start (point-marker)))))
  49. (insert command-str)
  50. (realgud:send-input)
  51. )
  52. ;; else
  53. (message "Process %s not in `run' state; not issuing %s"
  54. process command-str)
  55. )
  56. )
  57. (defalias 'comint-output-filter-orig
  58. (symbol-function 'comint-output-filter))
  59. (defvar realgud-last-output-start)
  60. (defun fake-output-filter(process string)
  61. "A process output filter that saves the results into a temporary buffer."
  62. (with-current-buffer (get-buffer-create "*realgud-process-output-temp*")
  63. (goto-char (point-max))
  64. (set (make-local-variable 'realgud-last-output-start)
  65. (point-marker))
  66. (insert (concat "\n" string))
  67. (goto-char (point-max))))
  68. (defun realgud-send-command-process (process command-str)
  69. "Invoke debugger COMMAND adding that command and the
  70. results into the command buffer."
  71. (fset 'comint-output-filter (symbol-function 'fake-output-filter))
  72. (apply comint-input-sender (list process command-str))
  73. (sit-for 0.25) ;; FIXME with something better
  74. (fset 'comint-output-filter (symbol-function 'comint-output-filter-orig))
  75. )
  76. ;; Here are some other possibilities for functions.
  77. ;; Comint-specific: doesn't insert input into the buffer which is
  78. ;; what gud-call does.
  79. ;; (apply comint-input-sender (list proc command))
  80. ;;
  81. ;; Works on any process-oriented buffer, not just comint.
  82. ;; (process-send-string (get-buffer-process (current-buffer))
  83. ;; (concat command "\n"))
  84. (defun realgud-send-command (command &optional opt-send-fn opt-buffer)
  85. "Invoke the debugger COMMAND adding that command and the
  86. results into the command buffer."
  87. (let* ((cmdbuf (realgud-get-cmdbuf opt-buffer))
  88. (send-command-fn (or opt-send-fn (function realgud:send-command-common)))
  89. )
  90. (if cmdbuf
  91. (with-current-buffer cmdbuf
  92. (let ((process (get-buffer-process cmdbuf)))
  93. (unless process
  94. (realgud-cmdbuf-info-in-debugger?= nil)
  95. (error "Command process buffer is not running")
  96. )
  97. (if (realgud-sget 'cmdbuf-info 'in-debugger?)
  98. (funcall send-command-fn process command)
  99. (error "Command buffer doesn't think a debugger is running - Use `realgud-cmdbuf-toggle-in-debugger?' to toggle")
  100. )
  101. ))
  102. (error "Can't find command process buffer")
  103. )))
  104. (defun realgud-send-command-invisible (command-str)
  105. (realgud-send-command command-str (function realgud-send-command-process)))
  106. (defvar realgud-expand-format-overrides nil
  107. "An alist of overrides for `realgud-expand-format'.
  108. Each element should have the form (KEY . VALUE). Key should be a
  109. single-character escape accepted by `realgud-expand-format';
  110. value should be a string. Every time %KEY is encountered in te
  111. string, it will be replaced by VALUE instead of being processed
  112. as usual. If VALUE is nil, the override is ignored.")
  113. (defun realgud-expand-format (fmt-str &optional opt-str opt-buffer)
  114. "Expands commands format characters inside FMT-STR.
  115. OPT-STR is an optional string (used with %p and %s). Values are
  116. taken from current buffer, or OPT-BUFFER if non-nil. Some
  117. %-escapes in the string arguments are expanded. These are:
  118. %f -- Name without directory of current source file.
  119. %F -- Name without directory or extension of current source file.
  120. %x -- Name of current source file.
  121. %X -- Expanded name of current source file.
  122. %U -- Expanded name of current source file stripping file://.
  123. %d -- Directory of current source file.
  124. %l -- Number of current source line.
  125. %c -- Fully qualified class name derived from the expression
  126. surrounding point.
  127. %p -- Value of OPT-STR, converted to string using `int-to-string'
  128. %q -- Value of OPT-STR with string escapes (as ksh, bash, and zsh do).
  129. %s -- Value of OPT-STR.
  130. %p and %s are replaced by an empty string if OPT-STR is nil."
  131. (let* ((buffer (or opt-buffer (current-buffer)))
  132. (srcbuf (realgud-get-srcbuf buffer))
  133. (src-file-name (and srcbuf (buffer-file-name srcbuf)))
  134. result)
  135. (while (and fmt-str
  136. (let ((case-fold-search nil))
  137. (string-match "\\([^%]*\\)%\\([dfFlpqxUXs]\\)" fmt-str)))
  138. (let* ((key-str (match-string 2 fmt-str))
  139. (key (string-to-char key-str)))
  140. (setq result
  141. (concat
  142. result (match-string 1 fmt-str)
  143. (cond
  144. ((cdr (assq key realgud-expand-format-overrides)))
  145. ((eq key ?d)
  146. (or (and src-file-name
  147. (file-name-directory src-file-name))
  148. "*source-file-not-found-for-%d"))
  149. ((eq key ?f)
  150. (or (and src-file-name
  151. (file-name-nondirectory src-file-name))
  152. "*source-file-not-found-for-%f*"))
  153. ((eq key ?F)
  154. (or (and src-file-name
  155. (file-name-sans-extension
  156. (file-name-nondirectory src-file-name)))
  157. "*source-file-not-found-for-%F"))
  158. ((eq key ?l)
  159. (if srcbuf
  160. (with-current-buffer srcbuf
  161. (int-to-string
  162. (save-restriction
  163. (widen)
  164. (+ (count-lines (point-min) (point))
  165. (if (bolp) 1 0)))))
  166. "source-buffer-not-found-for-%l"))
  167. ((eq key ?p) (if opt-str (int-to-string opt-str) ""))
  168. ;; String with escapes. %q follows shell (ksh, bash, zsh)
  169. ;; The other possibility was Python's %r, !r or "repr".
  170. ;; That isn't as perfect a fit though.
  171. ((eq key ?q) (if opt-str
  172. (let ((print-escape-newlines t))
  173. (prin1-to-string opt-str))
  174. ""))
  175. ;; String
  176. ((eq key ?s) (or opt-str ""))
  177. ((eq key ?x)
  178. (or (and src-file-name src-file-name)
  179. "*source-file-not-found-for-%x"))
  180. ((eq key ?X)
  181. (or (and src-file-name (expand-file-name src-file-name))
  182. "*source-file-not-found-for-%X"))
  183. ((eq key ?U)
  184. (if (string-match src-file-name "^file://")
  185. (setq src-file-name (substring src-file-name 7)))
  186. (or (and src-file-name (expand-file-name src-file-name))
  187. "*source-file-not-found-for-%X"))
  188. ;; ((eq key ?e)
  189. ;; (gud-find-expr))
  190. ;; ((eq key ?a)
  191. ;; (gud-read-address))
  192. ;; ((eq key ?c)
  193. ;; (gud-find-class srcbuf))
  194. (t key)))))
  195. (setq fmt-str (substring fmt-str (match-end 2))))
  196. ;; There might be text left in FMT-STR when the loop ends.
  197. (concat result fmt-str)))
  198. (defun realgud-command (fmt &optional arg no-record? frame-switch? realgud-prompts?)
  199. "Sends a command to the process associated with the command
  200. buffer of the current buffer. A bit of checking is done before
  201. sending the command to make sure that we can find a command
  202. buffer, and that it has a running process associated with it.
  203. FMT is a string which may contain format characters that are
  204. expanded. See `realgud-expand-format' for a list of the format
  205. characters and their meanings.
  206. If NO-RECORD? is set, the command won't be recorded in the
  207. position history. This is often done in status and information
  208. gathering or frame setting commands and is generally *not* done
  209. in commands that continue execution.
  210. If FRAME-SWITCH? is set, the fringe overlay array icon is set to
  211. indicate the depth of the frame.
  212. If REALGUD-PROMPTS? is set, then then issuing the command will cause a
  213. debugger prompt.
  214. "
  215. (interactive "sCommand (may contain format chars): ")
  216. (let* ((command-str (realgud-expand-format fmt arg))
  217. (cmd-buff (realgud-get-cmdbuf))
  218. )
  219. (unless cmd-buff
  220. (error "Can't find command buffer for buffer %s" (current-buffer)))
  221. ;; Display the expanded command in the message area unless the
  222. ;; current buffer is the command buffer.
  223. (unless (realgud-cmdbuf?)
  224. (message "Command: %s" command-str))
  225. (with-current-buffer cmd-buff
  226. (let* ((process (get-buffer-process cmd-buff))
  227. (last-output-end (point-marker))
  228. (in-srcbuf? (realgud-sget 'cmdbuf-info 'in-srcbuf?))
  229. )
  230. (unless process
  231. (error "Can't find process for command buffer %s" cmd-buff))
  232. (unless (eq 'run (process-status process))
  233. (error "Process %s isn't running; status %s" process
  234. (process-status process)))
  235. (realgud-cmdbuf-info-no-record?= no-record?)
  236. (realgud-cmdbuf-info-frame-switch?= frame-switch?)
  237. ;; Down the line we may handle prompting in a more
  238. ;; sophisticated way. But for now, we handle this by forcing
  239. ;; display of the command buffer.
  240. (if realgud-prompts? (realgud-window-cmd-undisturb-src nil 't))
  241. (realgud-send-command command-str (function realgud:send-command-common))
  242. ;; Wait for the process-mark to change before changing variables
  243. ;; that effect the hook processing.
  244. (while (and (eq 'run (process-status process))
  245. (equal last-output-end (process-mark process)))
  246. (sit-for 0))
  247. ;; Reset temporary hook-processing variables to their default state.
  248. (realgud-cmdbuf-info-no-record?= nil)
  249. (realgud-cmdbuf-info-frame-switch?= nil)
  250. ))))
  251. (provide-me "realgud-")