Permalink
Browse files

Add stock Python debugger.

  • Loading branch information...
1 parent 4a29c6f commit 26e62737c2809ff3d0f1b37ba1d26f92fbd49047 @rocky rocky committed May 12, 2012
View
@@ -1,6 +1,7 @@
-/*.elc
+*.elc
+*~
+elc-stamp
/*.tar.gz
-/*~
/COPYING
/Makefile
/Makefile.in
@@ -14,3 +15,4 @@
/elc-temp
/install-sh
/missing
+script
View
@@ -9,6 +9,7 @@ Debuggers we currently support are:
* "kshdb":https://github.com/rocky/kshdb/wiki (Korn Shell)
* perldb (Perl)
* "Devel::Trepan":https://github.com/rocky/Perl-Devel-Trepan/wiki (Perl)
+ * pdb (Stock C Python debugger)
* "pydb":http://bashdb.sourceforge.net/pydb/ (Python)
* "pydbgr":http://code.google.com/p/pydbgr/ (Python)
* "trepanning":https://github.com/rocky/rb-trepanning/wiki (Ruby 1.9)
View
@@ -38,6 +38,7 @@ AC_CONFIG_FILES([Makefile \
dbgr/debugger/gdb/Makefile \
dbgr/debugger/kshdb/Makefile \
dbgr/debugger/perldb/Makefile \
+ dbgr/debugger/pdb/Makefile \
dbgr/debugger/pydbgr/Makefile \
dbgr/debugger/rdebug/Makefile \
dbgr/debugger/remake/Makefile \
View
@@ -16,6 +16,7 @@
"./dbgr/debugger/bashdb/bashdb"
"./dbgr/debugger/gdb/gdb"
"./dbgr/debugger/kshdb/kshdb"
+ "./dbgr/debugger/pdb/pdb"
"./dbgr/debugger/pydbgr/pydbgr"
"./dbgr/debugger/perldb/perldb"
"./dbgr/debugger/rdebug/rdebug"
@@ -1,4 +1,4 @@
-SUBDIRS = bashdb gdb kshdb perldb pydbgr rdebug remake \
+SUBDIRS = bashdb gdb kshdb pdb perldb pydbgr rdebug remake \
trepan trepan.pl trepanx trepan8 zshdb
EXTRA_DIST = common.mk
@@ -0,0 +1,3 @@
+/Makefile
+/Makefile.in
+/core.elc
@@ -0,0 +1 @@
+include ../common.mk
View
@@ -0,0 +1,153 @@
+;;; Copyright (C) 2012 Rocky Bernstein <rocky@gnu.org>
+(eval-when-compile (require 'cl))
+
+(require 'load-relative)
+(require-relative-list '("../../common/track"
+ "../../common/core"
+ "../../common/lang")
+ "dbgr-")
+(require-relative-list '("init") "dbgr-pdb-")
+
+
+;; FIXME: I think the following could be generalized and moved to
+;; dbgr-... probably via a macro.
+(defvar pdb-minibuffer-history nil
+ "minibuffer history list for the command `pdb'.")
+
+(easy-mmode-defmap pdb-minibuffer-local-map
+ '(("\C-i" . comint-dynamic-complete-filename))
+ "Keymap for minibuffer prompting of gud startup command."
+ :inherit minibuffer-local-map)
+
+;; FIXME: I think this code and the keymaps and history
+;; variable chould be generalized, perhaps via a macro.
+(defun pdb-query-cmdline (&optional opt-debugger)
+ (dbgr-query-cmdline
+ 'pdb-suggest-invocation
+ pdb-minibuffer-local-map
+ 'pdb-minibuffer-history
+ opt-debugger))
+
+(defun pdb-parse-cmd-args (orig-args)
+ "Parse command line ARGS for the annotate level and name of script to debug.
+
+ARGS should contain a tokenized list of the command line to run.
+
+We return the a list containing
+- the command processor (e.g. python) and it's arguments if any - a list of strings
+- the name of the debugger given (e.g. pdb) and its arguments - a list of strings
+- the script name and its arguments - list of strings
+- whether the annotate or emacs option was given ('-A', '--annotate' or '--emacs) - a boolean
+
+For example for the following input
+ (map 'list 'symbol-name
+ '(python2.6 -O -Qold ./gcd.py a b))
+
+we might return:
+ ((python2.6 -O -Qold) (pdb) (./gcd.py a b) 't)
+
+NOTE: the above should have each item listed in quotes.
+"
+
+ ;; Parse the following kind of pattern:
+ ;; [python python-options] pdb pdb-options script-name script-options
+ (let (
+ (args orig-args)
+ (pair) ;; temp return from
+ (python-opt-two-args '())
+ ;; Python doesn't have mandatory 2-arg options in our sense,
+ ;; since the two args can be run together, e.g. "-C/tmp" or "-C /tmp"
+ ;;
+ (python-two-args '())
+ ;; pdb doesn't have any arguments
+ (pdb-two-args '())
+ (pdb-opt-two-args '())
+ (interp-regexp
+ (if (member system-type (list 'windows-nt 'cygwin 'msdos))
+ "^python[-0-9.]*\\(.exe\\)?$"
+ "^python[-0-9.]*$"))
+
+ ;; Things returned
+ (annotate-p nil)
+ (debugger-args '())
+ (debugger-name nil)
+ (interpreter-args '())
+ (script-args '())
+ (script-name nil)
+ )
+
+ (if (not (and args))
+ ;; Got nothing: return '(nil, nil)
+ (list interpreter-args debugger-args script-args annotate-p)
+ ;; else
+ ;; Strip off optional "python" or "python182" etc.
+ (when (string-match interp-regexp
+ (file-name-sans-extension
+ (file-name-nondirectory (car args))))
+ (setq interpreter-args (list (pop args)))
+
+ ;; Strip off Python-specific options
+ (while (and args
+ (string-match "^-" (car args)))
+ (setq pair (dbgr-parse-command-arg
+ args python-two-args python-opt-two-args))
+ (nconc interpreter-args (car pair))
+ (setq args (cadr pair))))
+
+ ;; Remove "pdb" from "pdb --pdb-options script
+ ;; --script-options"
+ (setq debugger-name (file-name-sans-extension
+ (file-name-nondirectory (car args))))
+ (unless (string-match "^\\(pdb\\|cli.py\\)$" debugger-name)
+ (message
+ "Expecting debugger name `%s' to be `pdb' or `cli.py'"
+ debugger-name))
+ (setq debugger-args (list (pop args)))
+
+ ;; Skip to the first non-option argument.
+ (while (and args (not script-name))
+ (let ((arg (car args)))
+ (cond
+ ;; Options with arguments.
+ ((string-match "^-" arg)
+ (setq pair (dbgr-parse-command-arg
+ args pdb-two-args pdb-opt-two-args))
+ (nconc debugger-args (car pair))
+ (setq args (cadr pair)))
+ ;; Anything else must be the script to debug.
+ (t (setq script-name arg)
+ (setq script-args args))
+ )))
+ (list interpreter-args debugger-args script-args annotate-p))))
+
+(defvar pdb-command-name) ; # To silence Warning: reference to free variable
+(defun pdb-suggest-invocation (debugger-name)
+ "Suggest a pdb command invocation via `dbgr-suggest-invocaton'"
+ (dbgr-suggest-invocation pdb-command-name pdb-minibuffer-history
+ "python" "\\.py"))
+
+(defun pdb-reset ()
+ "Pdb cleanup - remove debugger's internal buffers (frame,
+breakpoints, etc.)."
+ (interactive)
+ ;; (pdb-breakpoint-remove-all-icons)
+ (dolist (buffer (buffer-list))
+ (when (string-match "\\*pdb-[a-z]+\\*" (buffer-name buffer))
+ (let ((w (get-buffer-window buffer)))
+ (when w
+ (delete-window w)))
+ (kill-buffer buffer))))
+
+;; (defun pdb-reset-keymaps()
+;; "This unbinds the special debugger keys of the source buffers."
+;; (interactive)
+;; (setcdr (assq 'pdb-debugger-support-minor-mode minor-mode-map-alist)
+;; pdb-debugger-support-minor-mode-map-when-deactive))
+
+
+(defun pdb-customize ()
+ "Use `customize' to edit the settings of the `pdb' debugger."
+ (interactive)
+ (customize-group 'pdb))
+
+(provide-me "dbgr-pdb-")
View
@@ -0,0 +1,99 @@
+;;; Copyright (C) 2012 Rocky Bernstein <rocky@gnu.org>
+;;; Stock Python debugger pdb
+
+(eval-when-compile (require 'cl))
+
+(require 'load-relative)
+(require-relative-list '("../../common/regexp"
+ "../../common/loc"
+ "../../common/init")
+ "dbgr-")
+(require-relative-list '("../../lang/python") "dbgr-lang-")
+
+(defvar dbgr-pat-hash)
+(declare-function make-dbgr-loc-pat (dbgr-loc))
+
+(defvar dbgr-pdb-pat-hash (make-hash-table :test 'equal)
+ "Hash key is the what kind of pattern we want to match:
+backtrace, prompt, etc. The values of a hash entry is a
+dbgr-loc-pat struct")
+
+(declare-function make-dbgr-loc "dbgr-loc" (a b c d e f))
+
+;; Regular expression that describes a pdb location generally shown
+;; before a command prompt.
+;;
+;; Program-location lines look like this:
+;; > /usr/bin/zonetab2pot.py(15)<module>()
+;; or MS Windows:
+;; > c:\\mydirectory\\gcd.py(10)<module>
+(setf (gethash "loc" dbgr-pdb-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp "^> \\(\\(?:[a-zA-Z]:\\)?[-a-zA-Z0-9_/.\\\\ ]+\\)(\\([0-9]+\\))"
+ :file-group 1
+ :line-group 2))
+
+(setf (gethash "prompt" dbgr-pdb-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp "^[(]+Pdb[)]+ "
+ ))
+
+;; Regular expression that describes a Python backtrace line.
+(setf (gethash "lang-backtrace" dbgr-pdb-pat-hash)
+ dbgr-python-backtrace-loc-pat)
+
+;; Regular expression that describes a "breakpoint set" line. For example:
+;; Breakpoint 1 at /usr/bin/pdb:7
+(setf (gethash "brkpt-set" dbgr-pdb-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp "^Breakpoint \\([0-9]+\\) at[ \t\n]+\\(.+\\):\\([0-9]+\\)\\(\n\\|$\\)"
+ :num 1
+ :file-group 2
+ :line-group 3))
+
+;; Regular expression that describes a "delete breakpoint" line
+(setf (gethash "brkpt-del" dbgr-pdb-pat-hash)
+ (make-dbgr-loc-pat
+ :regexp "^Deleted breakpoint \\([0-9]+\\)\n"
+ :num 1))
+
+(setf (gethash "font-lock-keywords" dbgr-pdb-pat-hash)
+ '(
+ ;; The frame number and first type name, if present.
+ ("^\\(->\\|##\\)\\([0-9]+\\) \\(<module>\\)? *\\([a-zA-Z_][a-zA-Z0-9_]*\\)(\\(.+\\))?"
+ (2 dbgr-backtrace-number-face)
+ (4 font-lock-function-name-face nil t)) ; t means optional.
+
+ ;; Parameter sequence, E.g. gcd(a=3, b=5)
+ ;; ^^^^^^^^^
+ ("(\\(.+\\))"
+ (1 font-lock-variable-name-face))
+
+ ;; File name. E.g file '/test/gcd.py'
+ ;; ------^^^^^^^^^^^^-
+ ("[ \t]+file '\\([^ ]+*\\)'"
+ (1 dbgr-file-name-face))
+
+ ;; Line number. E.g. at line 28
+ ;; ---------^^
+ ("[ \t]+at line \\([0-9]+\\)$"
+ (1 dbgr-line-number-face))
+
+ ;; Function name.
+ ("\\<\\([a-zA-Z_][a-zA-Z0-9_]*\\)\\.\\([a-zA-Z_][a-zA-Z0-9_]*\\)"
+ (1 font-lock-type-face)
+ (2 font-lock-function-name-face))
+ ;; (pdb-frames-match-current-line
+ ;; (0 pdb-frames-current-frame-face append))
+ ))
+
+(setf (gethash "pdb" dbgr-pat-hash) dbgr-pdb-pat-hash)
+
+(defvar dbgr-pdb-command-hash (make-hash-table :test 'equal)
+ "Hash key is command name like 'shell' and the value is
+ the pdb command to use, like 'python'")
+
+(setf (gethash "shell" dbgr-pdb-command-hash) "python")
+(setf (gethash "pdb" dbgr-command-hash) dbgr-pdb-command-hash)
+
+(provide-me "dbgr-pdb-")
View
@@ -0,0 +1,65 @@
+;;; Copyright (C) 2012 Rocky Bernstein <rocky@gnu.org>
+;; `pdb' Main interface to pdb via Emacs
+(require 'load-relative)
+(require-relative-list '("../../common/helper"
+ "../../common/track") "dbgr-")
+(require-relative-list '("core" "track-mode") "dbgr-pdb-")
+
+;; This is needed, or at least the docstring part of it is needed to
+;; get the customization menu to work in Emacs 23.
+(defgroup pdb nil
+ "The Python pdb debugger"
+ :group 'processes
+ :group 'dbgr
+ :group 'python
+ :version "23.1")
+
+;; -------------------------------------------------------------------
+;; User definable variables
+;;
+
+(defcustom pdb-command-name
+ "pdb"
+ "File name for executing the stock Python debugger and command options.
+This should be an executable on your path, or an absolute file name."
+ :type 'string
+ :group 'pdb)
+
+(declare-function pdb-track-mode (bool))
+
+;; -------------------------------------------------------------------
+;; The end.
+;;
+
+;;;###autoload
+(defun dbgr-pdb (&optional opt-command-line no-reset)
+ "Invoke the pdb Python debugger and start the Emacs user interface.
+
+String COMMAND-LINE specifies how to run pdb.
+
+Normally command buffers are reused when the same debugger is
+reinvoked inside a command buffer with a similar command. If we
+discover that the buffer has prior command-buffer information and
+NO-RESET is nil, then that information which may point into other
+buffers and source buffers which may contain marks and fringe or
+marginal icons is reset."
+
+
+ (interactive)
+ (let* (
+ (cmd-str (or opt-command-line (pdb-query-cmdline
+ "pdb")))
+ (cmd-args (split-string-and-unquote cmd-str))
+ (parsed-args (pdb-parse-cmd-args cmd-args))
+ (script-args (cdr cmd-args))
+ (script-name (car script-args))
+ (cmd-buf))
+ (dbgr-run-process "pdb" script-name cmd-args
+ 'pdb-track-mode no-reset)
+ )
+ )
+
+
+(defalias 'pdb 'dbgr-pdb)
+
+(provide-me "dbgr-")
Oops, something went wrong.

0 comments on commit 26e6273

Please sign in to comment.