]> code.delx.au - gnu-emacs-elpa/blobdiff - packages/js2-mode/js2-imenu-extras.el
Merge commit '3575aaa39f311822dcedd53235ba036e9cf68ab8' from js2-mode
[gnu-emacs-elpa] / packages / js2-mode / js2-imenu-extras.el
index e8e15a505de4e234b633f5d5eb4c6676855a2452..3052cafedc12ab2960e5f0b5bfdf769cf547f6cd 100644 (file)
@@ -1,6 +1,6 @@
 ;;; js2-imenu-extras.el --- Imenu support for additional constructs\r
 \r
-;; Copyright (C) 2012-2013  Free Software Foundation, Inc.\r
+;; Copyright (C) 2012-2014  Free Software Foundation, Inc.\r
 \r
 ;; Author:    Dmitry Gutov <dgutov@yandex.ru>\r
 ;; Keywords:  languages, javascript, imenu\r
 \r
     (:framework backbone\r
      :call-re   ,(concat "\\_<" js2-mode-identifier-re "\\.extend\\s-*(")\r
-     :recorder  js2-imenu-record-backbone-extend))\r
+     :recorder  js2-imenu-record-backbone-extend)\r
+\r
+    (:framework enyo\r
+     :call-re   "\\_<enyo\\.kind\\s-*("\r
+     :recorder  js2-imenu-record-enyo-kind))\r
   "List of JavaScript class definition or extension styles.\r
 \r
 :framework is a valid value in `js2-imenu-enabled-frameworks'.\r
@@ -96,6 +100,12 @@ prefix any functions defined inside the IIFE with the module name."
   :type 'boolean\r
   :group 'js2-imenu)\r
 \r
+(defcustom js2-imenu-split-string-identifiers t\r
+  "When non-nil, split string identifiers on dots.\r
+Currently used for jQuery widgets, Dojo and Enyo declarations."\r
+  :type 'boolean\r
+  :group 'js2-imenu)\r
+\r
 ;;;###autoload\r
 (defun js2-imenu-extras-setup ()\r
   (when js2-imenu-enabled-frameworks\r
@@ -133,7 +143,10 @@ prefix any functions defined inside the IIFE with the module name."
 (defun js2-imenu-record-string-declare ()\r
   (js2-imenu-record-extend-first-arg\r
    (1- (point)) 'js2-string-node-p\r
-   (lambda (node) (split-string (js2-string-node-value node) "\\." t))))\r
+   (lambda (node)\r
+     (if js2-imenu-split-string-identifiers\r
+         (split-string (js2-string-node-value node) "\\." t)\r
+       (list (js2-string-node-value node))))))\r
 \r
 (defun js2-imenu-record-extend-first-arg (point pred qname-fn)\r
   (let* ((node (js2-node-at-point point))\r
@@ -160,6 +173,31 @@ prefix any functions defined inside the IIFE with the module name."
                                      (js2-compute-nested-prop-get subject)\r
                                      (js2-node-abs-pos methods)))))))\r
 \r
+(defun js2-imenu-record-enyo-kind ()\r
+  (let* ((node (js2-node-at-point (1- (point))))\r
+         (args (js2-call-node-args node))\r
+         (options (first args)))\r
+    (when (js2-object-node-p options)\r
+      (let ((name-value\r
+             (loop for elem in (js2-object-node-elems options)\r
+                   thereis\r
+                   (let ((key (js2-object-prop-node-left elem))\r
+                         (value (js2-object-prop-node-right elem)))\r
+                     (when (and (equal\r
+                                 (cond ((js2-name-node-p key)\r
+                                        (js2-name-node-name key))\r
+                                       ((js2-string-node-p key)\r
+                                        (js2-string-node-value key)))\r
+                                 "name")\r
+                                (js2-string-node-p value))\r
+                       (js2-string-node-value value))))))\r
+        (when name-value\r
+          (js2-record-object-literal options\r
+                                     (if js2-imenu-split-string-identifiers\r
+                                         (split-string name-value "\\.")\r
+                                       (list name-value))\r
+                                     (js2-node-abs-pos options)))))))\r
+\r
 (defun js2-imenu-walk-ast ()\r
   (js2-visit-ast\r
    js2-mode-ast\r
@@ -174,6 +212,35 @@ prefix any functions defined inside the IIFE with the module name."
          (js2-imenu-record-module-pattern node)))\r
        t))))\r
 \r
+(defun js2-imenu-parent-key-names (node)\r
+  "Get the list of parent key names of NODE.\r
+\r
+For example, for code\r
+\r
+  {rules: {password: {required: function() {}}}}\r
+\r
+when NODE is the inner `js2-object-prop-mode',\r
+it returns `(\"rules\" \"password\")'."\r
+  (let (rlt (n node))\r
+    (while (setq n (js2-imenu-parent-prop-node n))\r
+      (push (js2-prop-node-name (js2-object-prop-node-left n)) rlt))\r
+    rlt))\r
+\r
+(defun js2-imenu-parent-prop-node (node)\r
+  "When the parent of NODE is `js2-object-node',\r
+and the grandparent is `js2-object-prop-node',\r
+return the grandparent."\r
+  ;; Suppose the code is:\r
+  ;; {parent-key: {required: function() {}}}\r
+  ;; NODE is `required: function() {}'.\r
+  (let (p2 p3)\r
+    ;; Parent is `{required: function() {}}'.\r
+    (setq p2 (js2-node-parent node))\r
+    ;; GP is `parent-key: {required: function() {}}'.\r
+    (when (and p2 (js2-object-node-p p2))\r
+      (setq p3 (js2-node-parent p2))\r
+      (if (and p3 (js2-object-prop-node-p p3)) p3))))\r
+\r
 (defun js2-imenu-record-orphan-function (node)\r
   "Record orphan function when it's the value of NODE.\r
 NODE must be `js2-object-prop-node'."\r
@@ -181,10 +248,13 @@ NODE must be `js2-object-prop-node'."
     (let ((fn-node (js2-object-prop-node-right node)))\r
       (unless (and js2-imenu-function-map\r
                    (gethash fn-node js2-imenu-function-map))\r
-        (let ((key-node (js2-object-prop-node-left node)))\r
-          (js2-record-imenu-entry fn-node\r
-                                  (list js2-imenu-other-functions-ns\r
-                                        (js2-prop-node-name key-node))\r
+        (let ((key-node (js2-object-prop-node-left node))\r
+              (parent-prop-node (js2-imenu-parent-prop-node node))\r
+              chain)\r
+          (setq chain (nconc (js2-imenu-parent-key-names node)\r
+                             (list (js2-prop-node-name key-node))))\r
+          (push js2-imenu-other-functions-ns chain)\r
+          (js2-record-imenu-entry fn-node chain\r
                                   (js2-node-abs-pos key-node)))))))\r
 \r
 (defun js2-imenu-record-module-pattern (node)\r