emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[ELPA-diffs] /srv/bzr/emacs/elpa r399: js2-mode: Merge from upstream


From: Dmitry Gutov
Subject: [ELPA-diffs] /srv/bzr/emacs/elpa r399: js2-mode: Merge from upstream
Date: Fri, 10 May 2013 19:24:05 +0400
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 399
committer: Dmitry Gutov <address@hidden>
branch nick: elpa
timestamp: Fri 2013-05-10 19:24:05 +0400
message:
  js2-mode: Merge from upstream
  
  * js2-imenu-extras: New file.
  
  Git commit 3c69aea0c267e7bbadd5e35eb6cab54764c9d91c
added:
  packages/js2-mode/js2-imenu-extras.el
modified:
  packages/js2-mode/js2-mode.el
=== added file 'packages/js2-mode/js2-imenu-extras.el'
--- a/packages/js2-mode/js2-imenu-extras.el     1970-01-01 00:00:00 +0000
+++ b/packages/js2-mode/js2-imenu-extras.el     2013-05-10 15:24:05 +0000
@@ -0,0 +1,222 @@
+;;; js2-imenu-extras.el --- Imenu support for additional constructs
+
+;; Copyright (C) 2012-2013  Free Software Foundation, Inc.
+
+;; Author:    Dmitry Gutov <address@hidden>
+;; Keywords:  languages, javascript, imenu
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package adds Imenu support for additional framework constructs and
+;; structural patterns to `js2-mode'.
+
+;; Usage:
+
+;; (add-hook 'js2-mode-hook 'js2-imenu-extras-mode)
+
+;; To customize how it works:
+;;   M-x customize-group RET js2-imenu RET
+
+(eval-when-compile
+  (require 'cl))
+
+(require 'js2-mode)
+
+(defconst js2-imenu-extension-styles
+  `((:framework jquery
+     :call-re   "\\_<\\(?:jQuery\\|\\$\\|_\\)\\.extend\\s-*("
+     :recorder  js2-imenu-record-jquery-extend)
+
+    (:framework jquery-ui
+     :call-re   "^\\s-*\\(?:jQuery\\|\\$\\)\\.widget\\s-*("
+     :recorder  js2-imenu-record-string-declare)
+
+    (:framework dojo
+     :call-re   "^\\s-*dojo.declare\\s-*("
+     :recorder  js2-imenu-record-string-declare)
+
+    (:framework backbone
+     :call-re   ,(concat "\\_<" js2-mode-identifier-re "\\.extend\\s-*(")
+     :recorder  js2-imenu-record-backbone-extend))
+  "List of JavaScript class definition or extension styles.
+
+:framework is a valid value in `js2-imenu-enabled-frameworks'.
+
+:call-re is a regular expression that has no capturing groups.
+
+:recorder is a function name that will be called when the regular
+expression matches some text in the buffer.  When it's called, point will be
+at the end of the match.  The function must keep the point position.")
+
+(defconst js2-imenu-available-frameworks
+  (mapcar (lambda (style) (plist-get style :framework)) 
js2-imenu-extension-styles)
+  "List of available JavaScript framework symbols.")
+
+(defcustom js2-imenu-enabled-frameworks js2-imenu-available-frameworks
+  "Frameworks to be recognized by `js2-mode'."
+  :type (cons 'set (mapcar (lambda (x) (list 'const x))
+                           js2-imenu-available-frameworks))
+  :group 'js2-imenu)
+
+(defcustom js2-imenu-show-other-functions t
+  "Non-nil to show functions not recognized by other mechanisms,
+in a shared namespace."
+  :type 'boolean
+  :group 'js2-imenu)
+
+(defcustom js2-imenu-other-functions-ns "?"
+  "Namespace name to use for other functions."
+  :type 'string
+  :group 'js2-imenu)
+
+(defcustom js2-imenu-show-module-pattern t
+  "Non-nil to recognize the module pattern:
+
+var foobs = (function(a) {
+  return {fib: function() {}, fub: function() {}};
+})(b);
+
+We record the returned hash as belonging to the named module, and
+prefix any functions defined inside the IIFE with the module name."
+  :type 'boolean
+  :group 'js2-imenu)
+
+;;;###autoload
+(defun js2-imenu-extras-setup ()
+  (when js2-imenu-enabled-frameworks
+    (add-hook 'js2-post-parse-callbacks 'js2-imenu-record-declarations t t))
+  (when (or js2-imenu-show-other-functions js2-imenu-show-module-pattern)
+    (add-hook 'js2-post-parse-callbacks 'js2-imenu-walk-ast t t)))
+
+(defun js2-imenu-extras-remove ()
+  (remove-hook 'js2-post-parse-callbacks 'js2-imenu-record-declarations t)
+  (remove-hook 'js2-post-parse-callbacks 'js2-imenu-walk-ast t))
+
+(defun js2-imenu-record-declarations ()
+  (let* ((styles (loop for style in js2-imenu-extension-styles
+                       when (memq (plist-get style :framework)
+                                  js2-imenu-enabled-frameworks)
+                       collect style))
+         (re (mapconcat (lambda (style)
+                          (concat "\\(" (plist-get style :call-re) "\\)"))
+                        styles "\\|")))
+    (goto-char (point-min))
+    (while (js2-re-search-forward re nil t)
+      (loop for i from 0 to (1- (length styles))
+            when (match-beginning (1+ i))
+            return (funcall (plist-get (nth i styles) :recorder))))))
+
+(defun js2-imenu-record-jquery-extend ()
+  (let ((pred (lambda (subject)
+                (and
+                 (js2-prop-get-node-p subject)
+                 (string= (js2-name-node-name (js2-prop-get-node-right 
subject))
+                          "prototype")))))
+    (js2-imenu-record-extend-first-arg (1- (point)) pred
+                                       'js2-compute-nested-prop-get)))
+
+(defun js2-imenu-record-string-declare ()
+  (js2-imenu-record-extend-first-arg
+   (1- (point)) 'js2-string-node-p
+   (lambda (node) (split-string (js2-string-node-value node) "\\." t))))
+
+(defun js2-imenu-record-extend-first-arg (point pred qname-fn)
+  (let* ((node (js2-node-at-point point))
+         (args (js2-call-node-args node))
+         (subject (first args)))
+    (when (funcall pred subject)
+      (loop for arg in (cdr args)
+            when (js2-object-node-p arg)
+            do (js2-record-object-literal
+                arg (funcall qname-fn subject) (js2-node-abs-pos arg))))))
+
+(defun js2-imenu-record-backbone-extend ()
+  (let* ((node (js2-node-at-point (1- (point))))
+         (args (js2-call-node-args node))
+         (methods (first args))
+         (parent (js2-node-parent node)))
+    (when (js2-object-node-p methods)
+      (let ((subject (cond ((js2-var-init-node-p parent)
+                            (js2-var-init-node-target parent))
+                           ((js2-assign-node-p parent)
+                            (js2-assign-node-left parent)))))
+        (when subject
+          (js2-record-object-literal methods
+                                     (js2-compute-nested-prop-get subject)
+                                     (js2-node-abs-pos methods)))))))
+
+(defun js2-imenu-walk-ast ()
+  (js2-visit-ast
+   js2-mode-ast
+   (lambda (node end-p)
+     (unless end-p
+       (cond
+        ((and js2-imenu-show-other-functions
+              (js2-object-prop-node-p node))
+         (js2-imenu-record-orphan-function node))
+        ((and js2-imenu-show-module-pattern
+              (js2-assign-node-p node))
+         (js2-imenu-record-module-pattern node)))
+       t))))
+
+(defun js2-imenu-record-orphan-function (node)
+  "Record orphan function when it's the value of NODE.
+NODE must be `js2-object-prop-node'."
+  (when (js2-function-node-p (js2-object-prop-node-right node))
+    (let ((fn-node (js2-object-prop-node-right node)))
+      (unless (and js2-imenu-function-map
+                   (gethash fn-node js2-imenu-function-map))
+        (let ((key-node (js2-object-prop-node-left node)))
+          (js2-record-imenu-entry fn-node
+                                  (list js2-imenu-other-functions-ns
+                                        (js2-prop-node-name key-node))
+                                  (js2-node-abs-pos key-node)))))))
+
+(defun js2-imenu-record-module-pattern (node)
+  "Recognize and record module pattern use instance.
+NODE must be `js2-assign-node'."
+  (let ((init (js2-assign-node-right node)))
+    (when (js2-call-node-p init)
+      (let ((target (js2-assign-node-left node))
+            (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))
+                    (target-qname (js2-compute-nested-prop-get target)))
+                (js2-record-object-literal retval target-qname
+                                           (js2-node-abs-pos retval))
+                (js2-record-imenu-entry fn target-qname
+                                        (js2-node-abs-pos target))))))))))
+
+;;;###autoload
+(define-minor-mode js2-imenu-extras-mode
+  "Toggle Imenu support for frameworks and structural patterns."
+  :lighter ""
+  (if js2-imenu-extras-mode
+      (js2-imenu-extras-setup)
+    (js2-imenu-extras-remove)))
+
+(provide 'js2-imenu-extras)

=== modified file 'packages/js2-mode/js2-mode.el'
--- a/packages/js2-mode/js2-mode.el     2013-03-07 15:58:17 +0000
+++ b/packages/js2-mode/js2-mode.el     2013-05-10 15:24:05 +0000
@@ -7,7 +7,7 @@
 ;;         Dmitry Gutov <address@hidden>
 ;; URL:  https://github.com/mooz/js2-mode/
 ;;       http://code.google.com/p/js2-mode/
-;; Version: 20130307
+;; Version: 20130510
 ;; Keywords: languages, javascript
 ;; Package-Requires: ((emacs "24.1"))
 
@@ -56,6 +56,10 @@
 
 ;;   (add-hook 'js-mode-hook 'js2-minor-mode)
 
+;; You may also want to hook it in for shell scripts running via node.js:
+
+;;   (add-to-list 'interpreter-mode-alist '("node" . js2-mode))
+
 ;; To customize how it works:
 ;;   M-x customize-group RET js2-mode RET
 
@@ -165,7 +169,10 @@
             DocumentRange Range RangeException
 
             ;; W3C XML
-            XPathResult XMLHttpRequest))
+            XPathResult XMLHttpRequest
+
+            ;; console object.  Provided by at least Chrome and Firefox.
+            console))
   "Browser externs.
 You can cause these to be included or excluded with the custom
 variable `js2-include-browser-externs'.")
@@ -187,6 +194,15 @@
   "Node.js externs.
 Set `js2-include-node-externs' to t to include them.")
 
