1 ;;; Copyright (C) 2014-2015 Rocky Bernstein <rocky@gnu.org>
6 (require 'load-relative)
7 (require-relative-list '("core" "track" "utils") "realgud-")
8 (require-relative-list '("buffer/command") "realgud-buffer-")
10 (declare-function realgud-cmdbuf-info-in-debugger?= 'realgud-buffer-command)
11 (declare-function realgud-cmdbuf-info-cmd-args= 'realgud-buffer-command)
12 (declare-function realgud:track-set-debugger 'realgud-track)
13 (declare-function realgud-parse-command-arg 'realgud-core)
14 (declare-function realgud:expand-file-name-if-exists 'realgud-core)
16 (defun realgud:parse-cmd-args(args two-args opt-two-args interp-regexp debugger-regexp
17 path-args-list annotate-args)
18 "Parse command line ARGS for the annotate level and name of script to debug.
20 ARGS should contain a tokenized list of the command line to run.
22 We return the a list containing:
23 * the command processor (e.g. bash) and it's arguments if any - a list of strings
24 * the name of the debugger given (e.g. bashdb) and its arguments - a list of strings.
25 If there is no debugger, for example gdb, nodejs then nil is returned.
26 * the script name and its arguments - list of strings
27 * whether the annotate or emacs option was given ('-A', '--annotate' or '--emacs) - a boolean
29 The script name and options mentioning paths are file expanded
31 For example for the following input
32 (map 'list 'symbol-name
33 '(bash --norc bashdb -l . --emacs ./gcd.sh a b))
36 ((\"bash\" \"--norc\") (\"bashdb\" \"-l\" \"/tmp\" \"--emacs\") (\"/tmp/gcd.sh\" \"a\" \"b\") t)
38 Note that path elements have been expanded via `expand-file-name'.
40 ;; Parse the following kind of pattern:
41 ;; [bash bash-options] bashdb bashdb-options script-name script-options
47 (interpreter-args '())
53 ;; Got nothing: return '(nil, nil nil nil)
54 (list interpreter-args debugger-args script-args annotate-p)
56 ;; Strip off optional interpreter name
57 (when (and interp-regexp
58 (string-match interp-regexp
59 (file-name-sans-extension
60 (file-name-nondirectory (car args)))))
61 (setq interpreter-args (list (pop args)))
63 ;; Strip off compiler/intepreter-specific options
65 (string-match "^-" (car args)))
66 (setq pair (realgud-parse-command-arg
67 args two-args opt-two-args))
68 (nconc interpreter-args (car pair))
69 (setq args (cadr pair))))
71 ;; Skip to the first non-option argument.
72 (while (and args (not script-name))
73 (let ((arg (car args)))
76 ((member arg path-args-list)
79 (list arg (realgud:expand-file-name-if-exists
81 ;; Other options with arguments.
82 ((string-match "^-" arg)
83 (setq pair (realgud-parse-command-arg
84 args two-args opt-two-args))
85 (nconc debugger-args (car pair))
86 (setq args (cadr pair)))
87 ;; Anything else must be the script to debug.
88 (t (setq script-name (realgud:expand-file-name-if-exists arg))
89 (setq script-args (cons script-name (cdr args))))
91 (list interpreter-args debugger-args script-args annotate-p))))
93 (defun realgud:run-process(debugger-name script-filename cmd-args
96 "Runs `realgud-exec-shell' with DEBUGGER-NAME SCRIPT-FILENAME
97 and CMD-ARGS If this succeeds, we save CMD-ARGS in command-buffer
98 for use if we want to restart. If we don't succeed in running
99 the program, we will switch to the command buffer which shows
100 details of the error. The command buffer or nil is returned."
105 (apply 'realgud-exec-shell debugger-name script-filename
106 (car cmd-args) no-reset (cdr cmd-args)))
108 ;; FIXME: Is there probably is a way to remove the
109 ;; below test and combine in condition-case?
110 (let ((process (get-buffer-process cmd-buf)))
111 (if (and process (eq 'run (process-status process)))
113 (switch-to-buffer cmd-buf)
114 (realgud:track-set-debugger debugger-name)
115 (realgud-cmdbuf-info-in-debugger?= 't)
116 (realgud-cmdbuf-info-cmd-args= cmd-args)
118 (switch-to-buffer cmd-buf)
119 (when realgud-cmdbuf-info
120 (let* ((info realgud-cmdbuf-info)
121 (cmd-args (realgud-cmdbuf-info-cmd-args info))
122 (cmd-str (mapconcat 'identity cmd-args " ")))
123 (set minibuffer-history
124 (list-utils-uniq (cons cmd-str
125 (eval minibuffer-history)))
130 (if cmd-buf (switch-to-buffer cmd-buf))
131 (message "Error running command: %s" (mapconcat 'identity cmd-args " "))
139 (defun realgud:run-debugger (debugger-name query-cmdline-fn parse-cmd-args-fn
141 &optional opt-command-line
143 "Invoke the a debugger and start the Emacs user interface.
145 String OPT-COMMAND-LINE specifies how to run DEBUGGER-NAME. You
146 will be prompted for a command line using QUERY-CMDLINE-FN is one
149 OPT-COMMAND-LINE is treated like a shell string; arguments are
150 tokenized by `split-string-and-unquote'. The tokenized string is
151 parsed by PARSE-CMD-FN and path elements found by that
152 are expanded using `expand-file-name'.
154 If successful, The command buffer of the debugger process is returned.
155 Otherwise nil is returned.
157 (let* ((cmd-str (or opt-command-line (funcall query-cmdline-fn debugger-name)))
158 (cmd-args (split-string-and-unquote cmd-str))
159 (parsed-args (funcall parse-cmd-args-fn cmd-args))
160 (script-args (caddr parsed-args))
161 (script-name (car script-args))
163 (remove-if 'nil (realgud:flatten parsed-args)))
165 (realgud:run-process debugger-name script-name parsed-cmd-args
166 minibuffer-history no-reset)
170 (provide-me "realgud:")
173 ;; byte-compile-warnings: (not cl-functions)