diff options
| author | Eli Zaretskii | 2013-04-19 11:39:24 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2013-04-19 11:39:24 +0300 |
| commit | 4cf86a2fa737296d26e8a02338e2bf6f26e1133a (patch) | |
| tree | 094502cb2926db798570e62d32c680b2ce72b6c2 /lisp/progmodes/python.el | |
| parent | f60f289656d815827a492150f2e564dd081967f8 (diff) | |
| parent | 7d6883367a54b4eee342aa861ef73e4191151ef0 (diff) | |
| download | emacs-4cf86a2fa737296d26e8a02338e2bf6f26e1133a.tar.gz emacs-4cf86a2fa737296d26e8a02338e2bf6f26e1133a.zip | |
Merge from trunk.
Diffstat (limited to 'lisp/progmodes/python.el')
| -rw-r--r-- | lisp/progmodes/python.el | 234 |
1 files changed, 213 insertions, 21 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 53aff94ae0e..06d07d6ee3c 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -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 |
| @@ -1194,7 +1196,7 @@ Returns nil if point is not in a def or class." | |||
| 1194 | 1196 | ||
| 1195 | (defun python-nav--syntactically (fn poscompfn &optional contextfn) | 1197 | (defun python-nav--syntactically (fn poscompfn &optional contextfn) |
| 1196 | "Move point using FN avoiding places with specific context. | 1198 | "Move point using FN avoiding places with specific context. |
| 1197 | FN must take no arguments. POSCOMPFN is a two arguments function | 1199 | FN must take no arguments. POSCOMPFN is a two arguments function |
| 1198 | used to compare current and previous point after it is moved | 1200 | used to compare current and previous point after it is moved |
| 1199 | using FN, this is normally a less-than or greater-than | 1201 | using FN, this is normally a less-than or greater-than |
| 1200 | comparison. Optional argument CONTEXTFN defaults to | 1202 | comparison. Optional argument CONTEXTFN defaults to |
| @@ -3008,15 +3010,192 @@ Interactively, prompt for symbol." | |||
| 3008 | 3010 | ||
| 3009 | ;;; Imenu | 3011 | ;;; Imenu |
| 3010 | 3012 | ||
| 3011 | (defun python-imenu-prev-index-position () | 3013 | (defvar python-imenu-format-item-label-function |
| 3012 | "Python mode's `imenu-prev-index-position-function'." | 3014 | 'python-imenu-format-item-label |
| 3013 | (let ((found)) | 3015 | "Imenu function used to format an item label. |
| 3014 | (while (and (setq found | 3016 | It must be a function with two arguments: TYPE and NAME.") |
| 3015 | (re-search-backward python-nav-beginning-of-defun-regexp nil t)) | 3017 | |
| 3016 | (not (python-info-looking-at-beginning-of-defun)))) | 3018 | (defvar python-imenu-format-parent-item-label-function |
| 3017 | (and found | 3019 | 'python-imenu-format-parent-item-label |
| 3018 | (python-info-looking-at-beginning-of-defun) | 3020 | "Imenu function used to format a parent item label. |
| 3019 | (python-info-current-defun)))) | 3021 | It must be a function with two arguments: TYPE and NAME.") |
| 3022 | |||
| 3023 | (defvar python-imenu-format-parent-item-jump-label-function | ||
| 3024 | 'python-imenu-format-parent-item-jump-label | ||
| 3025 | "Imenu function used to format a parent jump item label. | ||
| 3026 | It must be a function with two arguments: TYPE and NAME.") | ||
| 3027 | |||
| 3028 | (defun python-imenu-format-item-label (type name) | ||
| 3029 | "Return imenu label for single node using TYPE and NAME." | ||
| 3030 | (format "%s (%s)" name type)) | ||
| 3031 | |||
| 3032 | (defun python-imenu-format-parent-item-label (type name) | ||
| 3033 | "Return imenu label for parent node using TYPE and NAME." | ||
| 3034 | (format "%s..." (python-imenu-format-item-label type name))) | ||
| 3035 | |||
| 3036 | (defun python-imenu-format-parent-item-jump-label (type name) | ||
| 3037 | "Return imenu label for parent node jump using TYPE and NAME." | ||
| 3038 | (if (string= type "class") | ||
| 3039 | "*class definition*" | ||
| 3040 | "*function definition*")) | ||
| 3041 | |||
| 3042 | (defun python-imenu--put-parent (type name pos num-children tree &optional root) | ||
| 3043 | "Add the parent with TYPE, NAME, POS and NUM-CHILDREN to TREE. | ||
| 3044 | Optional Argument ROOT must be non-nil when the node being | ||
| 3045 | processed is the root of the TREE." | ||
| 3046 | (let ((label | ||
| 3047 | (funcall python-imenu-format-item-label-function type name)) | ||
| 3048 | (jump-label | ||
| 3049 | (funcall python-imenu-format-parent-item-jump-label-function type name))) | ||
| 3050 | (if root | ||
| 3051 | ;; This is the root, everything is a children. | ||
| 3052 | (cons label (cons (cons jump-label pos) tree)) | ||
| 3053 | ;; This is node a which may contain some children. | ||
| 3054 | (cons | ||
| 3055 | (cons label (cons (cons jump-label pos) | ||
| 3056 | ;; Append all the children | ||
| 3057 | (python-util-popn tree num-children))) | ||
| 3058 | ;; All previous non-children nodes. | ||
| 3059 | (nthcdr num-children tree))))) | ||
| 3060 | |||
| 3061 | (defun python-imenu--build-tree (&optional min-indent prev-indent num-children tree) | ||
| 3062 | "Recursively build the tree of nested definitions of a node. | ||
| 3063 | Arguments MIN-INDENT PREV-INDENT NUM-CHILDREN and TREE are | ||
| 3064 | internal and should not be passed explicitly unless you know what | ||
| 3065 | you are doing." | ||
| 3066 | (setq num-children (or num-children 0) | ||
| 3067 | min-indent (or min-indent 0)) | ||
| 3068 | (let* ((pos (python-nav-backward-defun)) | ||
| 3069 | (type) | ||
| 3070 | (name (when (and pos (looking-at python-nav-beginning-of-defun-regexp)) | ||
| 3071 | (let ((split (split-string (match-string-no-properties 0)))) | ||
| 3072 | (setq type (car split)) | ||
| 3073 | (cadr split)))) | ||
| 3074 | (label (when name | ||
| 3075 | (funcall python-imenu-format-item-label-function type name))) | ||
| 3076 | (indent (current-indentation))) | ||
| 3077 | (cond ((not pos) | ||
| 3078 | ;; No defun found, nothing to add. | ||
| 3079 | tree) | ||
| 3080 | ((equal indent 0) | ||
| 3081 | (if (> num-children 0) | ||
| 3082 | ;; Append it as the parent of everything collected to | ||
| 3083 | ;; this point. | ||
| 3084 | (python-imenu--put-parent type name pos num-children tree t) | ||
| 3085 | ;; There are no children, this is a lonely defun. | ||
| 3086 | (cons label pos))) | ||
| 3087 | ((equal min-indent indent) | ||
| 3088 | ;; Stop collecting nodes after moving to a position with | ||
| 3089 | ;; indentation equaling min-indent. This is specially | ||
| 3090 | ;; useful for navigating nested definitions recursively. | ||
| 3091 | tree) | ||
| 3092 | (t | ||
| 3093 | (python-imenu--build-tree | ||
| 3094 | min-indent | ||
| 3095 | indent | ||
| 3096 | ;; Add another children, either when this is the | ||
| 3097 | ;; first call or when indentation is | ||
| 3098 | ;; less-or-equal than previous. And do not | ||
| 3099 | ;; discard the number of children, because the | ||
| 3100 | ;; way code is scanned, all children are | ||
| 3101 | ;; collected until a root node yet to be found | ||
| 3102 | ;; appears. | ||
| 3103 | (if (or (not prev-indent) | ||
| 3104 | (and | ||
| 3105 | (> indent min-indent) | ||
| 3106 | (<= indent prev-indent))) | ||
| 3107 | (1+ num-children) | ||
| 3108 | num-children) | ||
| 3109 | (cond ((not prev-indent) | ||
| 3110 | ;; First call to the function: append this | ||
| 3111 | ;; defun to the index. | ||
| 3112 | (list (cons label pos))) | ||
| 3113 | ((= indent prev-indent) | ||
| 3114 | ;; Add another defun with the same depth | ||
| 3115 | ;; as the previous. | ||
| 3116 | (cons (cons label pos) tree)) | ||
| 3117 | ((and (< indent prev-indent) | ||
| 3118 | (< 0 num-children)) | ||
| 3119 | ;; There are children to be appended and | ||
| 3120 | ;; the previous defun had more | ||
| 3121 | ;; indentation, the current one must be a | ||
| 3122 | ;; parent. | ||
| 3123 | (python-imenu--put-parent type name pos num-children tree)) | ||
| 3124 | ((> indent prev-indent) | ||
| 3125 | ;; There are children defuns deeper than | ||
| 3126 | ;; current depth. Fear not, we already | ||
| 3127 | ;; know how to treat them. | ||
| 3128 | (cons | ||
| 3129 | (prog1 | ||
| 3130 | (python-imenu--build-tree | ||
| 3131 | prev-indent indent 1 (list (cons label pos))) | ||
| 3132 | ;; Adjustment: after scanning backwards | ||
| 3133 | ;; for all deeper children, we need to | ||
| 3134 | ;; continue our scan for a parent from | ||
| 3135 | ;; the current defun we are looking at. | ||
| 3136 | (python-nav-forward-defun)) | ||
| 3137 | tree)))))))) | ||
| 3138 | |||
| 3139 | (defun python-imenu-create-index () | ||
| 3140 | "Return tree Imenu alist for the current python buffer. | ||
| 3141 | Change `python-imenu-format-item-label-function', | ||
| 3142 | `python-imenu-format-parent-item-label-function', | ||
| 3143 | `python-imenu-format-parent-item-jump-label-function' to | ||
| 3144 | customize how labels are formatted." | ||
| 3145 | (goto-char (point-max)) | ||
| 3146 | (let ((index) | ||
| 3147 | (tree)) | ||
| 3148 | (while (setq tree (python-imenu--build-tree)) | ||
| 3149 | (setq index (cons tree index))) | ||
| 3150 | index)) | ||
| 3151 | |||
| 3152 | (defun python-imenu-create-flat-index (&optional alist prefix) | ||
| 3153 | "Return flat outline of the current python buffer for Imenu. | ||
| 3154 | Optional Argument ALIST is the tree to be flattened, when nil | ||
| 3155 | `python-imenu-build-index' is used with | ||
| 3156 | `python-imenu-format-parent-item-jump-label-function' | ||
| 3157 | `python-imenu-format-parent-item-label-function' | ||
| 3158 | `python-imenu-format-item-label-function' set to (lambda (type | ||
| 3159 | name) name). Optional Argument PREFIX is used in recursive calls | ||
| 3160 | and should not be passed explicitly. | ||
| 3161 | |||
| 3162 | Converts this: | ||
| 3163 | |||
| 3164 | \((\"Foo\" . 103) | ||
| 3165 | (\"Bar\" . 138) | ||
| 3166 | (\"decorator\" | ||
| 3167 | (\"decorator\" . 173) | ||
| 3168 | (\"wrap\" | ||
| 3169 | (\"wrap\" . 353) | ||
| 3170 | (\"wrapped_f\" . 393)))) | ||
| 3171 | |||
| 3172 | To this: | ||
| 3173 | |||
| 3174 | \((\"Foo\" . 103) | ||
| 3175 | (\"Bar\" . 138) | ||
| 3176 | (\"decorator\" . 173) | ||
| 3177 | (\"decorator.wrap\" . 353) | ||
| 3178 | (\"decorator.wrapped_f\" . 393))" | ||
| 3179 | (apply | ||
| 3180 | 'nconc | ||
| 3181 | (mapcar | ||
| 3182 | (lambda (item) | ||
| 3183 | (let ((name (if prefix | ||
| 3184 | (concat prefix "." (car item)) | ||
| 3185 | (car item))) | ||
| 3186 | (pos (cdr item))) | ||
| 3187 | (cond ((or (numberp pos) (markerp pos)) | ||
| 3188 | (list (cons name pos))) | ||
| 3189 | ((listp pos) | ||
| 3190 | (message "%S" item) | ||
| 3191 | (cons | ||
| 3192 | (cons name (cdar pos)) | ||
| 3193 | (python-imenu-create-flat-index (cddr item) name)))))) | ||
| 3194 | (or alist | ||
| 3195 | (let ((python-imenu-format-item-label-function (lambda (type name) name)) | ||
| 3196 | (python-imenu-format-parent-item-label-function (lambda (type name) name)) | ||
| 3197 | (python-imenu-format-parent-item-jump-label-function (lambda (type name) name))) | ||
| 3198 | (python-imenu-create-index)))))) | ||
| 3020 | 3199 | ||
| 3021 | 3200 | ||
| 3022 | ;;; Misc helpers | 3201 | ;;; Misc helpers |
| @@ -3337,6 +3516,22 @@ Optional argument DIRECTION defines the direction to move to." | |||
| 3337 | (goto-char comment-start)) | 3516 | (goto-char comment-start)) |
| 3338 | (forward-comment factor))) | 3517 | (forward-comment factor))) |
| 3339 | 3518 | ||
| 3519 | (defun python-util-popn (lst n) | ||
| 3520 | "Return LST first N elements. | ||
| 3521 | N should be an integer, when it's a natural negative number its | ||
| 3522 | opposite is used. When N is bigger than the length of LST, the | ||
| 3523 | list is returned as is." | ||
| 3524 | (let* ((n (min (abs n))) | ||
| 3525 | (len (length lst)) | ||
| 3526 | (acc)) | ||
| 3527 | (if (> n len) | ||
| 3528 | lst | ||
| 3529 | (while (< 0 n) | ||
| 3530 | (setq acc (cons (car lst) acc) | ||
| 3531 | lst (cdr lst) | ||
| 3532 | n (1- n))) | ||
| 3533 | (reverse acc)))) | ||
| 3534 | |||
| 3340 | 3535 | ||
| 3341 | ;;;###autoload | 3536 | ;;;###autoload |
| 3342 | (define-derived-mode python-mode prog-mode "Python" | 3537 | (define-derived-mode python-mode prog-mode "Python" |
| @@ -3382,11 +3577,8 @@ if that value is non-nil." | |||
| 3382 | (add-hook 'post-self-insert-hook | 3577 | (add-hook 'post-self-insert-hook |
| 3383 | 'python-indent-post-self-insert-function nil 'local) | 3578 | 'python-indent-post-self-insert-function nil 'local) |
| 3384 | 3579 | ||
| 3385 | (set (make-local-variable 'imenu-extract-index-name-function) | 3580 | (set (make-local-variable 'imenu-create-index-function) |
| 3386 | #'python-info-current-defun) | 3581 | #'python-imenu-create-index) |
| 3387 | |||
| 3388 | (set (make-local-variable 'imenu-prev-index-position-function) | ||
| 3389 | #'python-imenu-prev-index-position) | ||
| 3390 | 3582 | ||
| 3391 | (set (make-local-variable 'add-log-current-defun-function) | 3583 | (set (make-local-variable 'add-log-current-defun-function) |
| 3392 | #'python-info-current-defun) | 3584 | #'python-info-current-defun) |