:type 'string\r
:group 'js2-mode)\r
\r
+(defcustom js2-imenu-show-module-pattern t\r
+ "Non-nil to recognize the module pattern:\r
+\r
+var foobs = (function(a) {\r
+ return {fib: function() {}, fub: function() {}};\r
+})(b);\r
+\r
+We record the returned hash as belonging to the named module, and\r
+prefix any functions defined inside the IIFE with the module name."\r
+ :type 'boolean\r
+ :group 'js2-mode)\r
+\r
(defun js2-imenu-extras-setup ()\r
(when js2-imenu-enabled-frameworks\r
(add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-declarations t))\r
- (when js2-imenu-show-other-functions\r
- (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-hashes t)))\r
+ (when (or js2-imenu-show-other-functions js2-imenu-show-module-pattern)\r
+ (add-to-list 'js2-post-parse-callbacks 'js2-imenu-walk-ast t)))\r
\r
(declare (special root))\r
\r
(js2-compute-nested-prop-get subject)\r
(js2-node-abs-pos methods)))))))\r
\r
-(defun js2-imenu-record-hashes ()\r
+(defun js2-imenu-walk-ast ()\r
(js2-visit-ast\r
root\r
(lambda (node end-p)\r
(unless end-p\r
- (if (and (js2-object-prop-node-p node)\r
- (js2-function-node-p (js2-object-prop-node-right node)))\r
- (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
- (js2-node-abs-pos key-node))))\r
- nil)\r
- t)))))\r
+ (cond\r
+ ((and js2-imenu-show-other-functions\r
+ (js2-object-prop-node-p node))\r
+ (js2-imenu-record-orphan-function node))\r
+ ((and js2-imenu-show-module-pattern\r
+ (js2-assign-node-p node))\r
+ (js2-imenu-record-module-pattern node)))\r
+ t))))\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
+ (when (js2-function-node-p (js2-object-prop-node-right node))\r
+ (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
+ (js2-node-abs-pos key-node)))))))\r
+\r
+(defun js2-imenu-record-module-pattern (node)\r
+ "Recognize and record module pattern use instance.\r
+NODE must be `js2-assign-node'."\r
+ (let ((init (js2-assign-node-right node)))\r
+ (when (js2-call-node-p init)\r
+ (let ((target (js2-assign-node-left node))\r
+ (callt (js2-call-node-target init)))\r
+ ;; Just basic call form: (function() {...})();\r
+ ;; TODO: Handle variations without duplicating `js2-wrapper-function-p'?\r
+ (when (and (js2-paren-node-p callt)\r
+ (js2-function-node-p (js2-paren-node-expr callt)))\r
+ (let* ((fn (js2-paren-node-expr callt))\r
+ (blk (js2-function-node-body fn))\r
+ (ret (car (last (js2-block-node-kids blk)))))\r
+ (when (and (js2-return-node-p ret)\r
+ (js2-object-node-p (js2-return-node-retval ret)))\r
+ ;; TODO: Map function names when revealing module pattern is used.\r
+ (let ((retval (js2-return-node-retval ret)))\r
+ (js2-record-object-literal retval\r
+ (js2-compute-nested-prop-get target)\r
+ (js2-node-abs-pos retval)))\r
+ (js2-record-imenu-functions fn target))))))))\r
\r
(provide 'js2-imenu-extras)\r
(defun js2-record-imenu-functions (node &optional var)
"Record function definitions for imenu.
NODE is a function node or an object literal.
-VAR, if non-nil, is the expression that NODE is being assigned to."
+VAR, if non-nil, is the expression that NODE is being assigned to.
+When passed arguments of wrong type, does nothing."
(when js2-parse-ide-mode
(let ((fun-p (js2-function-node-p node))
qname left fname-node pos)
(append qname (list (js2-infix-node-left e)))
(+ pos (js2-node-pos right)))))))))
-(defun js2-record-assign-functions (init target)
- "Record the functions involved in the assignment for imenu.
-TARGET is the target node, INIT is the value node."
- (cond
- ((or (js2-object-node-p init)
- (js2-function-node-p init))
- (js2-record-imenu-functions init target))
- ((js2-call-node-p init)
- ;; Module pattern: var foobs = (function(a) {return {fib: fun...}})(b);
- ;; We record the returned hash as belonging to the named module, and prefix
- ;; any functions defined inside IIFE with the module name.
- (let ((callt (js2-call-node-target init)))
- ;; Just basic call form: (function() {...})();
- ;; TODO: Handle variations without duplicating `js2-wrapper-function-p'?
- (when (and (js2-paren-node-p callt)
- (js2-function-node-p (js2-paren-node-expr callt)))
- (let* ((fn (js2-paren-node-expr callt))
- (blk (js2-function-node-body fn))
- (ret (car (last (js2-block-node-kids blk)))))
- (when (and (js2-return-node-p ret)
- (js2-object-node-p (js2-return-node-retval ret)))
- ;; TODO: Map function names when revealing module pattern is used.
- (let ((retval (js2-return-node-retval ret)))
- (js2-record-object-literal retval
- (js2-compute-nested-prop-get target)
- (js2-node-abs-pos retval)))
- (js2-record-imenu-functions fn target))))))))
-
(defsubst js2-node-top-level-decl-p (node)
"Return t if NODE's name is defined in the top-level scope.
Also returns t if NODE's name is not defined in any scope, since it implies
(when (js2-match-token js2-ASSIGN)
(setq init (js2-parse-assign-expr)
end (js2-node-end init))
- (when js2-parse-ide-mode
- (js2-record-assign-functions init name)))
+ (js2-record-imenu-functions init name))
(when name
(js2-set-face nbeg nend (if (js2-function-node-p init)
'font-lock-function-name-face
:right right))
(when js2-parse-ide-mode
(js2-highlight-assign-targets pn left right)
- (js2-record-assign-functions right left))
+ (js2-record-imenu-functions right left))
;; do this last so ide checks above can use absolute positions
(js2-node-add-children pn left right))
pn)))