;;; js2-mode.el --- Improved JavaScript editing mode
-;; Copyright (C) 2009, 2012 Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2011-2013 Free Software Foundation, Inc.
-;; Author: Steve Yegge <steve.yegge@gmail.com>
-;; Contributors: mooz <stillpedant@gmail.com>
-;; Dmitry Gutov <dgutov@yandex.ru>
-;; Version: See `js2-mode-version'
-;; Keywords: languages, javascript
+;; Author: Steve Yegge <steve.yegge@gmail.com>
+;; mooz <stillpedant@gmail.com>
+;; Dmitry Gutov <dgutov@yandex.ru>
+;; URL: https://github.com/mooz/js2-mode/
+;; http://code.google.com/p/js2-mode/
+;; Version: 20130219
+;; Keywords: languages, javascript
+;; Package-Requires: ((emacs "24.1"))
;; This file is part of GNU Emacs.
;; This JavaScript editing mode supports:
;; - strict recognition of the Ecma-262 language standard
-;; - support for most Rhino and SpiderMonkey extensions from 1.5 to 1.8
+;; - support for most Rhino and SpiderMonkey extensions from 1.5 and up
;; - parsing support for ECMAScript for XML (E4X, ECMA-357)
;; - accurate syntax highlighting using a recursive-descent parser
;; - on-the-fly reporting of syntax errors and strict-mode warnings
;; - show some or all block comments as /*...*/
;; - context-sensitive menu bar and popup menus
;; - code browsing using the `imenu' package
-;; - typing helpers such as automatic insertion of matching braces/parens
;; - many customization options
;; Installation:
;;
;; To install it as your major mode for JavaScript editing:
-;; (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
+;; (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
;; Alternately, to install it as a minor mode just for JavaScript linting,
;; you must add it to the appropriate major-mode hook. Normally this would be:
;; This means that `js2-mode' is currently only useful for editing JavaScript
;; files, and not for editing JavaScript within <script> tags or templates.
+;; The project page on GitHub is used for development and issue tracking.
+;; The original homepage at Google Code is mentioned here for posterity, it has
+;; outdated information and is mostly unmaintained.
+
;;; Code:
(eval-when-compile
(eval-and-compile
(require 'cc-mode) ; (only) for `c-populate-syntax-table'
- (require 'cc-langs) ; it's here in Emacs 21...
(require 'cc-engine)) ; for `c-paragraph-start' et. al.
(defvar electric-layout-rules)
"Mozilla Rhino externs.
Set `js2-include-rhino-externs' to t to include them.")
-(defvar js2-gears-externs
+(defvar js2-node-externs
(mapcar 'symbol-name
- '(
- ;; TODO(stevey): add these
- ))
- "Google Gears externs.
-Set `js2-include-gears-externs' to t to include them.")
+ '(__dirname __filename Buffer clearInterval clearTimeout require
+ console exports global module process setInterval setTimeout))
+ "Node.js externs.
+Set `js2-include-node-externs' to t to include them.")
;;; Variables
:type 'integer)
(js2-mark-safe-local 'js2-basic-offset 'integerp)
-
(defcustom js2-bounce-indent-p nil
"Non-nil to have indent-line function choose among alternatives.
If nil, the indent-line function will indent to a predetermined column
:type 'number
:group 'js2-mode)
-(defcustom js2-mode-escape-quotes t
- "Non-nil to disable automatic quote-escaping inside strings."
- :type 'boolean
- :group 'js2-mode)
-
(defcustom js2-concat-multiline-strings t
"Non-nil to automatically turn a newline in mid-string into a
string concatenation. When `eol', the '+' will be inserted at the
:type '(choice (const t) (const eol) (const nil))
:group 'js2-mode)
-(defcustom js2-mode-squeeze-spaces t
- "Non-nil to normalize whitespace when filling in comments.
-Multiple runs of spaces are converted to a single space."
- :type 'boolean
- :group 'js2-mode)
-
(defcustom js2-mode-show-parse-errors t
"True to highlight parse errors."
:type 'boolean
(defcustom js2-strict-trailing-comma-warning t
"Non-nil to warn about trailing commas in array literals.
-Ecma-262 forbids them, but many browsers permit them. IE is the
-big exception, and can produce bugs if you have trailing commas."
+Ecma-262-5.1 allows them, but older versions of IE raise an error."
:type 'boolean
:group 'js2-mode)
var foo = {int: 5, while: 6, continue: 7};
foo.return = 8;
-Ecma-262 forbids this syntax, but many browsers support it."
+Ecma-262 5.1 allows this syntax, but some engines still don't."
:type 'boolean
:group 'js2-mode)
:type 'boolean
:group 'js2-mode)
-(defvar js2-mode-version 20120416
- "Release number for `js2-mode'.")
-
;; scanner variables
(defmacro js2-deflocal (name value &optional comment)
which only worries about top-level (unqualified) references.
As js2-mode's processing improves, we will flesh out this list.
-The initial value is set to `js2-ecma-262-externs', unless you
-have set `js2-include-browser-externs', in which case the browser
-externs are also included.
+The initial value is set to `js2-ecma-262-externs', unless some
+of the `js2-include-?-externs' variables are set to t, in which
+case the browser, Rhino and/or Node.js externs are also included.
See `js2-additional-externs' for more information.")
"Non-nil to include browser externs in the master externs list.
If you work on JavaScript files that are not intended for browsers,
such as Mozilla Rhino server-side JavaScript, set this to nil.
-You can always include them on a per-file basis by calling
-`js2-add-browser-externs' from a function on `js2-mode-hook'.
-
See `js2-additional-externs' for more information about externs."
:type 'boolean
:group 'js2-mode)
-(defcustom js2-include-rhino-externs t
+(defcustom js2-include-rhino-externs nil
"Non-nil to include Mozilla Rhino externs in the master externs list.
See `js2-additional-externs' for more information about externs."
:type 'boolean
:group 'js2-mode)
-(defcustom js2-include-gears-externs t
- "Non-nil to include Google Gears externs in the master externs list.
+(defcustom js2-include-node-externs nil
+ "Non-nil to include Node.js externs in the master externs list.
See `js2-additional-externs' for more information about externs."
:type 'boolean
:group 'js2-mode)
These should go in `js2-additional-externs', which is buffer-local.
Finally, you can add a function to `js2-post-parse-callbacks',
-which is called after parsing completes, and `root' is bound to
+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
node visitor using `js2-visit-ast' and examine the parse tree
for specific import patterns that may imply the existence of
"Code has no side effects")
(js2-msg "msg.extra.trailing.comma"
- "Trailing comma is not legal in an ECMA-262 object initializer")
+ "Trailing comma is not supported in some browsers")
(js2-msg "msg.array.trailing.comma"
"Trailing comma yields different behavior across browsers")
(t t))))
(defun js2-wrapper-function-p (node)
- "Returns t if NODE is a function expression that's immediately invoked.
+ "Return t if NODE is a function expression that's immediately invoked.
NODE must be `js2-function-node'."
(let ((parent (js2-node-parent node)))
(or
;;; Parser
-(defconst js2-version "1.8.0"
- "Version of JavaScript supported, plus minor js2 version.")
+(defconst js2-version "1.8.5"
+ "Version of JavaScript supported.")
(defmacro js2-record-face (face)
"Record a style run of FACE for the current token."
tt))) ; return unflagged token
(defun js2-peek-flagged-token ()
- "Returns the current token along with any flags set for it."
+ "Return the current token along with any flags set for it."
(js2-peek-token)
js2-current-flagged-token)
(push comment (js2-ast-root-comments root))
(js2-node-add-children root comment)))
(setf (js2-node-len root) (- end pos))
+ (setq js2-mode-ast root) ; Make sure this is available for callbacks.
;; Give extensions a chance to muck with things before highlighting starts.
(let ((js2-additional-externs js2-additional-externs))
(save-excursion
(save-excursion
(back-to-indentation)
(or (js2-looking-at-operator-p)
- (when (js2-re-search-backward "\n" nil t) ;; skip comments
- (skip-chars-backward " \t")
- (unless (bolp) ;; previous line is empty
+ (when (catch 'found
+ (while (and (re-search-backward "\n" nil t)
+ (let ((state (syntax-ppss)))
+ (when (nth 4 state)
+ (goto-char (nth 8 state))) ;; skip comments
+ (skip-chars-backward " \t")
+ (if (bolp)
+ t
+ (throw 'found t))))))
+ (backward-char)
+ (when (js2-looking-at-operator-p)
(backward-char)
- (when (js2-looking-at-operator-p)
- (backward-char)
- (not (looking-at "\\*\\|++\\|--\\|/[/*]"))))))))
+ (not (looking-at "\\*\\|++\\|--\\|/[/*]")))))))
(defun js2-end-of-do-while-loop-p ()
"Return non-nil if word after point is `while' of a do-while
(= (current-indentation) saved-indent))))))))
(defun js2-multiline-decl-indentation ()
- "Returns the declaration indentation column if the current line belongs
+ "Return the declaration indentation column if the current line belongs
to a multiline declaration statement. See `js2-pretty-multiline-declarations'."
(let (forward-sexp-function ; use Lisp version
at-opening-bracket)
;; This has to be set before calling parse-partial-sexp below.
(inhibit-point-motion-hooks t))
(setq parse-status (save-excursion
- (syntax-ppss (point-at-bol)))
+ (syntax-ppss (point-at-bol)))
offset (- (point) (save-excursion
- (back-to-indentation)
- (point))))
+ (back-to-indentation)
+ (point))))
(js2-with-underscore-as-word-syntax
(if (nth 4 parse-status)
(js2-lineup-comment parse-status)
(setq js2-default-externs
(append js2-ecma-262-externs
(if js2-include-browser-externs js2-browser-externs)
- (if js2-include-gears-externs js2-gears-externs)
- (if js2-include-rhino-externs js2-rhino-externs)))
+ (if js2-include-rhino-externs js2-rhino-externs)
+ (if js2-include-node-externs js2-node-externs)))
;; Experiment: make reparse-delay longer for longer files.
(if (plusp js2-dynamic-idle-timer-adjust)
(setq js2-idle-timer-delay
(lst type)
"Add diagnostic TYPE and line number to errs list"
(mapcar (lambda (err)
- (cons err (list type (line-number-at-pos (nth 1 err)))))
+ (list err type (line-number-at-pos (nth 1 err))))
lst)))
(let* ((srcbuf (current-buffer))
(errbuf (get-buffer-create "*js-lint*"))
(let ((inhibit-read-only t))
(erase-buffer)
(dolist (err all-errs)
- (destructuring-bind ((msg-key beg end &rest) . (type line)) err
+ (destructuring-bind ((msg-key beg end &rest) type line) err
(insert-text-button
(format "line %d: %s" line (js2-get-msg msg-key))
'face type
(setq js2-default-externs
(append js2-ecma-262-externs
(if js2-include-browser-externs js2-browser-externs)
- (if js2-include-gears-externs js2-gears-externs)
- (if js2-include-rhino-externs js2-rhino-externs)))
+ (if js2-include-rhino-externs js2-rhino-externs)
+ (if js2-include-node-externs js2-node-externs)))
(setq font-lock-defaults '(nil t))
(js2-time
(setq interrupted-p
(catch 'interrupted
- (setq js2-mode-ast (js2-parse))
+ (js2-parse)
;; if parsing is interrupted, comments and regex
;; literals stay ignored by `parse-partial-sexp'
(remove-text-properties (point-min) (point-max)
"Debugging aid: highlight selected AST node on mouse click."
(interactive "e")
(mouse-set-point event)
- (let ((node (js2-node-at-point))
- beg end)
- (when js2-mode-show-overlay
+ (setq deactivate-mark t)
+ (when js2-mode-show-overlay
+ (let ((node (js2-node-at-point))
+ beg end)
(if (null node)
(message "No node found at location %s" (point))
(setq beg (js2-node-abs-pos node)
(js2-node-short-name (js2-node-parent node))
"nil"))))))
-(put 'js2-mode-show-node 'CUA 'move)
-
(defun js2-mode-hide-overlay (&optional p1 p2)
"Remove the debugging overlay when the point moves.
P1 and P2 are the old and new values of point, respectively."
(and (zerop (forward-line 1))
(looking-at "\\s-*//"))))
(indent-to col)
- (insert "// "))
- ;; Don't need to extend the comment after all.
- (js2-indent-line))))
+ (insert "// ")))
+ ;; Don't need to extend the comment after all.
+ (js2-indent-line)))
(defun js2-beginning-of-line ()
- "Toggles point between bol and first non-whitespace char in line.
+ "Toggle point between bol and first non-whitespace char in line.
Also moves past comment delimiters when inside comments."
(interactive)
(let (node beg)
(goto-char (point-at-bol))))))
(defun js2-end-of-line ()
- "Toggles point between eol and last non-whitespace char in line."
+ "Toggle point between eol and last non-whitespace char in line."
(interactive)
(if (eolp)
(skip-chars-backward " \t")