diff options
| author | Ken Manheimer | 2008-02-21 22:28:13 +0000 |
|---|---|---|
| committer | Ken Manheimer | 2008-02-21 22:28:13 +0000 |
| commit | 82ede38976aab812724f8c8075c83985ec771074 (patch) | |
| tree | ba6dda6060ef97352a1f5e0b56ef550a0a378306 /lisp/progmodes/python.el | |
| parent | 26e99723805dcf1809ffbe209f05722dc82845c3 (diff) | |
| download | emacs-82ede38976aab812724f8c8075c83985ec771074.tar.gz emacs-82ede38976aab812724f8c8075c83985ec771074.zip | |
Revise pdbtrack functionality to incorporate advances in python-mode.el.
(I'm doing this python.el checkin with some byte-compiler warnings. These
warnings existed before Nick Roberts or I applied any of the pdbtrack
changes, and look very clearly like preexisting, incomplete adoption of
code from python-mode.el. I'm going to next look at settling those
warnings, though I don't have time for a major reconciliation of the two
python-mode implementations.)
(python-pdbtrack-toggle-stack-tracking): Clarify docstring.
(python-pdbtrack-minor-mode-string): A sign indicating that pdb
tracking is happening.
(python-pdbtrack-stack-entry-regexp): Better recognize stack traces.
(python-pdbtrack-input-prompt): Better recognize PDB prompts.
(add python-pdbtrack-track-stack-file to comint-output-filter-functions):
Tracking is plugged in to all comint buffers once python.el is loaded.
(python-pdbtrack-overlay-arrow): Toggle activation of
`python-pdbtrack-minor-mode-string' in addition to the overlay arrow.
(python-pdbtrack-track-stack-file): Use new
`python-pdbtrack-get-source-buffer' for more flexible access to
debugging source files.
(python-pdbtrack-get-source-buffer): Identify debugging target
buffer according to pdb stack trace, optionally using new
`python-pdbtrack-grub-for-buffer' if file is not locally
available.
(python-pdbtrack-grub-for-buffer): Find most recent python-mode
named buffer, or having function with indicated name.
(python-shell): Remove comint-output-filter-functions hook
addition, it's being done elsewhere. Wrap long line.
Diffstat (limited to 'lisp/progmodes/python.el')
| -rw-r--r-- | lisp/progmodes/python.el | 195 |
1 files changed, 146 insertions, 49 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 9057e51e439..1b6632e0c29 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -545,15 +545,29 @@ mode buffer is visited during an Emacs session. After that, use | |||
| 545 | 545 | ||
| 546 | (defcustom python-pdbtrack-do-tracking-p t | 546 | (defcustom python-pdbtrack-do-tracking-p t |
| 547 | "*Controls whether the pdbtrack feature is enabled or not. | 547 | "*Controls whether the pdbtrack feature is enabled or not. |
| 548 | |||
| 548 | When non-nil, pdbtrack is enabled in all comint-based buffers, | 549 | When non-nil, pdbtrack is enabled in all comint-based buffers, |
| 549 | e.g. shell buffers and the *Python* buffer. When using pdb to debug a | 550 | e.g. shell interaction buffers and the *Python* buffer. |
| 550 | Python program, pdbtrack notices the pdb prompt and displays the | 551 | |
| 551 | source file and line that the program is stopped at, much the same way | 552 | When using pdb to debug a Python program, pdbtrack notices the |
| 552 | as gud-mode does for debugging C programs with gdb." | 553 | pdb prompt and presents the line in the source file where the |
| 554 | program is stopped in a pop-up buffer. It's similar to what | ||
| 555 | gud-mode does for debugging C programs with gdb, but without | ||
| 556 | having to restart the program." | ||
| 553 | :type 'boolean | 557 | :type 'boolean |
| 554 | :group 'python) | 558 | :group 'python) |
| 555 | (make-variable-buffer-local 'python-pdbtrack-do-tracking-p) | 559 | (make-variable-buffer-local 'python-pdbtrack-do-tracking-p) |
| 556 | 560 | ||
| 561 | (defcustom python-pdbtrack-minor-mode-string " PDB" | ||
| 562 | "*Minor-mode sign to be displayed when pdbtrack is active." | ||
| 563 | :type 'string | ||
| 564 | :group 'python) | ||
| 565 | |||
| 566 | ;; Add a designator to the minor mode strings | ||
| 567 | (or (assq 'python-pdbtrack-is-tracking-p minor-mode-alist) | ||
| 568 | (push '(python-pdbtrack-is-tracking-p python-pdbtrack-minor-mode-string) | ||
| 569 | minor-mode-alist)) | ||
| 570 | |||
| 557 | ;; Bind python-file-queue before installing the kill-emacs-hook. | 571 | ;; Bind python-file-queue before installing the kill-emacs-hook. |
| 558 | (defvar python-file-queue nil | 572 | (defvar python-file-queue nil |
| 559 | "Queue of Python temp files awaiting execution. | 573 | "Queue of Python temp files awaiting execution. |
| @@ -562,10 +576,10 @@ Currently-active file is at the head of the list.") | |||
| 562 | (defvar python-pdbtrack-is-tracking-p nil) | 576 | (defvar python-pdbtrack-is-tracking-p nil) |
| 563 | 577 | ||
| 564 | (defconst python-pdbtrack-stack-entry-regexp | 578 | (defconst python-pdbtrack-stack-entry-regexp |
| 565 | "> \\([^(]+\\)(\\([0-9]+\\))[?a-zA-Z0-9_]+()" | 579 | "^> \\(.*\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_]+\\)()" |
| 566 | "Regular expression pdbtrack uses to find a stack trace entry.") | 580 | "Regular expression pdbtrack uses to find a stack trace entry.") |
| 567 | 581 | ||
| 568 | (defconst python-pdbtrack-input-prompt "\n[(<]?pdb[>)]? " | 582 | (defconst python-pdbtrack-input-prompt "\n[(<]*[Pp]db[>)]+ " |
| 569 | "Regular expression pdbtrack uses to recognize a pdb prompt.") | 583 | "Regular expression pdbtrack uses to recognize a pdb prompt.") |
| 570 | 584 | ||
| 571 | (defconst python-pdbtrack-track-range 10000 | 585 | (defconst python-pdbtrack-track-range 10000 |
| @@ -2375,6 +2389,10 @@ without confirmation." | |||
| 2375 | 2389 | ||
| 2376 | ;;;; Modes. | 2390 | ;;;; Modes. |
| 2377 | 2391 | ||
| 2392 | ;; pdb tracking is alert once this file is loaded, but takes no action if | ||
| 2393 | ;; `python-pdbtrack-do-tracking-p' is nil. | ||
| 2394 | (add-hook 'comint-output-filter-functions 'python-pdbtrack-track-stack-file) | ||
| 2395 | |||
| 2378 | (defvar outline-heading-end-regexp) | 2396 | (defvar outline-heading-end-regexp) |
| 2379 | (defvar eldoc-documentation-function) | 2397 | (defvar eldoc-documentation-function) |
| 2380 | (defvar python-mode-running) ;Dynamically scoped var. | 2398 | (defvar python-mode-running) ;Dynamically scoped var. |
| @@ -2700,17 +2718,16 @@ This function is appropriate for `comint-output-filter-functions'." | |||
| 2700 | (python-execute-file pyproc (car python-file-queue)))))) | 2718 | (python-execute-file pyproc (car python-file-queue)))))) |
| 2701 | 2719 | ||
| 2702 | (defun python-pdbtrack-overlay-arrow (activation) | 2720 | (defun python-pdbtrack-overlay-arrow (activation) |
| 2703 | "Activate or de arrow at beginning-of-line in current buffer." | 2721 | "Activate or deactivate arrow at beginning-of-line in current buffer." |
| 2704 | ;; This was derived/simplified from edebug-overlay-arrow | 2722 | (if activation |
| 2705 | (cond (activation | 2723 | (progn |
| 2706 | (setq overlay-arrow-position (make-marker)) | 2724 | (setq overlay-arrow-position (make-marker) |
| 2707 | (setq overlay-arrow-string "=>") | 2725 | overlay-arrow-string "=>" |
| 2708 | (set-marker overlay-arrow-position | 2726 | python-pdbtrack-is-tracking-p t) |
| 2709 | (python-point 'bol) (current-buffer)) | 2727 | (set-marker overlay-arrow-position |
| 2710 | (setq python-pdbtrack-is-tracking-p t)) | 2728 | (python-point 'bol) (current-buffer))) |
| 2711 | (python-pdbtrack-is-tracking-p | 2729 | (setq overlay-arrow-position nil |
| 2712 | (setq overlay-arrow-position nil) | 2730 | python-pdbtrack-is-tracking-p nil))) |
| 2713 | (setq python-pdbtrack-is-tracking-p nil)))) | ||
| 2714 | 2731 | ||
| 2715 | (defun python-pdbtrack-track-stack-file (text) | 2732 | (defun python-pdbtrack-track-stack-file (text) |
| 2716 | "Show the file indicated by the pdb stack entry line, in a separate window. | 2733 | "Show the file indicated by the pdb stack entry line, in a separate window. |
| @@ -2718,49 +2735,131 @@ This function is appropriate for `comint-output-filter-functions'." | |||
| 2718 | Activity is disabled if the buffer-local variable | 2735 | Activity is disabled if the buffer-local variable |
| 2719 | `python-pdbtrack-do-tracking-p' is nil. | 2736 | `python-pdbtrack-do-tracking-p' is nil. |
| 2720 | 2737 | ||
| 2721 | We depend on the pdb input prompt matching `python-pdbtrack-input-prompt' | 2738 | We depend on the pdb input prompt being a match for |
| 2722 | at the beginning of the line." | 2739 | `python-pdbtrack-input-prompt'. |
| 2740 | |||
| 2741 | If the traceback target file path is invalid, we look for the | ||
| 2742 | most recently visited python-mode buffer which either has the | ||
| 2743 | name of the current function or class, or which defines the | ||
| 2744 | function or class. This is to provide for scripts not in the | ||
| 2745 | local filesytem (e.g., Zope's 'Script \(Python)', but it's not | ||
| 2746 | Zope specific). If you put a copy of the script in a buffer | ||
| 2747 | named for the script and activate python-mode, then pdbtrack will | ||
| 2748 | find it." | ||
| 2723 | ;; Instead of trying to piece things together from partial text | 2749 | ;; Instead of trying to piece things together from partial text |
| 2724 | ;; (which can be almost useless depending on Emacs version), we | 2750 | ;; (which can be almost useless depending on Emacs version), we |
| 2725 | ;; monitor to the point where we have the next pdb prompt, and then | 2751 | ;; monitor to the point where we have the next pdb prompt, and then |
| 2726 | ;; check all text from comint-last-input-end to process-mark. | 2752 | ;; check all text from comint-last-input-end to process-mark. |
| 2727 | ;; | 2753 | ;; |
| 2728 | ;; KLM: It might be nice to provide an optional override, so this | 2754 | ;; Also, we're very conservative about clearing the overlay arrow, |
| 2729 | ;; routine could be fed debugger output strings as the text | 2755 | ;; to minimize residue. This means, for instance, that executing |
| 2730 | ;; argument, for deliberate application elsewhere. | 2756 | ;; other pdb commands wipe out the highlight. You can always do a |
| 2731 | ;; | 2757 | ;; 'where' (aka 'w') PDB command to reveal the overlay arrow. |
| 2732 | ;; KLM: We're very conservative about clearing the overlay arrow, to | 2758 | |
| 2733 | ;; minimize residue. This means, for instance, that executing other | ||
| 2734 | ;; pdb commands wipes out the highlight. | ||
| 2735 | (let* ((origbuf (current-buffer)) | 2759 | (let* ((origbuf (current-buffer)) |
| 2736 | (currproc (get-buffer-process origbuf))) | 2760 | (currproc (get-buffer-process origbuf))) |
| 2761 | |||
| 2737 | (if (not (and currproc python-pdbtrack-do-tracking-p)) | 2762 | (if (not (and currproc python-pdbtrack-do-tracking-p)) |
| 2738 | (python-pdbtrack-overlay-arrow nil) | 2763 | (python-pdbtrack-overlay-arrow nil) |
| 2739 | (let* (;(origdir default-directory) | 2764 | |
| 2740 | (procmark (process-mark currproc)) | 2765 | (let* ((procmark (process-mark currproc)) |
| 2741 | (block (buffer-substring (max comint-last-input-end | 2766 | (block (buffer-substring (max comint-last-input-end |
| 2742 | (- procmark | 2767 | (- procmark |
| 2743 | python-pdbtrack-track-range)) | 2768 | python-pdbtrack-track-range)) |
| 2744 | procmark)) | 2769 | procmark)) |
| 2745 | fname lineno) | 2770 | target target_fname target_lineno target_buffer) |
| 2771 | |||
| 2746 | (if (not (string-match (concat python-pdbtrack-input-prompt "$") block)) | 2772 | (if (not (string-match (concat python-pdbtrack-input-prompt "$") block)) |
| 2747 | (python-pdbtrack-overlay-arrow nil) | 2773 | (python-pdbtrack-overlay-arrow nil) |
| 2748 | (if (not (string-match | 2774 | |
| 2749 | (concat ".*" python-pdbtrack-stack-entry-regexp ".*") | 2775 | (setq target (python-pdbtrack-get-source-buffer block)) |
| 2750 | block)) | 2776 | |
| 2751 | (python-pdbtrack-overlay-arrow nil) | 2777 | (if (stringp target) |
| 2752 | (setq fname (match-string 1 block) | 2778 | (progn |
| 2753 | lineno (match-string 2 block)) | 2779 | (python-pdbtrack-overlay-arrow nil) |
| 2754 | (if (file-exists-p fname) | 2780 | (message "pdbtrack: %s" target)) |
| 2755 | (progn | 2781 | |
| 2756 | (find-file-other-window fname) | 2782 | (setq target_lineno (car target) |
| 2757 | (goto-line (string-to-number lineno)) | 2783 | target_buffer (cadr target) |
| 2758 | (message "pdbtrack: line %s, file %s" lineno fname) | 2784 | target_fname (buffer-file-name target_buffer)) |
| 2759 | (python-pdbtrack-overlay-arrow t) | 2785 | (switch-to-buffer-other-window target_buffer) |
| 2760 | (pop-to-buffer origbuf t) ) | 2786 | (goto-line target_lineno) |
| 2761 | (if (= (elt fname 0) ?\<) | 2787 | (message "pdbtrack: line %s, file %s" target_lineno target_fname) |
| 2762 | (message "pdbtrack: (Non-file source: '%s')" fname) | 2788 | (python-pdbtrack-overlay-arrow t) |
| 2763 | (message "pdbtrack: File not found: %s" fname))))))))) | 2789 | (pop-to-buffer origbuf t) |
| 2790 | ;; in large shell buffers, above stuff may cause point to lag output | ||
| 2791 | (goto-char procmark) | ||
| 2792 | ))))) | ||
| 2793 | ) | ||
| 2794 | |||
| 2795 | (defun python-pdbtrack-get-source-buffer (block) | ||
| 2796 | "Return line number and buffer of code indicated by block's traceback text. | ||
| 2797 | |||
| 2798 | We look first to visit the file indicated in the trace. | ||
| 2799 | |||
| 2800 | Failing that, we look for the most recently visited python-mode buffer | ||
| 2801 | with the same name or having the named function. | ||
| 2802 | |||
| 2803 | If we're unable find the source code we return a string describing the | ||
| 2804 | problem." | ||
| 2805 | |||
| 2806 | (if (not (string-match python-pdbtrack-stack-entry-regexp block)) | ||
| 2807 | |||
| 2808 | "Traceback cue not found" | ||
| 2809 | |||
| 2810 | (let* ((filename (match-string 1 block)) | ||
| 2811 | (lineno (string-to-number (match-string 2 block))) | ||
| 2812 | (funcname (match-string 3 block)) | ||
| 2813 | funcbuffer) | ||
| 2814 | |||
| 2815 | (cond ((file-exists-p filename) | ||
| 2816 | (list lineno (find-file-noselect filename))) | ||
| 2817 | |||
| 2818 | ((setq funcbuffer (python-pdbtrack-grub-for-buffer funcname lineno)) | ||
| 2819 | (if (string-match "/Script (Python)$" filename) | ||
| 2820 | ;; Add in number of lines for leading '##' comments: | ||
| 2821 | (setq lineno | ||
| 2822 | (+ lineno | ||
| 2823 | (save-excursion | ||
| 2824 | (set-buffer funcbuffer) | ||
| 2825 | (if (equal (point-min)(point-max)) | ||
| 2826 | 0 | ||
| 2827 | (count-lines | ||
| 2828 | (point-min) | ||
| 2829 | (max (point-min) | ||
| 2830 | (string-match "^\\([^#]\\|#[^#]\\|#$\\)" | ||
| 2831 | (buffer-substring | ||
| 2832 | (point-min) (point-max))) | ||
| 2833 | ))))))) | ||
| 2834 | (list lineno funcbuffer)) | ||
| 2835 | |||
| 2836 | ((= (elt filename 0) ?\<) | ||
| 2837 | (format "(Non-file source: '%s')" filename)) | ||
| 2838 | |||
| 2839 | (t (format "Not found: %s(), %s" funcname filename))) | ||
| 2840 | ) | ||
| 2841 | ) | ||
| 2842 | ) | ||
| 2843 | |||
| 2844 | (defun python-pdbtrack-grub-for-buffer (funcname lineno) | ||
| 2845 | "Find recent python-mode buffer named, or having function named funcname." | ||
| 2846 | (let ((buffers (buffer-list)) | ||
| 2847 | buf | ||
| 2848 | got) | ||
| 2849 | (while (and buffers (not got)) | ||
| 2850 | (setq buf (car buffers) | ||
| 2851 | buffers (cdr buffers)) | ||
| 2852 | (if (and (save-excursion (set-buffer buf) | ||
| 2853 | (string= major-mode "python-mode")) | ||
| 2854 | (or (string-match funcname (buffer-name buf)) | ||
| 2855 | (string-match (concat "^\\s-*\\(def\\|class\\)\\s-+" | ||
| 2856 | funcname "\\s-*(") | ||
| 2857 | (save-excursion | ||
| 2858 | (set-buffer buf) | ||
| 2859 | (buffer-substring (point-min) | ||
| 2860 | (point-max)))))) | ||
| 2861 | (setq got buf))) | ||
| 2862 | got)) | ||
| 2764 | 2863 | ||
| 2765 | (defun python-toggle-shells (arg) | 2864 | (defun python-toggle-shells (arg) |
| 2766 | "Toggles between the CPython and JPython shells. | 2865 | "Toggles between the CPython and JPython shells. |
| @@ -2857,14 +2956,12 @@ filter." | |||
| 2857 | (switch-to-buffer-other-window | 2956 | (switch-to-buffer-other-window |
| 2858 | (apply 'make-comint python-which-bufname python-which-shell nil args)) | 2957 | (apply 'make-comint python-which-bufname python-which-shell nil args)) |
| 2859 | (make-local-variable 'comint-prompt-regexp) | 2958 | (make-local-variable 'comint-prompt-regexp) |
| 2860 | (set-process-sentinel (get-buffer-process (current-buffer)) 'python-sentinel) | 2959 | (set-process-sentinel (get-buffer-process (current-buffer)) |
| 2960 | 'python-sentinel) | ||
| 2861 | (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ") | 2961 | (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ") |
| 2862 | (add-hook 'comint-output-filter-functions | 2962 | (add-hook 'comint-output-filter-functions |
| 2863 | 'python-comint-output-filter-function nil t) | 2963 | 'python-comint-output-filter-function nil t) |
| 2864 | ;; pdbtrack | 2964 | ;; pdbtrack |
| 2865 | (add-hook 'comint-output-filter-functions | ||
| 2866 | 'python-pdbtrack-track-stack-file nil t) | ||
| 2867 | (setq python-pdbtrack-do-tracking-p t) | ||
| 2868 | (set-syntax-table python-mode-syntax-table) | 2965 | (set-syntax-table python-mode-syntax-table) |
| 2869 | (use-local-map python-shell-map))) | 2966 | (use-local-map python-shell-map))) |
| 2870 | 2967 | ||