Mercurial > emacs
comparison lisp/progmodes/python.el @ 92060:fd85a7810d53
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.
| author | Ken Manheimer <ken.manheimer@gmail.com> |
|---|---|
| date | Thu, 21 Feb 2008 22:28:13 +0000 |
| parents | 373b00a4775c |
| children | 105ec1146aa7 |
comparison
equal
deleted
inserted
replaced
| 92059:a22a49c13e2b | 92060:fd85a7810d53 |
|---|---|
| 543 (make-variable-buffer-local 'python-which-args) | 543 (make-variable-buffer-local 'python-which-args) |
| 544 (make-variable-buffer-local 'python-which-bufname) | 544 (make-variable-buffer-local 'python-which-bufname) |
| 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) |
| 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)) | |
| 556 | 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. |
| 560 Currently-active file is at the head of the list.") | 574 Currently-active file is at the head of the list.") |
| 561 | 575 |
| 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 |
| 572 "Max number of characters from end of buffer to search for stack entry.") | 586 "Max number of characters from end of buffer to search for stack entry.") |
| 573 | 587 |
| 2373 ["Undo Last Refactoring" brm-undo :help ""])))) | 2387 ["Undo Last Refactoring" brm-undo :help ""])))) |
| 2374 (error (error "BicycleRepairMan setup failed: %s" data)))) | 2388 (error (error "BicycleRepairMan setup failed: %s" data)))) |
| 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. |
| 2381 | 2399 |
| 2382 ;; Stuff to allow expanding abbrevs with non-word constituents. | 2400 ;; Stuff to allow expanding abbrevs with non-word constituents. |
| 2698 (if python-file-queue | 2716 (if python-file-queue |
| 2699 (let ((pyproc (get-buffer-process (current-buffer)))) | 2717 (let ((pyproc (get-buffer-process (current-buffer)))) |
| 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. |
| 2717 | 2734 |
| 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. |
| 2767 | 2866 |
| 2768 With positive argument ARG (interactively \\[universal-argument]), | 2867 With positive argument ARG (interactively \\[universal-argument]), |
| 2855 (mapconcat 'identity python-which-args " ") " ") | 2954 (mapconcat 'identity python-which-args " ") " ") |
| 2856 )))) | 2955 )))) |
| 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 |
| 2871 (defun python-pdbtrack-toggle-stack-tracking (arg) | 2968 (defun python-pdbtrack-toggle-stack-tracking (arg) |
| 2872 (interactive "P") | 2969 (interactive "P") |