+(defvar js2-typed-array-externs
+  (mapcar 'symbol-name
+          '(ArrayBuffer Uint8ClampedArray DataView
+            Int8Array Uint8Array Int16Array Uint16Array Int32Array Uint32Array
+            Float32Array Float64Array))
+  "Khronos typed array externs. Available in most modern browsers and
+in node.js >= 0.6. If `js2-include-node-externs' or 
`js2-include-browser-externs'
+are enabled, these will also be included.")
+
 ;;; Variables
 
 (defun js2-mark-safe-local (name pred)
@@ -842,6 +858,9 @@
 externs appropriate for the specific file, perhaps based on its path.
 These should go in `js2-additional-externs', which is buffer-local.
 
+Third, you can use JSLint's global declaration, as long as
+`js2-include-jslint-globals' is non-nil, which see.
+
 Finally, you can add a function to `js2-post-parse-callbacks',
 which is called after parsing completes, and `js2-mode-ast' is bound to
 the root of the parse tree.  At this stage you can set up an AST
@@ -1090,8 +1109,11 @@
   :type 'boolean
   :group 'js2-mode)
 
-(defcustom js2-auto-insert-catch-block t
-  "Non-nil to insert matching catch block on open-curly after `try'."
+(defcustom js2-include-jslint-globals t
+  "Non-nil to include the identifiers from JSLint global
+declaration (see http://www.jslint.com/lint.html#global) in the
+buffer-local externs list.  See `js2-additional-externs' for more
+information."
   :type 'boolean
   :group 'js2-mode)
 
@@ -4601,7 +4623,7 @@
         (let ((expr (js2-expr-stmt-node-expr node)))
           (or (js2-node-has-side-effects expr)
               (when (js2-string-node-p expr)
-                (string= "use strict" (js2-string-node-value expr))))))
+                (member (js2-string-node-value expr) '("use strict" "use 
asm"))))))
        ((= tt js2-COMMA)
         (js2-node-has-side-effects (js2-infix-node-right node)))
        ((or (= tt js2-AND)
@@ -6402,6 +6424,42 @@
                               'js2-external-variable))))
     (setq js2-recorded-identifiers nil)))
 
+(defun js2-set-default-externs ()
+  "Set the value of `js2-default-externs' based on the various
+`js2-include-?-externs' variables."
+  (setq js2-default-externs
+        (append js2-ecma-262-externs
+                (if js2-include-browser-externs js2-browser-externs)
+                (if js2-include-rhino-externs js2-rhino-externs)
+                (if js2-include-node-externs js2-node-externs)
+                (if (or js2-include-browser-externs js2-include-node-externs)
+                    js2-typed-array-externs))))
+
+(defun js2-apply-jslint-globals ()
+  (setq js2-additional-externs
+        (nconc (js2-get-jslint-globals)
+               js2-additional-externs)))
+
+(defun js2-get-jslint-globals ()
+  (loop for node in (js2-ast-root-comments js2-mode-ast)
+        when (and (eq 'block (js2-comment-node-format node))
+                  (save-excursion
+                    (goto-char (js2-node-abs-pos node))
+                    (looking-at "/\\*global ")))
+        append (js2-get-jslint-globals-in
+                (match-end 0)
+                (js2-node-abs-end node))))
+
+(defun js2-get-jslint-globals-in (beg end)
+  (let (res)
+    (save-excursion
+      (goto-char beg)
+      (while (re-search-forward js2-mode-identifier-re end t)
+        (let ((match (match-string 0)))
+          (unless (member match '("true" "false"))
+            (push match res)))))
+    (nreverse res)))
+
 ;;; IMenu support
 
 ;; We currently only support imenu, but eventually should support speedbar and
@@ -7109,8 +7167,7 @@
     ;; Give extensions a chance to muck with things before highlighting starts.
     (let ((js2-additional-externs js2-additional-externs))
       (save-excursion
-        (dolist (callback js2-post-parse-callbacks)
-          (funcall callback)))
+        (run-hooks 'js2-post-parse-callbacks))
       (js2-highlight-undeclared-vars))
     root))
 
@@ -9593,11 +9650,10 @@
                         (js2-backward-sws)
                         (or (eq (char-before) ?,)
                             (and (not (eq (char-before) ?\;))
-                                 (and
-                                  (prog2 (skip-syntax-backward ".")
-                                      (looking-at js2-indent-operator-re)
-                                    (js2-backward-sws))
-                                  (not (eq (char-before) ?\;))))
+                                 (prog2 (skip-syntax-backward ".")
+                                     (looking-at js2-indent-operator-re)
+                                   (js2-backward-sws))
+                                 (not (eq (char-before) ?\;)))
                             (js2-same-line pos)))))
           (condition-case err
               (backward-sexp)
@@ -10043,11 +10099,7 @@
   (set (make-local-variable 'max-lisp-eval-depth)
        (max max-lisp-eval-depth 3000))
   (setq next-error-function #'js2-next-error)
-  (setq js2-default-externs
-        (append js2-ecma-262-externs
-                (if js2-include-browser-externs js2-browser-externs)
-                (if js2-include-rhino-externs js2-rhino-externs)
-                (if js2-include-node-externs js2-node-externs)))
+  (js2-set-default-externs)
   ;; Experiment:  make reparse-delay longer for longer files.
   (if (plusp js2-dynamic-idle-timer-adjust)
       (setq js2-idle-timer-delay
@@ -10058,6 +10110,8 @@
   (set (make-local-variable 'js2-highlight-level) 0) ; no syntax highlighting
   (add-hook 'after-change-functions #'js2-minor-mode-edit nil t)
   (add-hook 'change-major-mode-hook #'js2-minor-mode-exit nil t)
+  (when js2-include-jslint-globals
+    (add-hook 'js2-post-parse-callbacks 'js2-apply-jslint-globals nil t))
   (js2-reparse))
 
 (defun js2-minor-mode-exit ()
@@ -10069,6 +10123,7 @@
     (delete-overlay js2-mode-node-overlay)
     (setq js2-mode-node-overlay nil))
   (js2-remove-overlays)
+  (remove-hook 'js2-post-parse-callbacks 'js2-apply-jslint-globals t)
   (setq js2-mode-ast nil))
 
 (defvar js2-source-buffer nil "Linked source buffer for diagnostics view")
@@ -10228,12 +10283,6 @@
     (make-local-variable 'adaptive-fill-regexp)
     (c-setup-paragraph-variables))
 
-  (setq js2-default-externs
-        (append js2-ecma-262-externs
-                (if js2-include-browser-externs js2-browser-externs)
-                (if js2-include-rhino-externs js2-rhino-externs)
-                (if js2-include-node-externs js2-node-externs)))
-
   (setq font-lock-defaults '(nil t))
 
   ;; Experiment:  make reparse-delay longer for longer files.
@@ -10255,6 +10304,12 @@
         js2-mode-comments-hidden nil
         js2-mode-buffer-dirty-p t
         js2-mode-parsing nil)
+
+  (js2-set-default-externs)
+
+  (when js2-include-jslint-globals
+    (add-hook 'js2-post-parse-callbacks 'js2-apply-jslint-globals nil t))
+
   (js2-reparse))
 
 (defun js2-mode-exit ()


reply via email to

[Prev in Thread] Current Thread [Next in Thread]