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")