;; start on, so go back to the last expression. The recursive ;; call will find this place again and add it to the correct ;; list (re-search-backward py-imenu-generic-regexp (point-min) 'move) (setq sub-method-alist (py-imenu-create-index-engine cur-indent)) (if sub-method-alist ;; we put the last element on the index-alist on the start ;; of the submethod alist so the user can still get to it. (let ((save-elmt (pop index-alist))) (push (cons prev-name (cons save-elmt sub-method-alist)) index-alist)))) ;; found less indented expression, we're done. (t (setq looking-p nil) (re-search-backward py-imenu-generic-regexp (point-min) t))) ;; end-cond (setq prev-name def-name) (and looking-p (setq looking-p (re-search-forward py-imenu-generic-regexp (point-max) 'move)))) (nreverse index-alist))) (defun py-choose-shell-by-shebang () "Choose CPython or JPython mode by looking at #! on the first line.Returns the appropriate mode function.Used by `py-choose-shell', and similar to but distinct from`set-auto-mode', though it uses `auto-mode-interpreter-regexp' (if available)." ;; look for an interpreter specified in the first line ;; similar to set-auto-mode (files.el) (let* ((re (if (boundp 'auto-mode-interpreter-regexp) auto-mode-interpreter-regexp ;; stolen from Emacs 21.2 "#![ \t]?\\([^ \t\n]*/bin/env[ \t]\\)?\\([^ \t\n]+\\)")) (interpreter (save-excursion (goto-char (point-min)) (if (looking-at re) (match-string 2) ""))) elt) ;; Map interpreter name to a mode. (setq elt (assoc (file-name-nondirectory interpreter) py-shell-alist)) (and elt (caddr elt)))) (defun py-choose-shell-by-import () "Choose CPython or JPython mode based imports.If a file imports any packages in `py-jpython-packages', within`py-import-check-point-max' characters from the start of the file,return `jpython', otherwise return nil." (let (mode) (save-excursion (goto-char (point-min)) (while (and (not mode) (search-forward-regexp "^\\(\\(from\\)\\|\\(import\\)\\) \\([^ \t\n.]+\\)" py-import-check-point-max t)) (setq mode (and (member (match-string 4) py-jpython-packages) 'jpython )))) mode)) (defun py-choose-shell () "Choose CPython or JPython mode. Returns the appropriate mode function.This does the following: - look for an interpreter with `py-choose-shell-by-shebang' - examine imports using `py-choose-shell-by-import' - default to the variable `py-default-interpreter'" (interactive) (or (py-choose-shell-by-shebang) (py-choose-shell-by-import) py-default-interpreter; 'cpython ;; don't use to py-default-interpreter, because default; ;; is only way to choose CPython )) ;;;###autoload(defun python-mode () "Major mode for editing Python files.To submit a problem report, enter `\\[py-submit-bug-report]' from a`python-mode' buffer. Do `\\[py-describe-mode]' for detaileddocumentation. To see what version of `python-mode' you are running,enter `\\[py-version]'. This mode knows about Python indentation, tokens, comments andcontinuation lines. Paragraphs are separated by blank lines only. COMMANDS\\{py-mode-map}VARIABLES py-indent-offset\t\tindentation incrementpy-block-comment-prefix\t\tcomment string used by `comment-region'py-python-command\t\tshell command to invoke Python interpreterpy-temp-directory\t\tdirectory used for temp files (if needed)py-beep-if-tab-change\t\tring the bell if `tab-width' is changed" (interactive) ;; set up local variables (kill-all-local-variables) (make-local-variable 'font-lock-defaults) (make-local-variable 'paragraph-separate) (make-local-variable 'paragraph-start) (make-local-variable 'require-final-newline) (make-local-variable 'comment-start) (make-local-variable 'comment-end) (make-local-variable 'comment-start-skip) (make-local-variable 'comment-column) (make-local-variable 'comment-indent-function) (make-local-variable 'indent-region-function) (make-local-variable 'indent-line-function) (make-local-variable 'add-log-current-defun-function) ;; (set-syntax-table py-mode-syntax-table) (setq major-mode 'python-mode mode-name "Python" local-abbrev-table python-mode-abbrev-table font-lock-defaults '(python-font-lock-keywords) paragraph-separate "^[ \t]*$" paragraph-start "^[ \t]*$" require-final-newline t comment-start "# " comment-end "" comment-start-skip "# *" comment-column 40 comment-indent-function 'py-comment-indent-function indent-region-function 'py-indent-region indent-line-function 'py-indent-line ;; tell add-log.el how to find the current function/method/variable add-log-current-defun-function 'py-current-defun ) (use-local-map py-mode-map) ;; add the menu (if py-menu (easy-menu-add py-menu)) ;; Emacs 19 requires this (if (boundp 'comment-multi-line) (setq comment-multi-line nil)) ;; Install Imenu if available (when (py-safe (require 'imenu)) (setq imenu-create-index-function #'py-imenu-create-index-function) (setq imenu-generic-expression py-imenu-generic-expression) (if (fboundp 'imenu-add-to-menubar) (imenu-add-to-menubar (format "%s-%s" "IM" mode-name))) ) ;; Run the mode hook. Note that py-mode-hook is deprecated. (if python-mode-hook (run-hooks 'python-mode-hook) (run-hooks 'py-mode-hook)) ;; Now do the automagical guessing (if py-smart-indentation (let ((offset py-indent-offset)) ;; It's okay if this fails to guess a good value (if (and (py-safe (py-guess-indent-offset)) (<= py-indent-offset 8) (>= py-indent-offset 2)) (setq offset py-indent-offset)) (setq py-indent-offset offset) ;; Only turn indent-tabs-mode off if tab-width != ;; py-indent-offset. Never turn it on, because the user must ;; have explicitly turned it off. (if (/= tab-width py-indent-offset) (setq indent-tabs-mode nil)) )) ;; Set the default shell if not already set (when (null py-which-shell) (py-toggle-shells (py-choose-shell)))) (defun jpython-mode () "Major mode for editing JPython/Jython files.This is a simple wrapper around `python-mode'.It runs `jpython-mode-hook' then calls `python-mode.'It is added to `interpreter-mode-alist' and `py-choose-shell'." (interactive) (python-mode) (py-toggle-shells 'jpython) (when jpython-mode-hook (run-hooks 'jpython-mode-hook))) ;; It's handy to add recognition of Python files to the;; interpreter-mode-alist and to auto-mode-alist. With the former, we;; can specify different `derived-modes' based on the #! line, but;; with the latter, we can't. So we just won't add them if they're;; already added.(let ((modes '(("jpython" . jpython-mode) ("jython" . jpython-mode) ("python" . python-mode)))) (while modes (when (not (assoc (car modes) interpreter-mode-alist)) (push (car modes) interpreter-mode-alist)) (setq modes (cdr modes)))) (when (not (or (rassq 'python-mode auto-mode-alist) (rassq 'jpython-mode auto-mode-alist))) (push '("\\.py$" . python-mode) auto-mode-alist)) ;; electric characters(defun py-outdent-p () "Returns non-nil if the current line should dedent one level." (save-excursion (and (progn (back-to-indentation) (looking-at py-outdent-re)) ;; short circuit infloop on illegal construct (not (bobp)) (progn (forward-line -1) (py-goto-initial-line) (back-to-indentation) (while (or (looking-at py-blank-or-comment-re) (bobp)) (backward-to-indentation 1)) (not (looking-at py-no-outdent-re))) ))) (defun py-electric-colon (arg) "Insert a colon.In certain cases the line is dedented appropriately. If a numericargument ARG is provided, that many colons are insertednon-electrically. Electric behavior is inhibited inside a string orcomment." (interactive "*P") (self-insert-command (prefix-numeric-value arg)) ;; are we in a string or comment? (if (save-excursion (let ((pps (parse-partial-sexp (save-excursion (py-beginning-of-def-or-class) (point)) (point)))) (not (or (nth 3 pps) (nth 4 pps))))) (save-excursion (let ((here (point)) (outdent 0) (indent (py-compute-indentation t))) (if (and (not arg) (py-outdent-p) (= indent (save-excursion (py-next-statement -1) (py-compute-indentation t))) ) (setq outdent py-indent-offset)) ;; Don't indent, only dedent. This assumes that any lines ;; that are already dedented relative to ;; py-compute-indentation were put there on purpose. It's ;; highly annoying to have `:' indent for you. Use TAB, C-c ;; C-l or C-c C-r to adjust. TBD: Is there a better way to ;; determine this??? (if (< (current-indentation) indent) nil (goto-char here) (beginning-of-line) (delete-horizontal-space) (indent-to (- indent outdent)) ))))) ;; Python subprocess utilities and filters(defun py-execute-file (proc filename) "Send to Python interpreter process PROC \"execfile('FILENAME')\".Make that process's buffer visible and force display. Also makecomint believe the user typed this string so that`kill-output-from-shell' does The Right Thing." (let ((curbuf (current-buffer)) (procbuf (process-buffer proc)); (comint-scroll-to-bottom-on-output t) (msg (format "## working on region in file %s...\n" filename)) (cmd (format "execfile(r'%s')\n" filename))) (unwind-protect (save-excursion (set-buffer procbuf) (goto-char (point-max)) (move-marker (process-mark proc) (point)) (funcall (process-filter proc) proc msg)) (set-buffer curbuf)) (process-send-string proc cmd))) (defun py-comint-output-filter-function (string) "Watch output for Python prompt and exec next file waiting in queue.This function is appropriate for `comint-output-filter-functions'." ;; TBD: this should probably use split-string (when (and (or (string-equal string ">>> ") (and (>= (length string) 5) (string-equal (substring string -5) "\n>>> "))) py-file-queue) (pop-to-buffer (current-buffer)) (py-safe (delete-file (car py-file-queue))) (setq py-file-queue (cdr py-file-queue)) (if py-file-queue (let ((pyproc (get-buffer-process (current-buffer)))) (py-execute-file pyproc (car py-file-queue)))) )) (defun py-pdbtrack-overlay-arrow (activation) "Activate or de arrow at beginning-of-line in current buffer." ;; This was derived/simplified from edebug-overlay-arrow (cond (activation (setq overlay-arrow-position (make-marker)) (setq overlay-arrow-string "=>") (set-marker overlay-arrow-position (py-point 'bol) (current-buffer)) (setq py-pdbtrack-is-tracking-p t)) (overlay-arrow-position (setq overlay-arrow-position nil) (setq py-pdbtrack-is-tracking-p nil)) )) (defun py-pdbtrack-track-stack-file (text) "Show the file indicated by the pdb stack entry line, in a separate window. Activity is disabled if the buffer-local variable`py-pdbtrack-do-tracking-p' is nil. We depend on the pdb input prompt matching `py-pdbtrack-input-prompt'at the beginning of the line. If the traceback target file path is invalid, we look for the mostrecently visited python-mode buffer which either has the name of thecurrent function \(or class) or which defines the function \(orclass). This is to provide for remote scripts, eg, Zope's 'Script(Python)' - put a _copy_ of the script in a buffer named for thescript, and set to python-mode, and pdbtrack will find it.)" ;; Instead of trying to piece things together from partial text ;; (which can be almost useless depending on Emacs version), we ;; monitor to the point where we have the next pdb prompt, and then ;; check all text from comint-last-input-end to process-mark. ;; ;; Also, we're very conservative about clearing the overlay arrow, ;; to minimize residue. This means, for instance, that executing ;; other pdb commands wipe out the highlight. You can always do a ;; 'where' (aka 'w') command to reveal the overlay arrow. (let* ((origbuf (current-buffer)) (currproc (get-buffer-process origbuf))) (if (not (and currproc py-pdbtrack-do-tracking-p)) (py-pdbtrack-overlay-arrow nil) (let* ((procmark (process-mark currproc)) (block (buffer-substring (max comint-last-input-end (- procmark py-pdbtrack-track-range)) procmark)) target target_fname target_lineno) (if (not (string-match (concat py-pdbtrack-input-prompt "$") block)) (py-pdbtrack-overlay-arrow nil) (setq target (py-pdbtrack-get-source-buffer block)) (if (stringp target) (message "pdbtrack: %s" target) (setq target_lineno (car target)) (setq target_buffer (cadr target)) (setq target_fname (buffer-file-name target_buffer)) (switch-to-buffer-other-window target_buffer) (goto-line target_lineno) (message "pdbtrack: line %s, file %s" target_lineno target_fname) (py-pdbtrack-overlay-arrow t) (pop-to-buffer origbuf t) ))))) ) (defun py-pdbtrack-get-source-buffer (block) "Return line number and buffer of code indicated by block's traceback text. We look first to visit the file indicated in the trace. Failing that, we look for the most recently visited python-mode bufferwith the same name or having having the named function. If we're unable find the source code we return a string describing theproblem as best as we can determine." (if (not (string-match py-pdbtrack-stack-entry-regexp block)) "Traceback cue not found" (let* ((filename (match-string 1 block)) (lineno (string-to-int (match-string 2 block))) (funcname (match-string 3 block)) funcbuffer) (cond ((file-exists-p filename) (list lineno (find-file-noselect filename))) ((setq funcbuffer (py-pdbtrack-grub-for-buffer funcname lineno)) (if (string-match "/Script (Python)$" filename) ;; Add in number of lines for leading '##' comments: (setq lineno (+ lineno (save-excursion (set-buffer funcbuffer) (count-lines (point-min) (max (point-min) (string-match "^\\([^#]\\|#[^#]\\|#$\\)" (buffer-substring (point-min) (point-max))) )))))) (list lineno funcbuffer)) ((= (elt filename 0) ?\<) (format "(Non-file source: '%s')" filename)) (t (format "Not found: %s(), %s" funcname filename))) ) ) ) (defun py-pdbtrack-grub-for-buffer (funcname lineno) "Find most recent buffer itself named or having function funcname. We first check the last buffer this function found, if any, then walkthrought the buffer-list history for python-mode buffers that arenamed for funcname or define a function funcname." (let ((buffers (buffer-list)) curbuf got) (while (and buffers (not got)) (setq buf (car buffers) buffers (cdr buffers)) (if (and (save-excursion (set-buffer buf) (string= major-mode "python-mode")) (or (string-match funcname (buffer-name buf)) (string-match (concat "^\\s-*\\(def\\|class\\)\\s-+" funcname "\\s-*(") (save-excursion (set-buffer buf) (buffer-substring (point-min) (point-max)))))) (setq got buf))) (setq py-pdbtrack-last-grubbed-buffer got))) (defun py-postprocess-output-buffer (buf) "Highlight exceptions found in BUF.If an exception occurred return t, otherwise return nil. BUF must exist." (let (line file bol err-p) (save-excursion (set-buffer buf) (beginning-of-buffer) (while (re-search-forward py-traceback-line-re nil t) (setq file (match-string 1) line (string-to-int (match-string 2)) bol (py-point 'bol)) (py-highlight-line bol (py-point 'eol) file line))) (when (and py-jump-on-exception line) (beep) (py-jump-to-exception file line) (setq err-p t)) err-p)) ;;; Subprocess commands ;; only used when (memq 'broken-temp-names py-emacs-features)(defvar py-serial-number 0)(defvar py-exception-buffer nil)(defconst py-output-buffer "*Python Output*")(make-variable-buffer-local 'py-output-buffer) ;; for toggling between CPython and JPython(defvar py-which-shell nil)(defvar py-which-args py-python-command-args)(defvar py-which-bufname "Python")(make-variable-buffer-local 'py-which-shell)(make-variable-buffer-local 'py-which-args)(make-variable-buffer-local 'py-which-bufname) (defun py-toggle-shells (arg) "Toggles between the CPython and JPython shells. With positive argument ARG (interactively \\[universal-argument]),uses the CPython shell, with negative ARG uses the JPython shell, andwith a zero argument, toggles the shell. Programmatically, ARG can also be one of the symbols `cpython' or`jpython', equivalent to positive arg and negative arg respectively." (interactive "P") ;; default is to toggle (if (null arg) (setq arg 0)) ;; preprocess arg (cond ((equal arg 0) ;; toggle (if (string-equal py-which-bufname "Python") (setq arg -1) (setq arg 1))) ((equal arg 'cpython) (setq arg 1)) ((equal arg 'jpython) (setq arg -1)))Lines 1001–1500 of 3768. Previous lines Load more
;; start on, so go back to the last expression. The recursive ;; call will find this place again and add it to the correct ;; list (re-search-backward py-imenu-generic-regexp (point-min) 'move) (setq sub-method-alist (py-imenu-create-index-engine cur-indent)) (if sub-method-alist ;; we put the last element on the index-alist on the start ;; of the submethod alist so the user can still get to it. (let ((save-elmt (pop index-alist))) (push (cons prev-name (cons save-elmt sub-method-alist)) index-alist)))) ;; found less indented expression, we're done. (t (setq looking-p nil) (re-search-backward py-imenu-generic-regexp (point-min) t))) ;; end-cond (setq prev-name def-name) (and looking-p (setq looking-p (re-search-forward py-imenu-generic-regexp (point-max) 'move)))) (nreverse index-alist))) (defun py-choose-shell-by-shebang () "Choose CPython or JPython mode by looking at #! on the first line. Returns the appropriate mode function. Used by `py-choose-shell', and similar to but distinct from `set-auto-mode', though it uses `auto-mode-interpreter-regexp' (if available)." ;; look for an interpreter specified in the first line ;; similar to set-auto-mode (files.el) (let* ((re (if (boundp 'auto-mode-interpreter-regexp) auto-mode-interpreter-regexp ;; stolen from Emacs 21.2 "#![ \t]?\\([^ \t\n]*/bin/env[ \t]\\)?\\([^ \t\n]+\\)")) (interpreter (save-excursion (goto-char (point-min)) (if (looking-at re) (match-string 2) ""))) elt) ;; Map interpreter name to a mode. (setq elt (assoc (file-name-nondirectory interpreter) py-shell-alist)) (and elt (caddr elt)))) (defun py-choose-shell-by-import () "Choose CPython or JPython mode based imports. If a file imports any packages in `py-jpython-packages', within `py-import-check-point-max' characters from the start of the file, return `jpython', otherwise return nil." (let (mode) (save-excursion (goto-char (point-min)) (while (and (not mode) (search-forward-regexp "^\\(\\(from\\)\\|\\(import\\)\\) \\([^ \t\n.]+\\)" py-import-check-point-max t)) (setq mode (and (member (match-string 4) py-jpython-packages) 'jpython )))) mode)) (defun py-choose-shell () "Choose CPython or JPython mode. Returns the appropriate mode function. This does the following: - look for an interpreter with `py-choose-shell-by-shebang' - examine imports using `py-choose-shell-by-import' - default to the variable `py-default-interpreter'" (interactive) (or (py-choose-shell-by-shebang) (py-choose-shell-by-import) py-default-interpreter ; 'cpython ;; don't use to py-default-interpreter, because default ; ;; is only way to choose CPython )) ;;;###autoload (defun python-mode () "Major mode for editing Python files. To submit a problem report, enter `\\[py-submit-bug-report]' from a `python-mode' buffer. Do `\\[py-describe-mode]' for detailed documentation. To see what version of `python-mode' you are running, enter `\\[py-version]'. This mode knows about Python indentation, tokens, comments and continuation lines. Paragraphs are separated by blank lines only. COMMANDS \\{py-mode-map} VARIABLES py-indent-offset\t\tindentation increment py-block-comment-prefix\t\tcomment string used by `comment-region' py-python-command\t\tshell command to invoke Python interpreter py-temp-directory\t\tdirectory used for temp files (if needed) py-beep-if-tab-change\t\tring the bell if `tab-width' is changed" (interactive) ;; set up local variables (kill-all-local-variables) (make-local-variable 'font-lock-defaults) (make-local-variable 'paragraph-separate) (make-local-variable 'paragraph-start) (make-local-variable 'require-final-newline) (make-local-variable 'comment-start) (make-local-variable 'comment-end) (make-local-variable 'comment-start-skip) (make-local-variable 'comment-column) (make-local-variable 'comment-indent-function) (make-local-variable 'indent-region-function) (make-local-variable 'indent-line-function) (make-local-variable 'add-log-current-defun-function) ;; (set-syntax-table py-mode-syntax-table) (setq major-mode 'python-mode mode-name "Python" local-abbrev-table python-mode-abbrev-table font-lock-defaults '(python-font-lock-keywords) paragraph-separate "^[ \t]*$" paragraph-start "^[ \t]*$" require-final-newline t comment-start "# " comment-end "" comment-start-skip "# *" comment-column 40 comment-indent-function 'py-comment-indent-function indent-region-function 'py-indent-region indent-line-function 'py-indent-line ;; tell add-log.el how to find the current function/method/variable add-log-current-defun-function 'py-current-defun ) (use-local-map py-mode-map) ;; add the menu (if py-menu (easy-menu-add py-menu)) ;; Emacs 19 requires this (if (boundp 'comment-multi-line) (setq comment-multi-line nil)) ;; Install Imenu if available (when (py-safe (require 'imenu)) (setq imenu-create-index-function #'py-imenu-create-index-function) (setq imenu-generic-expression py-imenu-generic-expression) (if (fboundp 'imenu-add-to-menubar) (imenu-add-to-menubar (format "%s-%s" "IM" mode-name))) ) ;; Run the mode hook. Note that py-mode-hook is deprecated. (if python-mode-hook (run-hooks 'python-mode-hook) (run-hooks 'py-mode-hook)) ;; Now do the automagical guessing (if py-smart-indentation (let ((offset py-indent-offset)) ;; It's okay if this fails to guess a good value (if (and (py-safe (py-guess-indent-offset)) (<= py-indent-offset 8) (>= py-indent-offset 2)) (setq offset py-indent-offset)) (setq py-indent-offset offset) ;; Only turn indent-tabs-mode off if tab-width != ;; py-indent-offset. Never turn it on, because the user must ;; have explicitly turned it off. (if (/= tab-width py-indent-offset) (setq indent-tabs-mode nil)) )) ;; Set the default shell if not already set (when (null py-which-shell) (py-toggle-shells (py-choose-shell)))) (defun jpython-mode () "Major mode for editing JPython/Jython files. This is a simple wrapper around `python-mode'. It runs `jpython-mode-hook' then calls `python-mode.' It is added to `interpreter-mode-alist' and `py-choose-shell'. " (interactive) (python-mode) (py-toggle-shells 'jpython) (when jpython-mode-hook (run-hooks 'jpython-mode-hook))) ;; It's handy to add recognition of Python files to the ;; interpreter-mode-alist and to auto-mode-alist. With the former, we ;; can specify different `derived-modes' based on the #! line, but ;; with the latter, we can't. So we just won't add them if they're ;; already added. (let ((modes '(("jpython" . jpython-mode) ("jython" . jpython-mode) ("python" . python-mode)))) (while modes (when (not (assoc (car modes) interpreter-mode-alist)) (push (car modes) interpreter-mode-alist)) (setq modes (cdr modes)))) (when (not (or (rassq 'python-mode auto-mode-alist) (rassq 'jpython-mode auto-mode-alist))) (push '("\\.py$" . python-mode) auto-mode-alist)) ;; electric characters (defun py-outdent-p () "Returns non-nil if the current line should dedent one level." (save-excursion (and (progn (back-to-indentation) (looking-at py-outdent-re)) ;; short circuit infloop on illegal construct (not (bobp)) (progn (forward-line -1) (py-goto-initial-line) (back-to-indentation) (while (or (looking-at py-blank-or-comment-re) (bobp)) (backward-to-indentation 1)) (not (looking-at py-no-outdent-re))) ))) (defun py-electric-colon (arg) "Insert a colon. In certain cases the line is dedented appropriately. If a numeric argument ARG is provided, that many colons are inserted non-electrically. Electric behavior is inhibited inside a string or comment." (interactive "*P") (self-insert-command (prefix-numeric-value arg)) ;; are we in a string or comment? (if (save-excursion (let ((pps (parse-partial-sexp (save-excursion (py-beginning-of-def-or-class) (point)) (point)))) (not (or (nth 3 pps) (nth 4 pps))))) (save-excursion (let ((here (point)) (outdent 0) (indent (py-compute-indentation t))) (if (and (not arg) (py-outdent-p) (= indent (save-excursion (py-next-statement -1) (py-compute-indentation t))) ) (setq outdent py-indent-offset)) ;; Don't indent, only dedent. This assumes that any lines ;; that are already dedented relative to ;; py-compute-indentation were put there on purpose. It's ;; highly annoying to have `:' indent for you. Use TAB, C-c ;; C-l or C-c C-r to adjust. TBD: Is there a better way to ;; determine this??? (if (< (current-indentation) indent) nil (goto-char here) (beginning-of-line) (delete-horizontal-space) (indent-to (- indent outdent)) ))))) ;; Python subprocess utilities and filters (defun py-execute-file (proc filename) "Send to Python interpreter process PROC \"execfile('FILENAME')\". Make that process's buffer visible and force display. Also make comint believe the user typed this string so that `kill-output-from-shell' does The Right Thing." (let ((curbuf (current-buffer)) (procbuf (process-buffer proc)) ; (comint-scroll-to-bottom-on-output t) (msg (format "## working on region in file %s...\n" filename)) (cmd (format "execfile(r'%s')\n" filename))) (unwind-protect (save-excursion (set-buffer procbuf) (goto-char (point-max)) (move-marker (process-mark proc) (point)) (funcall (process-filter proc) proc msg)) (set-buffer curbuf)) (process-send-string proc cmd))) (defun py-comint-output-filter-function (string) "Watch output for Python prompt and exec next file waiting in queue. This function is appropriate for `comint-output-filter-functions'." ;; TBD: this should probably use split-string (when (and (or (string-equal string ">>> ") (and (>= (length string) 5) (string-equal (substring string -5) "\n>>> "))) py-file-queue) (pop-to-buffer (current-buffer)) (py-safe (delete-file (car py-file-queue))) (setq py-file-queue (cdr py-file-queue)) (if py-file-queue (let ((pyproc (get-buffer-process (current-buffer)))) (py-execute-file pyproc (car py-file-queue)))) )) (defun py-pdbtrack-overlay-arrow (activation) "Activate or de arrow at beginning-of-line in current buffer." ;; This was derived/simplified from edebug-overlay-arrow (cond (activation (setq overlay-arrow-position (make-marker)) (setq overlay-arrow-string "=>") (set-marker overlay-arrow-position (py-point 'bol) (current-buffer)) (setq py-pdbtrack-is-tracking-p t)) (overlay-arrow-position (setq overlay-arrow-position nil) (setq py-pdbtrack-is-tracking-p nil)) )) (defun py-pdbtrack-track-stack-file (text) "Show the file indicated by the pdb stack entry line, in a separate window. Activity is disabled if the buffer-local variable `py-pdbtrack-do-tracking-p' is nil. We depend on the pdb input prompt matching `py-pdbtrack-input-prompt' at the beginning of the line. If the traceback target file path is invalid, we look for the most recently visited python-mode buffer which either has the name of the current function \(or class) or which defines the function \(or class). This is to provide for remote scripts, eg, Zope's 'Script (Python)' - put a _copy_ of the script in a buffer named for the script, and set to python-mode, and pdbtrack will find it.)" ;; Instead of trying to piece things together from partial text ;; (which can be almost useless depending on Emacs version), we ;; monitor to the point where we have the next pdb prompt, and then ;; check all text from comint-last-input-end to process-mark. ;; ;; Also, we're very conservative about clearing the overlay arrow, ;; to minimize residue. This means, for instance, that executing ;; other pdb commands wipe out the highlight. You can always do a ;; 'where' (aka 'w') command to reveal the overlay arrow. (let* ((origbuf (current-buffer)) (currproc (get-buffer-process origbuf))) (if (not (and currproc py-pdbtrack-do-tracking-p)) (py-pdbtrack-overlay-arrow nil) (let* ((procmark (process-mark currproc)) (block (buffer-substring (max comint-last-input-end (- procmark py-pdbtrack-track-range)) procmark)) target target_fname target_lineno) (if (not (string-match (concat py-pdbtrack-input-prompt "$") block)) (py-pdbtrack-overlay-arrow nil) (setq target (py-pdbtrack-get-source-buffer block)) (if (stringp target) (message "pdbtrack: %s" target) (setq target_lineno (car target)) (setq target_buffer (cadr target)) (setq target_fname (buffer-file-name target_buffer)) (switch-to-buffer-other-window target_buffer) (goto-line target_lineno) (message "pdbtrack: line %s, file %s" target_lineno target_fname) (py-pdbtrack-overlay-arrow t) (pop-to-buffer origbuf t) ))))) ) (defun py-pdbtrack-get-source-buffer (block) "Return line number and buffer of code indicated by block's traceback text. We look first to visit the file indicated in the trace. Failing that, we look for the most recently visited python-mode buffer with the same name or having having the named function. If we're unable find the source code we return a string describing the problem as best as we can determine." (if (not (string-match py-pdbtrack-stack-entry-regexp block)) "Traceback cue not found" (let* ((filename (match-string 1 block)) (lineno (string-to-int (match-string 2 block))) (funcname (match-string 3 block)) funcbuffer) (cond ((file-exists-p filename) (list lineno (find-file-noselect filename))) ((setq funcbuffer (py-pdbtrack-grub-for-buffer funcname lineno)) (if (string-match "/Script (Python)$" filename) ;; Add in number of lines for leading '##' comments: (setq lineno (+ lineno (save-excursion (set-buffer funcbuffer) (count-lines (point-min) (max (point-min) (string-match "^\\([^#]\\|#[^#]\\|#$\\)" (buffer-substring (point-min) (point-max))) )))))) (list lineno funcbuffer)) ((= (elt filename 0) ?\<) (format "(Non-file source: '%s')" filename)) (t (format "Not found: %s(), %s" funcname filename))) ) ) ) (defun py-pdbtrack-grub-for-buffer (funcname lineno) "Find most recent buffer itself named or having function funcname. We first check the last buffer this function found, if any, then walk throught the buffer-list history for python-mode buffers that are named for funcname or define a function funcname." (let ((buffers (buffer-list)) curbuf got) (while (and buffers (not got)) (setq buf (car buffers) buffers (cdr buffers)) (if (and (save-excursion (set-buffer buf) (string= major-mode "python-mode")) (or (string-match funcname (buffer-name buf)) (string-match (concat "^\\s-*\\(def\\|class\\)\\s-+" funcname "\\s-*(") (save-excursion (set-buffer buf) (buffer-substring (point-min) (point-max)))))) (setq got buf))) (setq py-pdbtrack-last-grubbed-buffer got))) (defun py-postprocess-output-buffer (buf) "Highlight exceptions found in BUF. If an exception occurred return t, otherwise return nil. BUF must exist." (let (line file bol err-p) (save-excursion (set-buffer buf) (beginning-of-buffer) (while (re-search-forward py-traceback-line-re nil t) (setq file (match-string 1) line (string-to-int (match-string 2)) bol (py-point 'bol)) (py-highlight-line bol (py-point 'eol) file line))) (when (and py-jump-on-exception line) (beep) (py-jump-to-exception file line) (setq err-p t)) err-p)) ;;; Subprocess commands ;; only used when (memq 'broken-temp-names py-emacs-features) (defvar py-serial-number 0) (defvar py-exception-buffer nil) (defconst py-output-buffer "*Python Output*") (make-variable-buffer-local 'py-output-buffer) ;; for toggling between CPython and JPython (defvar py-which-shell nil) (defvar py-which-args py-python-command-args) (defvar py-which-bufname "Python") (make-variable-buffer-local 'py-which-shell) (make-variable-buffer-local 'py-which-args) (make-variable-buffer-local 'py-which-bufname) (defun py-toggle-shells (arg) "Toggles between the CPython and JPython shells. With positive argument ARG (interactively \\[universal-argument]), uses the CPython shell, with negative ARG uses the JPython shell, and with a zero argument, toggles the shell. Programmatically, ARG can also be one of the symbols `cpython' or `jpython', equivalent to positive arg and negative arg respectively." (interactive "P") ;; default is to toggle (if (null arg) (setq arg 0)) ;; preprocess arg (cond ((equal arg 0) ;; toggle (if (string-equal py-which-bufname "Python") (setq arg -1) (setq arg 1))) ((equal arg 'cpython) (setq arg 1)) ((equal arg 'jpython) (setq arg -1)))