├── .gitignore
├── README.md
└── js2-imenu-extras.el
/.gitignore:
--------------------------------------------------------------------------------
1 | *.elc
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Description
2 | ======
3 |
4 | An improved JavaScript mode for GNU Emacs. Forked from .
5 |
6 | For the list of user-visible changes, see
7 | [Changes from the original mode](https://github.com/mooz/js2-mode/wiki/Changes-from-the-original-mode).
8 |
9 | Installation
10 | ======
11 |
12 | $ git clone git://github.com/mooz/js2-mode.git
13 | $ cd js2-mode
14 | $ emacs --batch -f batch-byte-compile js2-mode.el
15 |
16 | Then put js2-mode.elc into your site-lisp directory.
17 |
18 | In you emacs config:
19 |
20 | (autoload 'js2-mode "js2-mode" nil t)
21 | (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
22 |
23 | See for
24 | additional details.
25 |
26 | Bugs
27 | ====
28 |
29 | If you find problems, please report them at .
30 |
31 | See Also
32 | ======
33 |
34 | Some third-party modes that use the generated syntax tree:
35 |
36 | * [js2-highlight-vars-mode](http://mihai.bazon.net/projects/editing-javascript-with-emacs-js2-mode/js2-highlight-vars-mode)
37 | * [js2-refactor](https://github.com/magnars/js2-refactor.el)
38 |
--------------------------------------------------------------------------------
/js2-imenu-extras.el:
--------------------------------------------------------------------------------
1 | (eval-when-compile
2 | (require 'cl))
3 |
4 | (defconst js2-imenu-extension-styles
5 | `((:framework jquery
6 | :call-re "\\_<\\(?:jQuery\\|\\$\\|_\\)\\.extend\\s-*("
7 | :recorder js2-imenu-record-jquery-extend)
8 |
9 | (:framework jquery-ui
10 | :call-re "^\\s-*\\(?:jQuery\\|\\$\\)\\.widget\\s-*("
11 | :recorder js2-imenu-record-string-declare)
12 |
13 | (:framework dojo
14 | :call-re "^\\s-*dojo.declare\\s-*("
15 | :recorder js2-imenu-record-string-declare)
16 |
17 | (:framework backbone
18 | :call-re ,(concat "\\_<" js2-mode-identifier-re "\\.extend\\s-*(")
19 | :recorder js2-imenu-record-backbone-extend)))
20 |
21 | (defconst js2-imenu-available-frameworks
22 | (mapcar (lambda (style) (plist-get style :framework)) js2-imenu-extension-styles)
23 | "List of available JavaScript framework symbols.")
24 |
25 | (defcustom js2-imenu-enabled-frameworks js2-imenu-available-frameworks
26 | "Frameworks to be recognized by `js2-mode'."
27 | :type (cons 'set (mapcar (lambda (x) (list 'const x))
28 | js2-imenu-available-frameworks))
29 | :group 'js2-mode)
30 |
31 | (defcustom js2-imenu-show-other-functions t
32 | "Non-nil to show functions not recognized by other mechanisms,
33 | in a shared namespace."
34 | :type 'boolean
35 | :group 'js2-mode)
36 |
37 | (defcustom js2-imenu-other-functions-ns "?"
38 | "Namespace name to use for other functions."
39 | :type 'string
40 | :group 'js2-mode)
41 |
42 | (defun js2-imenu-extras-setup ()
43 | (when js2-imenu-enabled-frameworks
44 | (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-declarations t))
45 | (when js2-imenu-show-other-functions
46 | (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-hashes t)))
47 |
48 | (declare (special root))
49 |
50 | (defun js2-imenu-record-declarations ()
51 | (let* ((styles (loop for style in js2-imenu-extension-styles
52 | when (memq (plist-get style :framework)
53 | js2-imenu-enabled-frameworks)
54 | collect style))
55 | (re (mapconcat (lambda (style)
56 | (concat "\\(" (plist-get style :call-re) "\\)"))
57 | styles "\\|"))
58 | ;; Dynamic scoping. Ew.
59 | (js2-mode-ast root)
60 | chains)
61 | (goto-char (point-min))
62 | (while (js-re-search-forward re nil t)
63 | (push (loop for i from 0 to (1- (length styles))
64 | when (match-beginning (1+ i))
65 | return (funcall (plist-get (nth i styles) :recorder)))
66 | chains))
67 | chains))
68 |
69 | (defun js2-imenu-record-jquery-extend ()
70 | (let ((pred (lambda (subject)
71 | (and
72 | (js2-prop-get-node-p subject)
73 | (string= (js2-name-node-name (js2-prop-get-node-right subject))
74 | "prototype")))))
75 | (js2-imenu-record-extend-first-arg (1- (point)) pred
76 | 'js2-compute-nested-prop-get)))
77 |
78 | (defun js2-imenu-record-string-declare ()
79 | (js2-imenu-record-extend-first-arg
80 | (1- (point)) 'js2-string-node-p
81 | (lambda (node) (split-string (js2-string-node-value node) "\\." t))))
82 |
83 | (defun js2-imenu-record-extend-first-arg (point pred qname-fn)
84 | (let* ((node (js2-node-at-point point))
85 | (args (js2-call-node-args node))
86 | (subject (first args)))
87 | (when (funcall pred subject)
88 | (loop for arg in (cdr args)
89 | when (js2-object-node-p arg)
90 | do (js2-record-object-literal
91 | arg (funcall qname-fn subject) (js2-node-abs-pos arg))))))
92 |
93 | (defun js2-imenu-record-backbone-extend ()
94 | (let* ((node (js2-node-at-point (1- (point))))
95 | (args (js2-call-node-args node))
96 | (methods (first args))
97 | (parent (js2-node-parent node)))
98 | (when (js2-object-node-p methods)
99 | (let ((subject (cond ((js2-var-init-node-p parent)
100 | (js2-var-init-node-target parent))
101 | ((js2-assign-node-p parent)
102 | (js2-assign-node-left parent)))))
103 | (when subject
104 | (js2-record-object-literal methods
105 | (js2-compute-nested-prop-get subject)
106 | (js2-node-abs-pos methods)))))))
107 |
108 | (defun js2-imenu-record-hashes ()
109 | (js2-visit-ast
110 | root
111 | (lambda (node end-p)
112 | (unless end-p
113 | (if (and (js2-object-prop-node-p node)
114 | (js2-function-node-p (js2-object-prop-node-right node)))
115 | (let ((fn-node (js2-object-prop-node-right node)))
116 | (unless (and js2-imenu-function-map
117 | (gethash fn-node js2-imenu-function-map))
118 | (let ((key-node (js2-object-prop-node-left node)))
119 | (js2-record-imenu-entry fn-node
120 | (list js2-imenu-other-functions-ns
121 | (js2-prop-node-name key-node))
122 | (js2-node-abs-pos key-node))))
123 | nil)
124 | t)))))
125 |
126 | (provide 'js2-imenu-extras)
127 |
--------------------------------------------------------------------------------