diff options
| author | Fabián Ezequiel Gallina | 2013-08-13 13:36:32 -0300 |
|---|---|---|
| committer | Fabián Ezequiel Gallina | 2013-08-13 13:36:32 -0300 |
| commit | ad75644970a5deccb1d40465e20087f5806ed3df (patch) | |
| tree | 8dc0ba2c980d3f6a3abc98918912b71c7141f363 | |
| parent | 866c710eeb75ce47767442952028d79b76c1606a (diff) | |
| download | emacs-ad75644970a5deccb1d40465e20087f5806ed3df.tar.gz emacs-ad75644970a5deccb1d40465e20087f5806ed3df.zip | |
* 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.
| -rw-r--r-- | lisp/ChangeLog | 5 | ||||
| -rw-r--r-- | lisp/progmodes/python.el | 114 | ||||
| -rw-r--r-- | test/ChangeLog | 5 | ||||
| -rw-r--r-- | test/automated/python-tests.el | 52 |
4 files changed, 94 insertions, 82 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 0c8791d8af7..11e5e913398 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2013-08-13 Fabián Ezequiel Gallina <fgallina@gnu.org> | ||
| 2 | |||
| 3 | * progmodes/python.el (python-imenu--build-tree) | ||
| 4 | (python-imenu--put-parent): Simplify and Fix (GH bug 146). | ||
| 5 | |||
| 1 | 2013-08-13 Xue Fuqiao <xfq.free@gmail.com> | 6 | 2013-08-13 Xue Fuqiao <xfq.free@gmail.com> |
| 2 | 7 | ||
| 3 | * simple.el (backward-word): Mention the optional argument. | 8 | * simple.el (backward-word): Mention the optional argument. |
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.") | |||
| 3042 | "*class definition*" | 3042 | "*class definition*" |
| 3043 | "*function definition*")) | 3043 | "*function definition*")) |
| 3044 | 3044 | ||
| 3045 | (defun python-imenu--put-parent (type name pos num-children tree &optional root) | 3045 | (defun python-imenu--put-parent (type name pos tree) |
| 3046 | "Add the parent with TYPE, NAME, POS and NUM-CHILDREN to TREE. | 3046 | "Add the parent with TYPE, NAME and POS to TREE." |
| 3047 | Optional Argument ROOT must be non-nil when the node being | ||
| 3048 | processed is the root of the TREE." | ||
| 3049 | (let ((label | 3047 | (let ((label |
| 3050 | (funcall python-imenu-format-item-label-function type name)) | 3048 | (funcall python-imenu-format-item-label-function type name)) |
| 3051 | (jump-label | 3049 | (jump-label |
| 3052 | (funcall python-imenu-format-parent-item-jump-label-function type name))) | 3050 | (funcall python-imenu-format-parent-item-jump-label-function type name))) |
| 3053 | (if root | 3051 | (if (not tree) |
| 3054 | ;; This is the root, everything is a children. | 3052 | (cons label pos) |
| 3055 | (cons label (cons (cons jump-label pos) tree)) | 3053 | (cons label (cons (cons jump-label pos) tree))))) |
| 3056 | ;; This is node a which may contain some children. | ||
| 3057 | (cons | ||
| 3058 | (cons label (cons (cons jump-label pos) | ||
| 3059 | ;; Append all the children | ||
| 3060 | (python-util-popn tree num-children))) | ||
| 3061 | ;; All previous non-children nodes. | ||
| 3062 | (nthcdr num-children tree))))) | ||
| 3063 | 3054 | ||
| 3064 | (defun python-imenu--build-tree (&optional min-indent prev-indent num-children tree) | 3055 | (defun python-imenu--build-tree (&optional min-indent prev-indent tree) |
| 3065 | "Recursively build the tree of nested definitions of a node. | 3056 | "Recursively build the tree of nested definitions of a node. |
| 3066 | Arguments MIN-INDENT PREV-INDENT NUM-CHILDREN and TREE are | 3057 | Arguments MIN-INDENT PREV-INDENT and TREE are internal and should |
| 3067 | internal and should not be passed explicitly unless you know what | 3058 | not be passed explicitly unless you know what you are doing." |
| 3068 | you are doing." | 3059 | (setq min-indent (or min-indent 0) |
| 3069 | (setq num-children (or num-children 0) | 3060 | prev-indent (or prev-indent python-indent-offset)) |
| 3070 | min-indent (or min-indent 0)) | ||
| 3071 | (let* ((pos (python-nav-backward-defun)) | 3061 | (let* ((pos (python-nav-backward-defun)) |
| 3072 | (type) | 3062 | (type) |
| 3073 | (name (when (and pos (looking-at python-nav-beginning-of-defun-regexp)) | 3063 | (name (when (and pos (looking-at python-nav-beginning-of-defun-regexp)) |
| @@ -3076,73 +3066,33 @@ you are doing." | |||
| 3076 | (cadr split)))) | 3066 | (cadr split)))) |
| 3077 | (label (when name | 3067 | (label (when name |
| 3078 | (funcall python-imenu-format-item-label-function type name))) | 3068 | (funcall python-imenu-format-item-label-function type name))) |
| 3079 | (indent (current-indentation))) | 3069 | (indent (current-indentation)) |
| 3070 | (children-indent-limit (+ python-indent-offset min-indent))) | ||
| 3080 | (cond ((not pos) | 3071 | (cond ((not pos) |
| 3081 | ;; No defun found, nothing to add. | 3072 | ;; Nothing found, probably near to bobp. |
| 3082 | tree) | 3073 | nil) |
| 3083 | ((equal indent 0) | 3074 | ((<= indent min-indent) |
| 3084 | (if (> num-children 0) | 3075 | ;; The current indentation points that this is a parent |
| 3085 | ;; Append it as the parent of everything collected to | 3076 | ;; node, add it to the tree and stop recursing. |
| 3086 | ;; this point. | 3077 | (python-imenu--put-parent type name pos tree)) |
| 3087 | (python-imenu--put-parent type name pos num-children tree t) | ||
| 3088 | ;; There are no children, this is a lonely defun. | ||
| 3089 | (cons label pos))) | ||
| 3090 | ((equal min-indent indent) | ||
| 3091 | ;; Stop collecting nodes after moving to a position with | ||
| 3092 | ;; indentation equaling min-indent. This is specially | ||
| 3093 | ;; useful for navigating nested definitions recursively. | ||
| 3094 | (if (> num-children 0) | ||
| 3095 | tree | ||
| 3096 | ;; When there are no children, the collected tree is a | ||
| 3097 | ;; single node intended to be added in the list of defuns | ||
| 3098 | ;; of its parent. | ||
| 3099 | (car tree))) | ||
| 3100 | (t | 3078 | (t |
| 3101 | (python-imenu--build-tree | 3079 | (python-imenu--build-tree |
| 3102 | min-indent | 3080 | min-indent |
| 3103 | indent | 3081 | indent |
| 3104 | ;; Add another children, either when this is the | 3082 | (if (<= indent children-indent-limit) |
| 3105 | ;; first call or when indentation is | 3083 | ;; This lays within the children indent offset range, |
| 3106 | ;; less-or-equal than previous. And do not | 3084 | ;; so it's a normal children of its parent (i.e., not |
| 3107 | ;; discard the number of children, because the | 3085 | ;; a children of a children). |
| 3108 | ;; way code is scanned, all children are | 3086 | (cons (cons label pos) tree) |
| 3109 | ;; collected until a root node yet to be found | 3087 | ;; Oh noes, a children of a children?!. Fear not, we |
| 3110 | ;; appears. | 3088 | ;; know how to roll. We recursely parse these by |
| 3111 | (if (or (not prev-indent) | 3089 | ;; swapping prev-indent and min-indent plus adding this |
| 3112 | (and | 3090 | ;; newly found item to a fresh subtree. This works, I |
| 3113 | (> indent min-indent) | 3091 | ;; promise. |
| 3114 | (<= indent prev-indent))) | 3092 | (cons |
| 3115 | (1+ num-children) | 3093 | (python-imenu--build-tree |
| 3116 | num-children) | 3094 | prev-indent indent (list (cons label pos))) |
| 3117 | (cond ((not prev-indent) | 3095 | tree))))))) |
| 3118 | ;; First call to the function: append this | ||
| 3119 | ;; defun to the index. | ||
| 3120 | (list (cons label pos))) | ||
| 3121 | ((= indent prev-indent) | ||
| 3122 | ;; Add another defun with the same depth | ||
| 3123 | ;; as the previous. | ||
| 3124 | (cons (cons label pos) tree)) | ||
| 3125 | ((and (< indent prev-indent) | ||
| 3126 | (< 0 num-children)) | ||
| 3127 | ;; There are children to be appended and | ||
| 3128 | ;; the previous defun had more | ||
| 3129 | ;; indentation, the current one must be a | ||
| 3130 | ;; parent. | ||
| 3131 | (python-imenu--put-parent type name pos num-children tree)) | ||
| 3132 | ((> indent prev-indent) | ||
| 3133 | ;; There are children defuns deeper than | ||
| 3134 | ;; current depth. Fear not, we already | ||
| 3135 | ;; know how to treat them. | ||
| 3136 | (cons | ||
| 3137 | (prog1 | ||
| 3138 | (python-imenu--build-tree | ||
| 3139 | prev-indent indent 0 (list (cons label pos))) | ||
| 3140 | ;; Adjustment: after scanning backwards | ||
| 3141 | ;; for all deeper children, we need to | ||
| 3142 | ;; continue our scan for a parent from | ||
| 3143 | ;; the current defun we are looking at. | ||
| 3144 | (python-nav-forward-defun)) | ||
| 3145 | tree)))))))) | ||
| 3146 | 3096 | ||
| 3147 | (defun python-imenu-create-index () | 3097 | (defun python-imenu-create-index () |
| 3148 | "Return tree Imenu alist for the current python buffer. | 3098 | "Return tree Imenu alist for the current python buffer. |
diff --git a/test/ChangeLog b/test/ChangeLog index 2e4d19e7a36..1d38f2dd429 100644 --- a/test/ChangeLog +++ b/test/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2013-08-13 Fabián Ezequiel Gallina <fgallina@gnu.org> | ||
| 2 | |||
| 3 | * automated/python-tests.el (python-imenu-create-index-4) | ||
| 4 | (python-imenu-create-flat-index-2): New tests. | ||
| 5 | |||
| 1 | 2013-08-05 Glenn Morris <rgm@gnu.org> | 6 | 2013-08-05 Glenn Morris <rgm@gnu.org> |
| 2 | 7 | ||
| 3 | * automated/mule-util.el: New file, with tests extracted from | 8 | * automated/mule-util.el: New file, with tests extracted from |
diff --git a/test/automated/python-tests.el b/test/automated/python-tests.el index fdae235ad38..ef1c0155ab5 100644 --- a/test/automated/python-tests.el +++ b/test/automated/python-tests.el | |||
| @@ -1792,6 +1792,34 @@ class Foo(object): | |||
| 1792 | (cons "foo2 (def)" (copy-marker 77))))) | 1792 | (cons "foo2 (def)" (copy-marker 77))))) |
| 1793 | (python-imenu-create-index))))) | 1793 | (python-imenu-create-index))))) |
| 1794 | 1794 | ||
| 1795 | (ert-deftest python-imenu-create-index-4 () | ||
| 1796 | (python-tests-with-temp-buffer | ||
| 1797 | " | ||
| 1798 | class Foo(object): | ||
| 1799 | class Bar(object): | ||
| 1800 | def __init__(self): | ||
| 1801 | pass | ||
| 1802 | |||
| 1803 | def __str__(self): | ||
| 1804 | pass | ||
| 1805 | |||
| 1806 | def __init__(self): | ||
| 1807 | pass | ||
| 1808 | " | ||
| 1809 | (goto-char (point-max)) | ||
| 1810 | (should (equal | ||
| 1811 | (list | ||
| 1812 | (list | ||
| 1813 | "Foo (class)" | ||
| 1814 | (cons "*class definition*" (copy-marker 2)) | ||
| 1815 | (list | ||
| 1816 | "Bar (class)" | ||
| 1817 | (cons "*class definition*" (copy-marker 21)) | ||
| 1818 | (cons "__init__ (def)" (copy-marker 44)) | ||
| 1819 | (cons "__str__ (def)" (copy-marker 90))) | ||
| 1820 | (cons "__init__ (def)" (copy-marker 135)))) | ||
| 1821 | (python-imenu-create-index))))) | ||
| 1822 | |||
| 1795 | (ert-deftest python-imenu-create-flat-index-1 () | 1823 | (ert-deftest python-imenu-create-flat-index-1 () |
| 1796 | (python-tests-with-temp-buffer | 1824 | (python-tests-with-temp-buffer |
| 1797 | " | 1825 | " |
| @@ -1851,6 +1879,30 @@ class Baz(object): | |||
| 1851 | (cons "Baz.Frob.c" (copy-marker 626))) | 1879 | (cons "Baz.Frob.c" (copy-marker 626))) |
| 1852 | (python-imenu-create-flat-index))))) | 1880 | (python-imenu-create-flat-index))))) |
| 1853 | 1881 | ||
| 1882 | (ert-deftest python-imenu-create-flat-index-2 () | ||
| 1883 | (python-tests-with-temp-buffer | ||
| 1884 | " | ||
| 1885 | class Foo(object): | ||
| 1886 | class Bar(object): | ||
| 1887 | def __init__(self): | ||
| 1888 | pass | ||
| 1889 | |||
| 1890 | def __str__(self): | ||
| 1891 | pass | ||
| 1892 | |||
| 1893 | def __init__(self): | ||
| 1894 | pass | ||
| 1895 | " | ||
| 1896 | (goto-char (point-max)) | ||
| 1897 | (should (equal | ||
| 1898 | (list | ||
| 1899 | (cons "Foo" (copy-marker 2)) | ||
| 1900 | (cons "Foo.Bar" (copy-marker 21)) | ||
| 1901 | (cons "Foo.Bar.__init__" (copy-marker 44)) | ||
| 1902 | (cons "Foo.Bar.__str__" (copy-marker 90)) | ||
| 1903 | (cons "Foo.__init__" (copy-marker 135))) | ||
| 1904 | (python-imenu-create-flat-index))))) | ||
| 1905 | |||
| 1854 | 1906 | ||
| 1855 | ;;; Misc helpers | 1907 | ;;; Misc helpers |
| 1856 | 1908 | ||