├── .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 | --------------------------------------------------------------------------------