aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/python.el
diff options
context:
space:
mode:
authorTom Tromey2013-06-03 12:25:05 -0600
committerTom Tromey2013-06-03 12:25:05 -0600
commit68359abba96d7ec4db8aab3d3dd9cf1105c3bab5 (patch)
tree862703e7e1a1888170136a8296a5750d6b2ae2eb /lisp/progmodes/python.el
parentcbcba8ce7f980b01c18c0fd561ef6687b1361507 (diff)
parente2d8a6f0a229b4ebe26484b892ec4f14888f58b6 (diff)
downloademacs-68359abba96d7ec4db8aab3d3dd9cf1105c3bab5.tar.gz
emacs-68359abba96d7ec4db8aab3d3dd9cf1105c3bab5.zip
merge from trunk; clean up some issues
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r--lisp/progmodes/python.el358
1 files changed, 316 insertions, 42 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index f0f67d01845..ccb2dcba42e 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -157,7 +157,7 @@
157 157
158;; Skeletons: 6 skeletons are provided for simple inserting of class, 158;; Skeletons: 6 skeletons are provided for simple inserting of class,
159;; def, for, if, try and while. These skeletons are integrated with 159;; def, for, if, try and while. These skeletons are integrated with
160;; dabbrev. If you have `dabbrev-mode' activated and 160;; abbrev. If you have `abbrev-mode' activated and
161;; `python-skeleton-autoinsert' is set to t, then whenever you type 161;; `python-skeleton-autoinsert' is set to t, then whenever you type
162;; the name of any of those defined and hit SPC, they will be 162;; the name of any of those defined and hit SPC, they will be
163;; automatically expanded. As an alternative you can use the defined 163;; automatically expanded. As an alternative you can use the defined
@@ -177,12 +177,14 @@
177;; might guessed you should run `python-shell-send-buffer' from time 177;; might guessed you should run `python-shell-send-buffer' from time
178;; to time to get better results too. 178;; to time to get better results too.
179 179
180;; Imenu: This mode supports Imenu in its most basic form, letting it 180;; Imenu: There are two index building functions to be used as
181;; build the necessary alist via `imenu-default-create-index-function' 181;; `imenu-create-index-function': `python-imenu-create-index' (the
182;; by having set `imenu-extract-index-name-function' to 182;; default one, builds the alist in form of a tree) and
183;; `python-info-current-defun' and 183;; `python-imenu-create-flat-index'. See also
184;; `imenu-prev-index-position-function' to 184;; `python-imenu-format-item-label-function',
185;; `python-imenu-prev-index-position'. 185;; `python-imenu-format-parent-item-label-function',
186;; `python-imenu-format-parent-item-jump-label-function' variables for
187;; changing the way labels are formatted in the tree version.
186 188
187;; If you used python-mode.el you probably will miss auto-indentation 189;; If you used python-mode.el you probably will miss auto-indentation
188;; when inserting newlines. To achieve the same behavior you have 190;; when inserting newlines. To achieve the same behavior you have
@@ -368,22 +370,24 @@ This variant of `rx' supports common python named REGEXPS."
368 370
369;;; Font-lock and syntax 371;;; Font-lock and syntax
370 372
373(eval-when-compile
374 (defun python-syntax--context-compiler-macro (form type &optional syntax-ppss)
375 (pcase type
376 (`'comment
377 `(let ((ppss (or ,syntax-ppss (syntax-ppss))))
378 (and (nth 4 ppss) (nth 8 ppss))))
379 (`'string
380 `(let ((ppss (or ,syntax-ppss (syntax-ppss))))
381 (and (nth 3 ppss) (nth 8 ppss))))
382 (`'paren
383 `(nth 1 (or ,syntax-ppss (syntax-ppss))))
384 (_ form))))
385
371(defun python-syntax-context (type &optional syntax-ppss) 386(defun python-syntax-context (type &optional syntax-ppss)
372 "Return non-nil if point is on TYPE using SYNTAX-PPSS. 387 "Return non-nil if point is on TYPE using SYNTAX-PPSS.
373TYPE can be `comment', `string' or `paren'. It returns the start 388TYPE can be `comment', `string' or `paren'. It returns the start
374character address of the specified TYPE." 389character address of the specified TYPE."
375 (declare (compiler-macro 390 (declare (compiler-macro python-syntax--context-compiler-macro))
376 (lambda (form)
377 (pcase type
378 (`'comment
379 `(let ((ppss (or ,syntax-ppss (syntax-ppss))))
380 (and (nth 4 ppss) (nth 8 ppss))))
381 (`'string
382 `(let ((ppss (or ,syntax-ppss (syntax-ppss))))
383 (and (nth 3 ppss) (nth 8 ppss))))
384 (`'paren
385 `(nth 1 (or ,syntax-ppss (syntax-ppss))))
386 (_ form)))))
387 (let ((ppss (or syntax-ppss (syntax-ppss)))) 391 (let ((ppss (or syntax-ppss (syntax-ppss))))
388 (pcase type 392 (pcase type
389 (`comment (and (nth 4 ppss) (nth 8 ppss))) 393 (`comment (and (nth 4 ppss) (nth 8 ppss)))
@@ -638,6 +642,13 @@ It makes underscores and dots word constituent chars.")
638These make `python-indent-calculate-indentation' subtract the value of 642These make `python-indent-calculate-indentation' subtract the value of
639`python-indent-offset'.") 643`python-indent-offset'.")
640 644
645(defvar python-indent-block-enders
646 '("break" "continue" "pass" "raise" "return")
647 "List of words that mark the end of a block.
648These make `python-indent-calculate-indentation' subtract the
649value of `python-indent-offset' when `python-indent-context' is
650AFTER-LINE.")
651
641(defun python-indent-guess-indent-offset () 652(defun python-indent-guess-indent-offset ()
642 "Guess and set `python-indent-offset' for the current buffer." 653 "Guess and set `python-indent-offset' for the current buffer."
643 (interactive) 654 (interactive)
@@ -763,9 +774,13 @@ START is the buffer position where the sexp starts."
763 (save-excursion 774 (save-excursion
764 (goto-char context-start) 775 (goto-char context-start)
765 (current-indentation)) 776 (current-indentation))
766 (if (progn 777 (if (or (save-excursion
767 (back-to-indentation) 778 (back-to-indentation)
768 (looking-at (regexp-opt python-indent-dedenters))) 779 (looking-at (regexp-opt python-indent-dedenters)))
780 (save-excursion
781 (python-util-forward-comment -1)
782 (python-nav-beginning-of-statement)
783 (member (current-word) python-indent-block-enders)))
769 python-indent-offset 784 python-indent-offset
770 0))) 785 0)))
771 ;; When inside of a string, do nothing. just use the current 786 ;; When inside of a string, do nothing. just use the current
@@ -1180,6 +1195,70 @@ Returns nil if point is not in a def or class."
1180 ;; Ensure point moves forward. 1195 ;; Ensure point moves forward.
1181 (and (> beg-pos (point)) (goto-char beg-pos))))) 1196 (and (> beg-pos (point)) (goto-char beg-pos)))))
1182 1197
1198(defun python-nav--syntactically (fn poscompfn &optional contextfn)
1199 "Move point using FN avoiding places with specific context.
1200FN must take no arguments. POSCOMPFN is a two arguments function
1201used to compare current and previous point after it is moved
1202using FN, this is normally a less-than or greater-than
1203comparison. Optional argument CONTEXTFN defaults to
1204`python-syntax-context-type' and is used for checking current
1205point context, it must return a non-nil value if this point must
1206be skipped."
1207 (let ((contextfn (or contextfn 'python-syntax-context-type))
1208 (start-pos (point-marker))
1209 (prev-pos))
1210 (catch 'found
1211 (while t
1212 (let* ((newpos
1213 (and (funcall fn) (point-marker)))
1214 (context (funcall contextfn)))
1215 (cond ((and (not context) newpos
1216 (or (and (not prev-pos) newpos)
1217 (and prev-pos newpos
1218 (funcall poscompfn newpos prev-pos))))
1219 (throw 'found (point-marker)))
1220 ((and newpos context)
1221 (setq prev-pos (point)))
1222 (t (when (not newpos) (goto-char start-pos))
1223 (throw 'found nil))))))))
1224
1225(defun python-nav--forward-defun (arg)
1226 "Internal implementation of python-nav-{backward,forward}-defun.
1227Uses ARG to define which function to call, and how many times
1228repeat it."
1229 (let ((found))
1230 (while (and (> arg 0)
1231 (setq found
1232 (python-nav--syntactically
1233 (lambda ()
1234 (re-search-forward
1235 python-nav-beginning-of-defun-regexp nil t))
1236 '>)))
1237 (setq arg (1- arg)))
1238 (while (and (< arg 0)
1239 (setq found
1240 (python-nav--syntactically
1241 (lambda ()
1242 (re-search-backward
1243 python-nav-beginning-of-defun-regexp nil t))
1244 '<)))
1245 (setq arg (1+ arg)))
1246 found))
1247
1248(defun python-nav-backward-defun (&optional arg)
1249 "Navigate to closer defun backward ARG times.
1250Unlikely `python-nav-beginning-of-defun' this doesn't care about
1251nested definitions."
1252 (interactive "^p")
1253 (python-nav--forward-defun (- (or arg 1))))
1254
1255(defun python-nav-forward-defun (&optional arg)
1256 "Navigate to closer defun forward ARG times.
1257Unlikely `python-nav-beginning-of-defun' this doesn't care about
1258nested definitions."
1259 (interactive "^p")
1260 (python-nav--forward-defun (or arg 1)))
1261
1183(defun python-nav-beginning-of-statement () 1262(defun python-nav-beginning-of-statement ()
1184 "Move to start of current statement." 1263 "Move to start of current statement."
1185 (interactive "^") 1264 (interactive "^")
@@ -1603,7 +1682,7 @@ This variable, when set to a string, makes the values stored in
1603`python-shell-process-environment' and `python-shell-exec-path' 1682`python-shell-process-environment' and `python-shell-exec-path'
1604to be modified properly so shells are started with the specified 1683to be modified properly so shells are started with the specified
1605virtualenv." 1684virtualenv."
1606 :type 'string 1685 :type '(choice (const nil) string)
1607 :group 'python 1686 :group 'python
1608 :safe 'stringp) 1687 :safe 'stringp)
1609 1688
@@ -2644,8 +2723,8 @@ the if condition."
2644(defvar python-skeleton-available '() 2723(defvar python-skeleton-available '()
2645 "Internal list of available skeletons.") 2724 "Internal list of available skeletons.")
2646 2725
2647(define-abbrev-table 'python-mode-abbrev-table () 2726(define-abbrev-table 'python-mode-skeleton-abbrev-table ()
2648 "Abbrev table for Python mode." 2727 "Abbrev table for Python mode skeletons."
2649 :case-fixed t 2728 :case-fixed t
2650 ;; Allow / inside abbrevs. 2729 ;; Allow / inside abbrevs.
2651 :regexp "\\(?:^\\|[^/]\\)\\<\\([[:word:]/]+\\)\\W*" 2730 :regexp "\\(?:^\\|[^/]\\)\\<\\([[:word:]/]+\\)\\W*"
@@ -2658,13 +2737,13 @@ the if condition."
2658(defmacro python-skeleton-define (name doc &rest skel) 2737(defmacro python-skeleton-define (name doc &rest skel)
2659 "Define a `python-mode' skeleton using NAME DOC and SKEL. 2738 "Define a `python-mode' skeleton using NAME DOC and SKEL.
2660The skeleton will be bound to python-skeleton-NAME and will 2739The skeleton will be bound to python-skeleton-NAME and will
2661be added to `python-mode-abbrev-table'." 2740be added to `python-mode-skeleton-abbrev-table'."
2662 (declare (indent 2)) 2741 (declare (indent 2))
2663 (let* ((name (symbol-name name)) 2742 (let* ((name (symbol-name name))
2664 (function-name (intern (concat "python-skeleton-" name)))) 2743 (function-name (intern (concat "python-skeleton-" name))))
2665 `(progn 2744 `(progn
2666 (define-abbrev python-mode-abbrev-table ,name "" ',function-name 2745 (define-abbrev python-mode-skeleton-abbrev-table
2667 :system t) 2746 ,name "" ',function-name :system t)
2668 (setq python-skeleton-available 2747 (setq python-skeleton-available
2669 (cons ',function-name python-skeleton-available)) 2748 (cons ',function-name python-skeleton-available))
2670 (define-skeleton ,function-name 2749 (define-skeleton ,function-name
@@ -2672,6 +2751,10 @@ be added to `python-mode-abbrev-table'."
2672 (format "Insert %s statement." name)) 2751 (format "Insert %s statement." name))
2673 ,@skel)))) 2752 ,@skel))))
2674 2753
2754(define-abbrev-table 'python-mode-abbrev-table ()
2755 "Abbrev table for Python mode."
2756 :parents (list python-mode-skeleton-abbrev-table))
2757
2675(defmacro python-define-auxiliary-skeleton (name doc &optional &rest skel) 2758(defmacro python-define-auxiliary-skeleton (name doc &optional &rest skel)
2676 "Define a `python-mode' auxiliary skeleton using NAME DOC and SKEL. 2759 "Define a `python-mode' auxiliary skeleton using NAME DOC and SKEL.
2677The skeleton will be bound to python-skeleton-NAME." 2760The skeleton will be bound to python-skeleton-NAME."
@@ -2928,15 +3011,193 @@ Interactively, prompt for symbol."
2928 3011
2929;;; Imenu 3012;;; Imenu
2930 3013
2931(defun python-imenu-prev-index-position () 3014(defvar python-imenu-format-item-label-function
2932 "Python mode's `imenu-prev-index-position-function'." 3015 'python-imenu-format-item-label
2933 (let ((found)) 3016 "Imenu function used to format an item label.
2934 (while (and (setq found 3017It must be a function with two arguments: TYPE and NAME.")
2935 (re-search-backward python-nav-beginning-of-defun-regexp nil t)) 3018
2936 (not (python-info-looking-at-beginning-of-defun)))) 3019(defvar python-imenu-format-parent-item-label-function
2937 (and found 3020 'python-imenu-format-parent-item-label
2938 (python-info-looking-at-beginning-of-defun) 3021 "Imenu function used to format a parent item label.
2939 (python-info-current-defun)))) 3022It must be a function with two arguments: TYPE and NAME.")
3023
3024(defvar python-imenu-format-parent-item-jump-label-function
3025 'python-imenu-format-parent-item-jump-label
3026 "Imenu function used to format a parent jump item label.
3027It must be a function with two arguments: TYPE and NAME.")
3028
3029(defun python-imenu-format-item-label (type name)
3030 "Return imenu label for single node using TYPE and NAME."
3031 (format "%s (%s)" name type))
3032
3033(defun python-imenu-format-parent-item-label (type name)
3034 "Return imenu label for parent node using TYPE and NAME."
3035 (format "%s..." (python-imenu-format-item-label type name)))
3036
3037(defun python-imenu-format-parent-item-jump-label (type name)
3038 "Return imenu label for parent node jump using TYPE and NAME."
3039 (if (string= type "class")
3040 "*class definition*"
3041 "*function definition*"))
3042
3043(defun python-imenu--put-parent (type name pos num-children tree &optional root)
3044 "Add the parent with TYPE, NAME, POS and NUM-CHILDREN to TREE.
3045Optional Argument ROOT must be non-nil when the node being
3046processed is the root of the TREE."
3047 (let ((label
3048 (funcall python-imenu-format-item-label-function type name))
3049 (jump-label
3050 (funcall python-imenu-format-parent-item-jump-label-function type name)))
3051 (if root
3052 ;; This is the root, everything is a children.
3053 (cons label (cons (cons jump-label pos) tree))
3054 ;; This is node a which may contain some children.
3055 (cons
3056 (cons label (cons (cons jump-label pos)
3057 ;; Append all the children
3058 (python-util-popn tree num-children)))
3059 ;; All previous non-children nodes.
3060 (nthcdr num-children tree)))))
3061
3062(defun python-imenu--build-tree (&optional min-indent prev-indent num-children tree)
3063 "Recursively build the tree of nested definitions of a node.
3064Arguments MIN-INDENT PREV-INDENT NUM-CHILDREN and TREE are
3065internal and should not be passed explicitly unless you know what
3066you are doing."
3067 (setq num-children (or num-children 0)
3068 min-indent (or min-indent 0))
3069 (let* ((pos (python-nav-backward-defun))
3070 (type)
3071 (name (when (and pos (looking-at python-nav-beginning-of-defun-regexp))
3072 (let ((split (split-string (match-string-no-properties 0))))
3073 (setq type (car split))
3074 (cadr split))))
3075 (label (when name
3076 (funcall python-imenu-format-item-label-function type name)))
3077 (indent (current-indentation)))
3078 (cond ((not pos)
3079 ;; No defun found, nothing to add.
3080 tree)
3081 ((equal indent 0)
3082 (if (> num-children 0)
3083 ;; Append it as the parent of everything collected to
3084 ;; this point.
3085 (python-imenu--put-parent type name pos num-children tree t)
3086 ;; There are no children, this is a lonely defun.
3087 (cons label pos)))
3088 ((equal min-indent indent)
3089 ;; Stop collecting nodes after moving to a position with
3090 ;; indentation equaling min-indent. This is specially
3091 ;; useful for navigating nested definitions recursively.
3092 tree)
3093 (t
3094 (python-imenu--build-tree
3095 min-indent
3096 indent
3097 ;; Add another children, either when this is the
3098 ;; first call or when indentation is
3099 ;; less-or-equal than previous. And do not
3100 ;; discard the number of children, because the
3101 ;; way code is scanned, all children are
3102 ;; collected until a root node yet to be found
3103 ;; appears.
3104 (if (or (not prev-indent)
3105 (and
3106 (> indent min-indent)
3107 (<= indent prev-indent)))
3108 (1+ num-children)
3109 num-children)
3110 (cond ((not prev-indent)
3111 ;; First call to the function: append this
3112 ;; defun to the index.
3113 (list (cons label pos)))
3114 ((= indent prev-indent)
3115 ;; Add another defun with the same depth
3116 ;; as the previous.
3117 (cons (cons label pos) tree))
3118 ((and (< indent prev-indent)
3119 (< 0 num-children))
3120 ;; There are children to be appended and
3121 ;; the previous defun had more
3122 ;; indentation, the current one must be a
3123 ;; parent.
3124 (python-imenu--put-parent type name pos num-children tree))
3125 ((> indent prev-indent)
3126 ;; There are children defuns deeper than
3127 ;; current depth. Fear not, we already
3128 ;; know how to treat them.
3129 (cons
3130 (prog1
3131 (python-imenu--build-tree
3132 prev-indent indent 1 (list (cons label pos)))
3133 ;; Adjustment: after scanning backwards
3134 ;; for all deeper children, we need to
3135 ;; continue our scan for a parent from
3136 ;; the current defun we are looking at.
3137 (python-nav-forward-defun))
3138 tree))))))))
3139
3140(defun python-imenu-create-index ()
3141 "Return tree Imenu alist for the current python buffer.
3142Change `python-imenu-format-item-label-function',
3143`python-imenu-format-parent-item-label-function',
3144`python-imenu-format-parent-item-jump-label-function' to
3145customize how labels are formatted."
3146 (goto-char (point-max))
3147 (let ((index)
3148 (tree))
3149 (while (setq tree (python-imenu--build-tree))
3150 (setq index (cons tree index)))
3151 index))
3152
3153(defun python-imenu-create-flat-index (&optional alist prefix)
3154 "Return flat outline of the current python buffer for Imenu.
3155Optional Argument ALIST is the tree to be flattened, when nil
3156`python-imenu-build-index' is used with
3157`python-imenu-format-parent-item-jump-label-function'
3158`python-imenu-format-parent-item-label-function'
3159`python-imenu-format-item-label-function' set to (lambda (type
3160name) name). Optional Argument PREFIX is used in recursive calls
3161and should not be passed explicitly.
3162
3163Converts this:
3164
3165 \((\"Foo\" . 103)
3166 (\"Bar\" . 138)
3167 (\"decorator\"
3168 (\"decorator\" . 173)
3169 (\"wrap\"
3170 (\"wrap\" . 353)
3171 (\"wrapped_f\" . 393))))
3172
3173To this:
3174
3175 \((\"Foo\" . 103)
3176 (\"Bar\" . 138)
3177 (\"decorator\" . 173)
3178 (\"decorator.wrap\" . 353)
3179 (\"decorator.wrapped_f\" . 393))"
3180 ;; Inspired by imenu--flatten-index-alist removed in revno 21853.
3181 (apply
3182 'nconc
3183 (mapcar
3184 (lambda (item)
3185 (let ((name (if prefix
3186 (concat prefix "." (car item))
3187 (car item)))
3188 (pos (cdr item)))
3189 (cond ((or (numberp pos) (markerp pos))
3190 (list (cons name pos)))
3191 ((listp pos)
3192 (cons
3193 (cons name (cdar pos))
3194 (python-imenu-create-flat-index (cddr item) name))))))
3195 (or alist
3196 (let* ((fn (lambda (type name) name))
3197 (python-imenu-format-item-label-function fn)
3198 (python-imenu-format-parent-item-label-function fn)
3199 (python-imenu-format-parent-item-jump-label-function fn))
3200 (python-imenu-create-index))))))
2940 3201
2941 3202
2942;;; Misc helpers 3203;;; Misc helpers
@@ -3257,6 +3518,22 @@ Optional argument DIRECTION defines the direction to move to."
3257 (goto-char comment-start)) 3518 (goto-char comment-start))
3258 (forward-comment factor))) 3519 (forward-comment factor)))
3259 3520
3521(defun python-util-popn (lst n)
3522 "Return LST first N elements.
3523N should be an integer, when it's a natural negative number its
3524opposite is used. When N is bigger than the length of LST, the
3525list is returned as is."
3526 (let* ((n (min (abs n)))
3527 (len (length lst))
3528 (acc))
3529 (if (> n len)
3530 lst
3531 (while (< 0 n)
3532 (setq acc (cons (car lst) acc)
3533 lst (cdr lst)
3534 n (1- n)))
3535 (reverse acc))))
3536
3260 3537
3261;;;###autoload 3538;;;###autoload
3262(define-derived-mode python-mode prog-mode "Python" 3539(define-derived-mode python-mode prog-mode "Python"
@@ -3302,11 +3579,8 @@ if that value is non-nil."
3302 (add-hook 'post-self-insert-hook 3579 (add-hook 'post-self-insert-hook
3303 'python-indent-post-self-insert-function nil 'local) 3580 'python-indent-post-self-insert-function nil 'local)
3304 3581
3305 (set (make-local-variable 'imenu-extract-index-name-function) 3582 (set (make-local-variable 'imenu-create-index-function)
3306 #'python-info-current-defun) 3583 #'python-imenu-create-index)
3307
3308 (set (make-local-variable 'imenu-prev-index-position-function)
3309 #'python-imenu-prev-index-position)
3310 3584
3311 (set (make-local-variable 'add-log-current-defun-function) 3585 (set (make-local-variable 'add-log-current-defun-function)
3312 #'python-info-current-defun) 3586 #'python-info-current-defun)