From ad75644970a5deccb1d40465e20087f5806ed3df Mon Sep 17 00:00:00 2001 From: Fabián Ezequiel Gallina Date: Tue, 13 Aug 2013 13:36:32 -0300 Subject: * lisp/progmodes/python.el (python-imenu--build-tree) (python-imenu--put-parent): Simplify and Fix (GH bug 146). * test/automated/python-tests.el (python-imenu-create-index-4) (python-imenu-create-flat-index-2): New tests. --- lisp/progmodes/python.el | 114 +++++++++++++---------------------------------- 1 file changed, 32 insertions(+), 82 deletions(-) (limited to 'lisp/progmodes/python.el') diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 62870f9085b..70c2e5dec53 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -3042,32 +3042,22 @@ It must be a function with two arguments: TYPE and NAME.") "*class definition*" "*function definition*")) -(defun python-imenu--put-parent (type name pos num-children tree &optional root) - "Add the parent with TYPE, NAME, POS and NUM-CHILDREN to TREE. -Optional Argument ROOT must be non-nil when the node being -processed is the root of the TREE." +(defun python-imenu--put-parent (type name pos tree) + "Add the parent with TYPE, NAME and POS to TREE." (let ((label (funcall python-imenu-format-item-label-function type name)) (jump-label (funcall python-imenu-format-parent-item-jump-label-function type name))) - (if root - ;; This is the root, everything is a children. - (cons label (cons (cons jump-label pos) tree)) - ;; This is node a which may contain some children. - (cons - (cons label (cons (cons jump-label pos) - ;; Append all the children - (python-util-popn tree num-children))) - ;; All previous non-children nodes. - (nthcdr num-children tree))))) + (if (not tree) + (cons label pos) + (cons label (cons (cons jump-label pos) tree))))) -(defun python-imenu--build-tree (&optional min-indent prev-indent num-children tree) +(defun python-imenu--build-tree (&optional min-indent prev-indent tree) "Recursively build the tree of nested definitions of a node. -Arguments MIN-INDENT PREV-INDENT NUM-CHILDREN and TREE are -internal and should not be passed explicitly unless you know what -you are doing." - (setq num-children (or num-children 0) - min-indent (or min-indent 0)) +Arguments MIN-INDENT PREV-INDENT and TREE are internal and should +not be passed explicitly unless you know what you are doing." + (setq min-indent (or min-indent 0) + prev-indent (or prev-indent python-indent-offset)) (let* ((pos (python-nav-backward-defun)) (type) (name (when (and pos (looking-at python-nav-beginning-of-defun-regexp)) @@ -3076,73 +3066,33 @@ you are doing." (cadr split)))) (label (when name (funcall python-imenu-format-item-label-function type name))) - (indent (current-indentation))) + (indent (current-indentation)) + (children-indent-limit (+ python-indent-offset min-indent))) (cond ((not pos) - ;; No defun found, nothing to add. - tree) - ((equal indent 0) - (if (> num-children 0) - ;; Append it as the parent of everything collected to - ;; this point. - (python-imenu--put-parent type name pos num-children tree t) - ;; There are no children, this is a lonely defun. - (cons label pos))) - ((equal min-indent indent) - ;; Stop collecting nodes after moving to a position with - ;; indentation equaling min-indent. This is specially - ;; useful for navigating nested definitions recursively. - (if (> num-children 0) - tree - ;; When there are no children, the collected tree is a - ;; single node intended to be added in the list of defuns - ;; of its parent. - (car tree))) + ;; Nothing found, probably near to bobp. + nil) + ((<= indent min-indent) + ;; The current indentation points that this is a parent + ;; node, add it to the tree and stop recursing. + (python-imenu--put-parent type name pos tree)) (t (python-imenu--build-tree min-indent indent - ;; Add another children, either when this is the - ;; first call or when indentation is - ;; less-or-equal than previous. And do not - ;; discard the number of children, because the - ;; way code is scanned, all children are - ;; collected until a root node yet to be found - ;; appears. - (if (or (not prev-indent) - (and - (> indent min-indent) - (<= indent prev-indent))) - (1+ num-children) - num-children) - (cond ((not prev-indent) - ;; First call to the function: append this - ;; defun to the index. - (list (cons label pos))) - ((= indent prev-indent) - ;; Add another defun with the same depth - ;; as the previous. - (cons (cons label pos) tree)) - ((and (< indent prev-indent) - (< 0 num-children)) - ;; There are children to be appended and - ;; the previous defun had more - ;; indentation, the current one must be a - ;; parent. - (python-imenu--put-parent type name pos num-children tree)) - ((> indent prev-indent) - ;; There are children defuns deeper than - ;; current depth. Fear not, we already - ;; know how to treat them. - (cons - (prog1 - (python-imenu--build-tree - prev-indent indent 0 (list (cons label pos))) - ;; Adjustment: after scanning backwards - ;; for all deeper children, we need to - ;; continue our scan for a parent from - ;; the current defun we are looking at. - (python-nav-forward-defun)) - tree)))))))) + (if (<= indent children-indent-limit) + ;; This lays within the children indent offset range, + ;; so it's a normal children of its parent (i.e., not + ;; a children of a children). + (cons (cons label pos) tree) + ;; Oh noes, a children of a children?!. Fear not, we + ;; know how to roll. We recursely parse these by + ;; swapping prev-indent and min-indent plus adding this + ;; newly found item to a fresh subtree. This works, I + ;; promise. + (cons + (python-imenu--build-tree + prev-indent indent (list (cons label pos))) + tree))))))) (defun python-imenu-create-index () "Return tree Imenu alist for the current python buffer. -- cgit v1.2.1 From 526e5233cc0e2375798bdc79329a893302fdfb4b Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 15 Aug 2013 22:15:51 -0700 Subject: Spelling fixes. --- lisp/progmodes/python.el | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'lisp/progmodes/python.el') diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 70c2e5dec53..01833ffd70b 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -3080,14 +3080,14 @@ not be passed explicitly unless you know what you are doing." min-indent indent (if (<= indent children-indent-limit) - ;; This lays within the children indent offset range, - ;; so it's a normal children of its parent (i.e., not - ;; a children of a children). + ;; This lies within the children indent offset range, + ;; so it's a normal child of its parent (i.e., not + ;; a child of a child). (cons (cons label pos) tree) - ;; Oh noes, a children of a children?!. Fear not, we - ;; know how to roll. We recursely parse these by + ;; Oh no, a child of a child?! Fear not, we + ;; know how to roll. We recursively parse these by ;; swapping prev-indent and min-indent plus adding this - ;; newly found item to a fresh subtree. This works, I + ;; newly found item to a fresh subtree. This works, I ;; promise. (cons (python-imenu--build-tree -- cgit v1.2.1 From 9e89d835b04c20a8cd3dfad452fa827d675b0938 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 26 Aug 2013 22:41:41 -0400 Subject: * lisp/progmodes/python.el (python-font-lock-keywords): Don't return nil from a matcher-function unless there's no more matches. Fixes: debbugs:15161 --- lisp/progmodes/python.el | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) (limited to 'lisp/progmodes/python.el') diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 01833ffd70b..7004836e69f 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -501,29 +501,24 @@ The type returned can be `comment', `string' or `paren'." (,(lambda (limit) (let ((re (python-rx (group (+ (any word ?. ?_))) (? ?\[ (+ (not (any ?\]))) ?\]) (* space) - assignment-operator))) - (when (re-search-forward re limit t) - (while (and (python-syntax-context 'paren) - (re-search-forward re limit t))) - (if (not (or (python-syntax-context 'paren) - (equal (char-after (point-marker)) ?=))) - t - (set-match-data nil))))) + assignment-operator)) + (res nil)) + (while (and (setq res (re-search-forward re limit t)) + (or (python-syntax-context 'paren) + (equal (char-after (point-marker)) ?=)))) + res)) (1 font-lock-variable-name-face nil nil)) ;; support for a, b, c = (1, 2, 3) (,(lambda (limit) (let ((re (python-rx (group (+ (any word ?. ?_))) (* space) (* ?, (* space) (+ (any word ?. ?_)) (* space)) ?, (* space) (+ (any word ?. ?_)) (* space) - assignment-operator))) - (when (and (re-search-forward re limit t) - (goto-char (nth 3 (match-data)))) - (while (and (python-syntax-context 'paren) - (re-search-forward re limit t)) - (goto-char (nth 3 (match-data)))) - (if (not (python-syntax-context 'paren)) - t - (set-match-data nil))))) + assignment-operator)) + (res nil)) + (while (and (setq res (re-search-forward re limit t)) + (goto-char (match-end 1)) + (python-syntax-context 'paren))) + res)) (1 font-lock-variable-name-face nil nil)))) (defconst python-syntax-propertize-function -- cgit v1.2.1 From cd16c5f1f5db8cfc6895288889fd9f5b376bfc41 Mon Sep 17 00:00:00 2001 From: Fabián Ezequiel Gallina Date: Mon, 2 Sep 2013 00:21:13 -0300 Subject: * progmodes/python.el (python-shell-completion-get-completions): Drop use of deleted `comint-last-prompt-overlay'. --- lisp/progmodes/python.el | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'lisp/progmodes/python.el') diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 7004836e69f..b8e2f4c8de9 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -2266,13 +2266,17 @@ and use the following as the value of this variable: LINE is used to detect the context on how to complete given INPUT." (let* ((prompt - ;; Get the last prompt for the inferior process - ;; buffer. This is used for the completion code selection - ;; heuristic. + ;; Get last prompt of the inferior process buffer (this + ;; intentionally avoids using `comint-last-prompt' because + ;; of incompatibilities with Emacs 24.x). (with-current-buffer (process-buffer process) - (buffer-substring-no-properties - (overlay-start comint-last-prompt-overlay) - (overlay-end comint-last-prompt-overlay)))) + (save-excursion + (buffer-substring-no-properties + (- (point) (length line)) + (progn + (re-search-backward "^") + (python-util-forward-comment) + (point)))))) (completion-context ;; Check whether a prompt matches a pdb string, an import ;; statement or just the standard prompt and use the -- cgit v1.2.1 From e5c144d64de3f87d2f8d264960e24f65aeb67857 Mon Sep 17 00:00:00 2001 From: Fabián Ezequiel Gallina Date: Mon, 2 Sep 2013 00:37:18 -0300 Subject: * progmodes/python.el (python-nav-if-name-main): New command. --- lisp/progmodes/python.el | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'lisp/progmodes/python.el') diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index b8e2f4c8de9..af55854bbc4 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -52,12 +52,12 @@ ;; Extra functions `python-nav-forward-statement', ;; `python-nav-backward-statement', ;; `python-nav-beginning-of-statement', `python-nav-end-of-statement', -;; `python-nav-beginning-of-block' and `python-nav-end-of-block' are -;; included but no bound to any key. At last but not least the -;; specialized `python-nav-forward-sexp' allows easy navigation -;; between code blocks. If you prefer `cc-mode'-like `forward-sexp' -;; movement, setting `forward-sexp-function' to nil is enough, You can -;; do that using the `python-mode-hook': +;; `python-nav-beginning-of-block', `python-nav-end-of-block' and +;; `python-nav-if-name-main' are included but no bound to any key. At +;; last but not least the specialized `python-nav-forward-sexp' allows +;; easy navigation between code blocks. If you prefer `cc-mode'-like +;; `forward-sexp' movement, setting `forward-sexp-function' to nil is +;; enough, You can do that using the `python-mode-hook': ;; (add-hook 'python-mode-hook ;; (lambda () (setq forward-sexp-function nil))) @@ -1583,6 +1583,29 @@ This command assumes point is not in a string or comment." (or arg (setq arg 1)) (python-nav-up-list (- arg))) +(defun python-nav-if-name-main () + "Move point at the beginning the __main__ block. +When \"if __name__ == '__main__':\" is found returns its +position, else returns nil." + (interactive) + (let ((point (point)) + (found (catch 'found + (goto-char (point-min)) + (while (re-search-forward + (python-rx line-start + "if" (+ space) + "__name__" (+ space) + "==" (+ space) + (group-n 1 (or ?\" ?\')) + "__main__" (backref 1) (* space) ":") + nil t) + (when (not (python-syntax-context-type)) + (beginning-of-line) + (throw 'found t)))))) + (if found + (point) + (ignore (goto-char point))))) + ;;; Shell integration -- cgit v1.2.1 From 96edb677815a79f2952d49959a0d4a8be6da08d6 Mon Sep 17 00:00:00 2001 From: Fabián Ezequiel Gallina Date: Mon, 2 Sep 2013 10:56:03 -0300 Subject: Format code sent to Python shell for robustness. * progmodes/python.el (python-shell-buffer-substring): New function. (python-shell-send-region, python-shell-send-buffer): Use it. --- lisp/progmodes/python.el | 65 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 14 deletions(-) (limited to 'lisp/progmodes/python.el') diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index af55854bbc4..fb2dc01c9be 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -2137,17 +2137,58 @@ Returns the output. See `python-shell-send-string-no-output'." (define-obsolete-function-alias 'python-send-string 'python-shell-internal-send-string "24.3") +(defun python-shell-buffer-substring (start end &optional nomain) + "Send buffer substring from START to END formatted for shell. +This is a wrapper over `buffer-substring' that takes care of +different transformations for the code sent to be evaluated in +the python shell: + 1. When Optional Argument NOMAIN is non-nil everything under an + \"if __name__ == '__main__'\" block will be removed. + 2. When a subregion of the buffer is sent, it takes care of + appending extra whitelines so tracebacks are correct. + 3. Wraps indented regions under an \"if True:\" block so the + interpreter evaluates them correctly." + (let ((substring (buffer-substring-no-properties start end)) + (fillstr (make-string (1- (line-number-at-pos start)) ?\n)) + (toplevel-block-p (save-excursion + (goto-char start) + (or (zerop (line-number-at-pos start)) + (progn + (python-util-forward-comment 1) + (zerop (current-indentation))))))) + (with-temp-buffer + (python-mode) + (insert fillstr) + (insert substring) + (goto-char (point-min)) + (when (not toplevel-block-p) + (insert "if True:") + (delete-region (point) (line-end-position))) + (when nomain + (let* ((if-name-main-start-end + (and nomain + (save-excursion + (when (python-nav-if-name-main) + (cons (point) + (progn (python-nav-forward-sexp) + (point))))))) + ;; Oh destructuring bind, how I miss you. + (if-name-main-start (car if-name-main-start-end)) + (if-name-main-end (cdr if-name-main-start-end))) + (when if-name-main-start-end + (goto-char if-name-main-start) + (delete-region if-name-main-start if-name-main-end) + (insert + (make-string + (- (line-number-at-pos if-name-main-end) + (line-number-at-pos if-name-main-start)) ?\n))))) + (buffer-substring-no-properties (point-min) (point-max))))) + (defun python-shell-send-region (start end) "Send the region delimited by START and END to inferior Python process." (interactive "r") (python-shell-send-string - (concat - (let ((line-num (line-number-at-pos start))) - ;; When sending a region, add blank lines for non sent code so - ;; backtraces remain correct. - (make-string (1- line-num) ?\n)) - (buffer-substring start end)) - nil t)) + (python-shell-buffer-substring start end) nil t)) (defun python-shell-send-buffer (&optional arg) "Send the entire buffer to inferior Python process. @@ -2156,13 +2197,9 @@ by \"if __name__== '__main__':\"" (interactive "P") (save-restriction (widen) - (let ((str (buffer-substring (point-min) (point-max)))) - (and - (not arg) - (setq str (replace-regexp-in-string - (python-rx if-name-main) - "if __name__ == '__main__ ':" str))) - (python-shell-send-string str)))) + (python-shell-send-string + (python-shell-buffer-substring + (point-min) (point-max) (not arg))))) (defun python-shell-send-defun (arg) "Send the current defun to inferior Python process. -- cgit v1.2.1