]> code.delx.au - gnu-emacs-elpa/blob - js2-imenu-extras.el
Remove leftover accumulator; require js2-mode
[gnu-emacs-elpa] / js2-imenu-extras.el
1 (eval-when-compile
2 (require 'cl))
3
4 (require 'js2-mode)
5
6 (defconst js2-imenu-extension-styles
7 `((:framework jquery
8 :call-re "\\_<\\(?:jQuery\\|\\$\\|_\\)\\.extend\\s-*("
9 :recorder js2-imenu-record-jquery-extend)
10
11 (:framework jquery-ui
12 :call-re "^\\s-*\\(?:jQuery\\|\\$\\)\\.widget\\s-*("
13 :recorder js2-imenu-record-string-declare)
14
15 (:framework dojo
16 :call-re "^\\s-*dojo.declare\\s-*("
17 :recorder js2-imenu-record-string-declare)
18
19 (:framework backbone
20 :call-re ,(concat "\\_<" js2-mode-identifier-re "\\.extend\\s-*(")
21 :recorder js2-imenu-record-backbone-extend)))
22
23 (defconst js2-imenu-available-frameworks
24 (mapcar (lambda (style) (plist-get style :framework)) js2-imenu-extension-styles)
25 "List of available JavaScript framework symbols.")
26
27 (defcustom js2-imenu-enabled-frameworks js2-imenu-available-frameworks
28 "Frameworks to be recognized by `js2-mode'."
29 :type (cons 'set (mapcar (lambda (x) (list 'const x))
30 js2-imenu-available-frameworks))
31 :group 'js2-mode)
32
33 (defcustom js2-imenu-show-other-functions t
34 "Non-nil to show functions not recognized by other mechanisms,
35 in a shared namespace."
36 :type 'boolean
37 :group 'js2-mode)
38
39 (defcustom js2-imenu-other-functions-ns "?"
40 "Namespace name to use for other functions."
41 :type 'string
42 :group 'js2-mode)
43
44 (defun js2-imenu-extras-setup ()
45 (when js2-imenu-enabled-frameworks
46 (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-declarations t))
47 (when js2-imenu-show-other-functions
48 (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-hashes t)))
49
50 (declare (special root))
51
52 (defun js2-imenu-record-declarations ()
53 (let* ((styles (loop for style in js2-imenu-extension-styles
54 when (memq (plist-get style :framework)
55 js2-imenu-enabled-frameworks)
56 collect style))
57 (re (mapconcat (lambda (style)
58 (concat "\\(" (plist-get style :call-re) "\\)"))
59 styles "\\|"))
60 ;; Dynamic scoping. Ew.
61 (js2-mode-ast root))
62 (goto-char (point-min))
63 (while (js-re-search-forward re nil t)
64 (loop for i from 0 to (1- (length styles))
65 when (match-beginning (1+ i))
66 return (funcall (plist-get (nth i styles) :recorder))))))
67
68 (defun js2-imenu-record-jquery-extend ()
69 (let ((pred (lambda (subject)
70 (and
71 (js2-prop-get-node-p subject)
72 (string= (js2-name-node-name (js2-prop-get-node-right subject))
73 "prototype")))))
74 (js2-imenu-record-extend-first-arg (1- (point)) pred
75 'js2-compute-nested-prop-get)))
76
77 (defun js2-imenu-record-string-declare ()
78 (js2-imenu-record-extend-first-arg
79 (1- (point)) 'js2-string-node-p
80 (lambda (node) (split-string (js2-string-node-value node) "\\." t))))
81
82 (defun js2-imenu-record-extend-first-arg (point pred qname-fn)
83 (let* ((node (js2-node-at-point point))
84 (args (js2-call-node-args node))
85 (subject (first args)))
86 (when (funcall pred subject)
87 (loop for arg in (cdr args)
88 when (js2-object-node-p arg)
89 do (js2-record-object-literal
90 arg (funcall qname-fn subject) (js2-node-abs-pos arg))))))
91
92 (defun js2-imenu-record-backbone-extend ()
93 (let* ((node (js2-node-at-point (1- (point))))
94 (args (js2-call-node-args node))
95 (methods (first args))
96 (parent (js2-node-parent node)))
97 (when (js2-object-node-p methods)
98 (let ((subject (cond ((js2-var-init-node-p parent)
99 (js2-var-init-node-target parent))
100 ((js2-assign-node-p parent)
101 (js2-assign-node-left parent)))))
102 (when subject
103 (js2-record-object-literal methods
104 (js2-compute-nested-prop-get subject)
105 (js2-node-abs-pos methods)))))))
106
107 (defun js2-imenu-record-hashes ()
108 (js2-visit-ast
109 root
110 (lambda (node end-p)
111 (unless end-p
112 (if (and (js2-object-prop-node-p node)
113 (js2-function-node-p (js2-object-prop-node-right node)))
114 (let ((fn-node (js2-object-prop-node-right node)))
115 (unless (and js2-imenu-function-map
116 (gethash fn-node js2-imenu-function-map))
117 (let ((key-node (js2-object-prop-node-left node)))
118 (js2-record-imenu-entry fn-node
119 (list js2-imenu-other-functions-ns
120 (js2-prop-node-name key-node))
121 (js2-node-abs-pos key-node))))
122 nil)
123 t)))))
124
125 (provide 'js2-imenu-extras)