diff options
Diffstat (limited to 'lisp/progmodes/python.el')
| -rw-r--r-- | lisp/progmodes/python.el | 358 |
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. |
| 373 | TYPE can be `comment', `string' or `paren'. It returns the start | 388 | TYPE can be `comment', `string' or `paren'. It returns the start |
| 374 | character address of the specified TYPE." | 389 | character 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.") | |||
| 638 | These make `python-indent-calculate-indentation' subtract the value of | 642 | These 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. | ||
| 648 | These make `python-indent-calculate-indentation' subtract the | ||
| 649 | value of `python-indent-offset' when `python-indent-context' is | ||
| 650 | AFTER-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. | ||
| 1200 | FN must take no arguments. POSCOMPFN is a two arguments function | ||
| 1201 | used to compare current and previous point after it is moved | ||
| 1202 | using FN, this is normally a less-than or greater-than | ||
| 1203 | comparison. Optional argument CONTEXTFN defaults to | ||
| 1204 | `python-syntax-context-type' and is used for checking current | ||
| 1205 | point context, it must return a non-nil value if this point must | ||
| 1206 | be 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. | ||
| 1227 | Uses ARG to define which function to call, and how many times | ||
| 1228 | repeat 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. | ||
| 1250 | Unlikely `python-nav-beginning-of-defun' this doesn't care about | ||
| 1251 | nested 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. | ||
| 1257 | Unlikely `python-nav-beginning-of-defun' this doesn't care about | ||
| 1258 | nested 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' |
| 1604 | to be modified properly so shells are started with the specified | 1683 | to be modified properly so shells are started with the specified |
| 1605 | virtualenv." | 1684 | virtualenv." |
| 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. |
| 2660 | The skeleton will be bound to python-skeleton-NAME and will | 2739 | The skeleton will be bound to python-skeleton-NAME and will |
| 2661 | be added to `python-mode-abbrev-table'." | 2740 | be 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. |
| 2677 | The skeleton will be bound to python-skeleton-NAME." | 2760 | The 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 | 3017 | It 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)))) | 3022 | It 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. | ||
| 3027 | It 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. | ||
| 3045 | Optional Argument ROOT must be non-nil when the node being | ||
| 3046 | processed 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. | ||
| 3064 | Arguments MIN-INDENT PREV-INDENT NUM-CHILDREN and TREE are | ||
| 3065 | internal and should not be passed explicitly unless you know what | ||
| 3066 | you 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. | ||
| 3142 | Change `python-imenu-format-item-label-function', | ||
| 3143 | `python-imenu-format-parent-item-label-function', | ||
| 3144 | `python-imenu-format-parent-item-jump-label-function' to | ||
| 3145 | customize 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. | ||
| 3155 | Optional 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 | ||
| 3160 | name) name). Optional Argument PREFIX is used in recursive calls | ||
| 3161 | and should not be passed explicitly. | ||
| 3162 | |||
| 3163 | Converts this: | ||
| 3164 | |||
| 3165 | \((\"Foo\" . 103) | ||
| 3166 | (\"Bar\" . 138) | ||
| 3167 | (\"decorator\" | ||
| 3168 | (\"decorator\" . 173) | ||
| 3169 | (\"wrap\" | ||
| 3170 | (\"wrap\" . 353) | ||
| 3171 | (\"wrapped_f\" . 393)))) | ||
| 3172 | |||
| 3173 | To 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. | ||
| 3523 | N should be an integer, when it's a natural negative number its | ||
| 3524 | opposite is used. When N is bigger than the length of LST, the | ||
| 3525 | list 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) |