[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master 54df259 22/22: Merge commit 'ac93b9eef9b6ac44d187b9688d68a
From: |
Dmitry Gutov |
Subject: |
[elpa] master 54df259 22/22: Merge commit 'ac93b9eef9b6ac44d187b9688d68a7a5f205b3fe' from js2-mode |
Date: |
Fri, 24 Apr 2015 02:57:17 +0000 |
branch: master
commit 54df2598550c8040def7aec80d04847458d990df
Merge: c10ba4b ac93b9e
Author: Dmitry Gutov <address@hidden>
Commit: Dmitry Gutov <address@hidden>
Merge commit 'ac93b9eef9b6ac44d187b9688d68a7a5f205b3fe' from js2-mode
Conflicts:
packages/js2-mode/js2-mode.el
---
packages/js2-mode/js2-mode.el | 362 ++++++++++++++++++++++---------------
packages/js2-mode/tests/indent.el | 45 ++++-
packages/js2-mode/tests/parser.el | 39 ++++
3 files changed, 295 insertions(+), 151 deletions(-)
diff --git a/packages/js2-mode/js2-mode.el b/packages/js2-mode/js2-mode.el
index 5bc0770..4fc2823 100644
--- a/packages/js2-mode/js2-mode.el
+++ b/packages/js2-mode/js2-mode.el
@@ -263,14 +263,37 @@ js2-mode also binds `js2-bounce-indent-backwards' to
Shift-Tab."
b = 20,
c = 30;
-If the value is not `all', and the first assigned value in
+If the value is t, and the first assigned value in the
declaration is a function/array/object literal spanning several
lines, it won't be indented additionally:
var o = { var bar = 2,
foo: 3 vs. o = {
}, foo: 3
- bar = 2; };"
+ bar = 2; };
+
+If the value is `all', it will always be indented additionally:
+
+ var o = {
+ foo: 3
+ };
+
+ var o = {
+ foo: 3
+ },
+ bar = 2;
+
+If the value is `dynamic', it will be indented additionally only
+if the declaration contains more than one variable:
+
+ var o = {
+ foo: 3
+ };
+
+ var o = {
+ foo: 3
+ },
+ bar = 2;"
:group 'js2-mode
:type 'symbol)
(js2-mark-safe-local 'js2-pretty-multiline-declarations 'symbolp)
@@ -650,11 +673,10 @@ which doesn't seem particularly useful, but Rhino permits
it."
(defvar js2-ARROW 162) ; function arrow (=>)
(defvar js2-CLASS 163)
(defvar js2-EXTENDS 164)
-(defvar js2-STATIC 165)
-(defvar js2-SUPER 166)
-(defvar js2-TEMPLATE_HEAD 167) ; part of template literal before
substitution
-(defvar js2-NO_SUBS_TEMPLATE 168) ; template literal without substitutions
-(defvar js2-TAGGED_TEMPLATE 169) ; tagged template literal
+(defvar js2-SUPER 165)
+(defvar js2-TEMPLATE_HEAD 166) ; part of template literal before
substitution
+(defvar js2-NO_SUBS_TEMPLATE 167) ; template literal without substitutions
+(defvar js2-TAGGED_TEMPLATE 168) ; tagged template literal
(defconst js2-num-tokens (1+ js2-TAGGED_TEMPLATE))
@@ -1274,6 +1296,7 @@ First match-group is the leading whitespace.")
(defvar js2-mode-syntax-table
(let ((table (make-syntax-table)))
(c-populate-syntax-table table)
+ (modify-syntax-entry ?` "\"" table)
table)
"Syntax table used in `js2-mode' buffers.")
@@ -1384,7 +1407,7 @@ the correct number of ARGS must be provided."
"Invalid assignment left-hand side.")
(js2-msg "msg.bad.decr"
- "Invalid decerement operand.")
+ "Invalid decrement operand.")
(js2-msg "msg.bad.incr"
"Invalid increment operand.")
@@ -2308,24 +2331,29 @@ If any given node in NODES is nil, doesn't record that
link."
(defun js2-node-get-enclosing-scope (node)
"Return the innermost `js2-scope' node surrounding NODE.
Returns nil if there is no enclosing scope node."
- (let ((parent (js2-node-parent node)))
- (while (not (js2-scope-p parent))
- (setq parent (js2-node-parent parent)))
- parent))
+ (while (and (setq node (js2-node-parent node))
+ (not (js2-scope-p node))))
+ node)
-(defun js2-get-defining-scope (scope name)
+(defun js2-get-defining-scope (scope name &optional point)
"Search up scope chain from SCOPE looking for NAME, a string or symbol.
-Returns `js2-scope' in which NAME is defined, or nil if not found."
+Returns `js2-scope' in which NAME is defined, or nil if not found.
+
+If POINT is non-nil, and if the found declaration type is
+`js2-LET', also check that the declaration node is before POINT."
(let ((sym (if (symbolp name)
name
(intern name)))
- table
result
(continue t))
(while (and scope continue)
(if (or
- (and (setq table (js2-scope-symbol-table scope))
- (assq sym table))
+ (let ((entry (cdr (assq sym (js2-scope-symbol-table scope)))))
+ (and entry
+ (or (not point)
+ (not (eq js2-LET (js2-symbol-decl-type entry)))
+ (>= point
+ (js2-node-abs-pos (js2-symbol-ast-node entry))))))
(and (eq sym 'arguments)
(js2-function-node-p scope)))
(setq continue nil
@@ -5360,7 +5388,7 @@ Returns logical OR of END_* flags."
(let* ((rv js2-END_DROPS_OFF)
(kids (js2-block-node-kids node))
(n (car kids)))
- ;; Check each statment. If the statement can continue onto the next
+ ;; Check each statement. If the statement can continue onto the next
;; one (i.e. END_DROPS_OFF is set), then check the next statement.
(while (and n (js2-flag-set-p rv js2-END_DROPS_OFF))
(js2-clear-flag rv js2-END_DROPS_OFF)
@@ -5684,7 +5712,7 @@ into temp buffers."
let
new null
return
- static super switch
+ super switch
this throw true try typeof
var void
while with
@@ -5705,7 +5733,7 @@ into temp buffers."
js2-LET
js2-NEW js2-NULL
js2-RETURN
- js2-STATIC js2-SUPER js2-SWITCH
+ js2-SUPER js2-SWITCH
js2-THIS js2-THROW js2-TRUE js2-TRY js2-TYPEOF
js2-VAR
js2-WHILE js2-WITH
@@ -5730,7 +5758,7 @@ The values are default faces to use for highlighting the
keywords.")
;; FIXME: Support strict mode-only future reserved words, after we know
;; which parts scopes are in strict mode, and which are not.
-(defconst js2-reserved-words '(class enum export extends import super)
+(defconst js2-reserved-words '(class enum export extends import static super)
"Future reserved keywords in ECMAScript 5.1.")
(defconst js2-keyword-names
@@ -6158,8 +6186,11 @@ its relevant fields and puts it into `js2-ti-tokens'."
(setf (js2-token-beg token) (- js2-ts-cursor 2))
(js2-skip-line)
(setf (js2-token-comment-type token) 'line)
- ;; include newline so highlighting goes to end of
window
- (cl-incf (js2-token-end token))
+ ;; include newline so highlighting goes to end of
+ ;; window, if there actually is a newline; if we
+ ;; hit eof, then implicitly there isn't
+ (unless js2-ts-hit-eof
+ (cl-incf (js2-token-end token)))
(throw 'return js2-COMMENT))
;; is it a /* comment?
(when (js2-match-char ?*)
@@ -6774,7 +6805,7 @@ Shown at or above `js2-highlight-level' 3.")
(defun js2-parse-highlight-member-expr-node (node)
"Perform syntax highlighting of EcmaScript built-in properties.
-The variable `js2-highlight-level' governs this highighting."
+The variable `js2-highlight-level' governs this highlighting."
(let (face target prop name pos end parent call-p callee)
(cond
;; case 1: simple name, e.g. foo
@@ -7035,7 +7066,7 @@ it is considered declared."
(unless (or (member name js2-global-externs)
(member name js2-default-externs)
(member name js2-additional-externs)
- (js2-get-defining-scope scope name))
+ (js2-get-defining-scope scope name pos))
(js2-report-warning "msg.undeclared.variable" name pos (- end pos)
'js2-external-variable))))
(setq js2-recorded-identifiers nil)))
@@ -8089,7 +8120,8 @@ node are given relative start positions and correct
lengths."
js2-ERROR
js2-SEMI
js2-CLASS
- js2-FUNCTION)
+ js2-FUNCTION
+ js2-EXPORT)
"List of tokens that don't do automatic semicolon insertion.")
(defconst js2-autoinsert-semi-and-warn
@@ -8524,9 +8556,13 @@ invalid export statements."
(when from-clause
(push from-clause children))
(when declaration
- (push declaration children))
+ (push declaration children)
+ (when (not (js2-function-node-p declaration))
+ (js2-auto-insert-semicolon declaration)))
(when default
- (push default children))
+ (push default children)
+ (when (not (js2-function-node-p default))
+ (js2-auto-insert-semicolon default)))
(let ((node (make-js2-export-node
:pos beg
:len (- (js2-current-token-end) beg)
@@ -8541,6 +8577,7 @@ invalid export statements."
"Parse a for, for-in or for each-in statement.
Last matched token must be js2-FOR."
(let ((for-pos (js2-current-token-beg))
+ (tmp-scope (make-js2-scope))
pn is-for-each is-for-in-or-of is-for-of
in-pos each-pos tmp-pos
init ; Node init is also foo in 'foo in object'.
@@ -8558,78 +8595,83 @@ Last matched token must be js2-FOR."
(if (js2-must-match js2-LP "msg.no.paren.for")
(setq lp (- (js2-current-token-beg) for-pos)))
(setq tt (js2-get-token))
- ;; 'for' makes local scope
- (js2-push-scope (make-js2-scope))
+ ;; Capture identifiers inside parens. We can't create the node
+ ;; (and use it as the current scope) until we know its type.
+ (js2-push-scope tmp-scope)
(unwind-protect
- ;; parse init clause
- (let ((js2-in-for-init t)) ; set as dynamic variable
- (cond
- ((= tt js2-SEMI)
- (js2-unget-token)
- (setq init (make-js2-empty-expr-node)))
- ((or (= tt js2-VAR) (= tt js2-LET))
- (setq init (js2-parse-variables tt (js2-current-token-beg))))
- (t
- (js2-unget-token)
- (setq init (js2-parse-expr)))))
- (if (or (js2-match-token js2-IN)
- (and (>= js2-language-version 200)
- (js2-match-contextual-kwd "of")
- (setq is-for-of t)))
- (setq is-for-in-or-of t
- in-pos (- (js2-current-token-beg) for-pos)
- ;; scope of iteration target object is not the scope we've
created above.
- ;; stash current scope temporary.
- cond (let ((js2-current-scope (js2-scope-parent-scope
js2-current-scope)))
- (js2-parse-expr))) ; object over which we're iterating
- ;; else ordinary for loop - parse cond and incr
- (js2-must-match js2-SEMI "msg.no.semi.for")
- (setq cond (if (= (js2-peek-token) js2-SEMI)
- (make-js2-empty-expr-node) ; no loop condition
- (js2-parse-expr)))
- (js2-must-match js2-SEMI "msg.no.semi.for.cond")
- (setq tmp-pos (js2-current-token-end)
- incr (if (= (js2-peek-token) js2-RP)
- (make-js2-empty-expr-node :pos tmp-pos)
- (js2-parse-expr))))
- (if (js2-must-match js2-RP "msg.no.paren.for.ctrl")
- (setq rp (- (js2-current-token-beg) for-pos)))
- (if (not is-for-in-or-of)
- (setq pn (make-js2-for-node :init init
- :condition cond
- :update incr
- :lp lp
- :rp rp))
- ;; cond could be null if 'in obj' got eaten by the init node.
- (if (js2-infix-node-p init)
- ;; it was (foo in bar) instead of (var foo in bar)
- (setq cond (js2-infix-node-right init)
- init (js2-infix-node-left init))
- (if (and (js2-var-decl-node-p init)
- (> (length (js2-var-decl-node-kids init)) 1))
- (js2-report-error "msg.mult.index")))
- (setq pn (make-js2-for-in-node :iterator init
- :object cond
- :in-pos in-pos
- :foreach-p is-for-each
- :each-pos each-pos
- :forof-p is-for-of
- :lp lp
- :rp rp)))
- (unwind-protect
- (progn
- (js2-enter-loop pn)
- ;; We have to parse the body -after- creating the loop node,
- ;; so that the loop node appears in the js2-loop-set, allowing
- ;; break/continue statements to find the enclosing loop.
- (setf body (js2-parse-statement)
- (js2-loop-node-body pn) body
- (js2-node-pos pn) for-pos
- (js2-node-len pn) (- (js2-node-end body) for-pos))
- (js2-node-add-children pn init cond incr body))
- ;; finally
- (js2-exit-loop))
+ (progn
+ ;; parse init clause
+ (let ((js2-in-for-init t)) ; set as dynamic variable
+ (cond
+ ((= tt js2-SEMI)
+ (js2-unget-token)
+ (setq init (make-js2-empty-expr-node)))
+ ((or (= tt js2-VAR) (= tt js2-LET))
+ (setq init (js2-parse-variables tt (js2-current-token-beg))))
+ (t
+ (js2-unget-token)
+ (setq init (js2-parse-expr)))))
+ (if (or (js2-match-token js2-IN)
+ (and (>= js2-language-version 200)
+ (js2-match-contextual-kwd "of")
+ (setq is-for-of t)))
+ (setq is-for-in-or-of t
+ in-pos (- (js2-current-token-beg) for-pos)
+ ;; scope of iteration target object is not the scope we've
created above.
+ ;; stash current scope temporary.
+ cond (let ((js2-current-scope (js2-scope-parent-scope
js2-current-scope)))
+ (js2-parse-expr))) ; object over which we're
iterating
+ ;; else ordinary for loop - parse cond and incr
+ (js2-must-match js2-SEMI "msg.no.semi.for")
+ (setq cond (if (= (js2-peek-token) js2-SEMI)
+ (make-js2-empty-expr-node) ; no loop condition
+ (js2-parse-expr)))
+ (js2-must-match js2-SEMI "msg.no.semi.for.cond")
+ (setq tmp-pos (js2-current-token-end)
+ incr (if (= (js2-peek-token) js2-RP)
+ (make-js2-empty-expr-node :pos tmp-pos)
+ (js2-parse-expr)))))
(js2-pop-scope))
+ (if (js2-must-match js2-RP "msg.no.paren.for.ctrl")
+ (setq rp (- (js2-current-token-beg) for-pos)))
+ (if (not is-for-in-or-of)
+ (setq pn (make-js2-for-node :init init
+ :condition cond
+ :update incr
+ :lp lp
+ :rp rp))
+ ;; cond could be null if 'in obj' got eaten by the init node.
+ (if (js2-infix-node-p init)
+ ;; it was (foo in bar) instead of (var foo in bar)
+ (setq cond (js2-infix-node-right init)
+ init (js2-infix-node-left init))
+ (if (and (js2-var-decl-node-p init)
+ (> (length (js2-var-decl-node-kids init)) 1))
+ (js2-report-error "msg.mult.index")))
+ (setq pn (make-js2-for-in-node :iterator init
+ :object cond
+ :in-pos in-pos
+ :foreach-p is-for-each
+ :each-pos each-pos
+ :forof-p is-for-of
+ :lp lp
+ :rp rp)))
+ ;; Transplant the declarations.
+ (setf (js2-scope-symbol-table pn)
+ (js2-scope-symbol-table tmp-scope))
+ (unwind-protect
+ (progn
+ (js2-enter-loop pn)
+ ;; We have to parse the body -after- creating the loop node,
+ ;; so that the loop node appears in the js2-loop-set, allowing
+ ;; break/continue statements to find the enclosing loop.
+ (setf body (js2-parse-statement)
+ (js2-loop-node-body pn) body
+ (js2-node-pos pn) for-pos
+ (js2-node-len pn) (- (js2-node-end body) for-pos))
+ (js2-node-add-children pn init cond incr body))
+ ;; finally
+ (js2-exit-loop))
pn))
(defun js2-parse-try ()
@@ -9151,7 +9193,7 @@ Returns the parsed `js2-var-decl-node' expression node."
(defun js2-parse-let (pos &optional stmt-p)
"Parse a let expression or statement.
A let-expression is of the form `let (vars) expr'.
-A let-statment is of the form `let (vars) {statements}'.
+A let-statement is of the form `let (vars) {statements}'.
The third form of let is a variable declaration list, handled
by `js2-parse-variables'."
(let ((pn (make-js2-let-node :pos pos))
@@ -9256,11 +9298,10 @@ If NODE is non-nil, it is the AST node associated with
the symbol."
(let* ((js2-in-for-init nil)
(expr (js2-parse-expr))
(pn (make-js2-paren-node :pos px-pos
- :expr expr
- :len (- (js2-current-token-end)
- px-pos))))
+ :expr expr)))
(js2-node-add-children pn (js2-paren-node-expr pn))
(js2-must-match js2-RP "msg.no.paren")
+ (setf (js2-node-len pn) (- (js2-current-token-end) px-pos))
pn)))))
(defun js2-parse-expr (&optional oneshot)
@@ -10149,6 +10190,9 @@ We should have just parsed the 'for' keyword before
calling this function."
:loops (nreverse loops)
:filters (and filter (list (car filter)))
:form 'LEGACY_ARRAY))
+ ;; Set comp loop's parent to the last loop.
+ ;; TODO: Get rid of the bogus expr scope.
+ (setf (js2-scope-parent-scope result) first)
(apply #'js2-node-add-children result expr (car filter)
(js2-comp-node-loops result))
result))
@@ -10302,9 +10346,14 @@ If ONLY-OF-P is non-nil, only the 'for (foo of bar)'
form is allowed."
(continue t)
tt elems elem after-comma)
(while continue
- (setq static (and class-p (js2-match-token js2-STATIC))
- tt (js2-get-prop-name-token)
+ (setq tt (js2-get-prop-name-token)
+ static nil
elem nil)
+ (when (and class-p (= js2-NAME tt)
+ (string= "static" (js2-current-token-string)))
+ (js2-record-face 'font-lock-keyword-face)
+ (setq static t
+ tt (js2-get-prop-name-token)))
(cond
;; {foo: ...}, {'foo': ...}, {foo, bar, ...},
;; {get foo() {...}}, {set foo(x) {...}}, or {foo(x) {...}}
@@ -10344,13 +10393,13 @@ If ONLY-OF-P is non-nil, only the 'for (foo of bar)'
form is allowed."
(if elem (js2-node-set-prop elem 'STATIC t)
(js2-report-error "msg.unexpected.static")))
;; Handle commas, depending on class-p.
- (let ((comma (js2-match-token js2-COMMA)))
- (if class-p
- (if comma
- (js2-report-error "msg.class.unexpected.comma"))
- (if comma
- (setq after-comma (js2-current-token-end))
- (setq continue nil))))
+ (let ((tok (js2-get-prop-name-token)))
+ (if (eq tok js2-COMMA)
+ (if class-p
+ (js2-report-error "msg.class.unexpected.comma")
+ (setq after-comma (js2-current-token-end)))
+ (js2-unget-token)
+ (unless class-p (setq continue nil))))
;; Append any parsed element.
(if elem (push elem elems))) ; end loop
(js2-must-match js2-RC "msg.no.brace.prop")
@@ -10754,6 +10803,40 @@ In particular, return the buffer position of the first
`for' kwd."
(goto-char for-kwd)
(current-column))))
+(defun js2-maybe-goto-declaration-keyword-end (bracket)
+ "Helper function for `js2-proper-indentation'.
+Depending on the value of `js2-pretty-multiline-declarations',
+move point to the end of a variable declaration keyword so that
+indentation is aligned to that column."
+ (cond
+ ((eq js2-pretty-multiline-declarations 'all)
+ (when (looking-at js2-declaration-keyword-re)
+ (goto-char (1+ (match-end 0)))))
+ ((eq js2-pretty-multiline-declarations 'dynamic)
+ (let (declaration-keyword-end
+ at-closing-bracket-p
+ comma-p)
+ (when (looking-at js2-declaration-keyword-re)
+ ;; Preserve the match data lest it somehow be overridden.
+ (setq declaration-keyword-end (match-end 0))
+ (save-excursion
+ (goto-char bracket)
+ (setq at-closing-bracket-p
+ ;; Handle scan errors gracefully.
+ (condition-case nil
+ (progn
+ ;; Use the regular `forward-sexp-function' because the
+ ;; normal one for this mode uses the AST.
+ (let (forward-sexp-function)
+ (forward-sexp))
+ t)
+ (error nil)))
+ (when at-closing-bracket-p
+ (js2-forward-sws)
+ (setq comma-p (looking-at-p ","))))
+ (when comma-p
+ (goto-char (1+ declaration-keyword-end))))))))
+
(defun js2-proper-indentation (parse-status)
"Return the proper indentation for the current line."
(save-excursion
@@ -10797,9 +10880,7 @@ In particular, return the buffer position of the first
`for' kwd."
(looking-at ")"))
(backward-list))
(back-to-indentation)
- (and (eq js2-pretty-multiline-declarations 'all)
- (looking-at js2-declaration-keyword-re)
- (goto-char (1+ (match-end 0))))
+ (js2-maybe-goto-declaration-keyword-end bracket)
(setq indent
(cond (same-indent-p
(current-column))
@@ -11088,22 +11169,24 @@ If so, we don't ever want to use bounce-indent."
offset (- (point) (save-excursion
(back-to-indentation)
(point))))
- (js2-with-underscore-as-word-syntax
- (if (nth 4 parse-status)
- (js2-lineup-comment parse-status)
- (setq indent-col (js2-proper-indentation parse-status))
- ;; See comments below about `js2-mode-last-indented-line'.
- (cond
- ;; bounce-indenting is disabled during electric-key indent.
- ;; It doesn't work well on first line of buffer.
- ((and js2-bounce-indent-p
- (not (js2-same-line (point-min)))
- (not (js2-1-line-comment-continuation-p)))
- (js2-bounce-indent indent-col parse-status bounce-backwards))
- ;; just indent to the guesser's likely spot
- (t (indent-line-to indent-col))))
- (when (cl-plusp offset)
- (forward-char offset)))))
+ ;; Don't touch multiline strings.
+ (unless (nth 3 parse-status)
+ (js2-with-underscore-as-word-syntax
+ (if (nth 4 parse-status)
+ (js2-lineup-comment parse-status)
+ (setq indent-col (js2-proper-indentation parse-status))
+ ;; See comments below about `js2-mode-last-indented-line'.
+ (cond
+ ;; bounce-indenting is disabled during electric-key indent.
+ ;; It doesn't work well on first line of buffer.
+ ((and js2-bounce-indent-p
+ (not (js2-same-line (point-min)))
+ (not (js2-1-line-comment-continuation-p)))
+ (js2-bounce-indent indent-col parse-status bounce-backwards))
+ ;; just indent to the guesser's likely spot
+ (t (indent-line-to indent-col))))
+ (when (cl-plusp offset)
+ (forward-char offset))))))
(defun js2-indent-region (start end)
"Indent the region, but don't use bounce indenting."
@@ -11543,13 +11626,6 @@ The last element is optional. When present, use
instead of FACE."
(when (overlay-get o 'js2-error)
(delete-overlay o))))))
-(defun js2-error-at-point (&optional pos)
- "Return non-nil if there's an error overlay at POS.
-Defaults to point."
- (cl-loop with pos = (or pos (point))
- for o in (overlays-at pos)
- thereis (overlay-get o 'js2-error)))
-
(defun js2-mode-apply-deferred-properties ()
"Apply fontifications and other text properties recorded during parsing."
(when (cl-plusp js2-highlight-level)
@@ -11619,9 +11695,6 @@ was found on `point-entered' or in
`cursor-sensor-functions'."
(not (current-message)))
(message msg))))
-;; FIXME: Why do we keep this?
-(define-obsolete-function-alias 'js2-echo-help #'js2-echo-error "forever")
-
(defun js2-line-break (&optional _soft)
"Break line at point and indent, continuing comment if within one.
If inside a string, and `js2-concat-multiline-strings' is not
@@ -11678,12 +11751,7 @@ PARSE-STATUS is as documented in `parse-partial-sexp'."
;; comment.
(setq needs-close
(or
- ;; FIXME: Why not (get-char-property <pos> 'js2-error) instead?
- (if (fboundp 'cursor-sensor-mode)
- (equal (get-text-property (1- (point)) 'cursor-sensor-functions)
- '(js2-echo-error))
- (eq (get-text-property (1- (point)) 'point-entered)
- 'js2-echo-error))
+ (get-char-property (1- (point)) 'js2-error)
;; The heuristic above doesn't work well when we're
;; creating a comment and there's another one downstream,
;; as our parser thinks this one ends at the end of the
@@ -12090,7 +12158,7 @@ move backward across N balanced expressions."
(when (setq child (js2-node-closest-child node (point) rp))
(setq pos (js2-node-abs-end child)))
(setq pos (1+ rp))))
- ;; No parens or child nodes, looks for the end of the curren node.
+ ;; No parens or child nodes, looks for the end of the current
node.
(cl-incf pos (js2-node-len
(if (js2-expr-stmt-node-p (js2-node-parent node))
;; Stop after the semicolon.
diff --git a/packages/js2-mode/tests/indent.el
b/packages/js2-mode/tests/indent.el
index affbd58..df69202 100644
--- a/packages/js2-mode/tests/indent.el
+++ b/packages/js2-mode/tests/indent.el
@@ -23,22 +23,25 @@
(require 'js2-mode)
(require 'cl-lib)
-(defun js2-test-indent (content)
+(defun js2-test-indent (content keep-indent)
(let ((s (replace-regexp-in-string "^ *|" "" content)))
(with-temp-buffer
- (insert (replace-regexp-in-string "^ *" "" s))
+ (insert
+ (if keep-indent
+ s
+ (replace-regexp-in-string "^ *" "" s)))
(js2-mode)
(indent-region (point-min) (point-max))
(should (string= s (buffer-substring-no-properties
(point-min) (point)))))))
-(cl-defmacro js2-deftest-indent (name content &key bind)
+(cl-defmacro js2-deftest-indent (name content &key bind keep-indent)
`(ert-deftest ,(intern (format "js2-%s" name)) ()
(let ,(append '((js2-basic-offset 2)
(js2-pretty-multiline-declarations t)
(inhibit-point-motion-hooks t))
bind)
- (js2-test-indent ,content))))
+ (js2-test-indent ,content ,keep-indent))))
(put 'js2-deftest-indent 'lisp-indent-function 'defun)
@@ -102,3 +105,37 @@
| default: 'donkey',
| tee: 'ornery'
|};")
+
+(js2-deftest-indent multiline-string-noop
+ "`multiline string
+ | contents
+ | are kept
+ | unchanged!`"
+ :keep-indent t)
+
+(js2-deftest-indent no-multiline-decl-first-arg-function-dynamic
+ "var foo = function() {
+ | return 7;
+ |};"
+ :bind ((js2-pretty-multiline-declarations 'dynamic)))
+
+(js2-deftest-indent multiline-decl-first-arg-function-indent-dynamic
+ "var foo = function() {
+ | return 7;
+ | },
+ | bar = 8;"
+ :bind ((js2-pretty-multiline-declarations 'dynamic)))
+
+(js2-deftest-indent multiline-decl-first-arg-function-indent-dynamic-comment
+ "var foo = function() {
+ | return 7;
+ | }/* MUAHAHAHA, ah ha! */,
+ | bar = 8;"
+ :bind ((js2-pretty-multiline-declarations 'dynamic)))
+
+(js2-deftest-indent multiline-decl-first-arg-function-indent-dynamic-scan-error
+ "var foo = function() {
+ | return 7;
+ | ,
+ | bar = 8;"
+ :bind ((js2-pretty-multiline-declarations 'dynamic)))
diff --git a/packages/js2-mode/tests/parser.el
b/packages/js2-mode/tests/parser.el
index b4f2d8f..0dd1502 100644
--- a/packages/js2-mode/tests/parser.el
+++ b/packages/js2-mode/tests/parser.el
@@ -608,6 +608,16 @@ the test."
(should export-node)
(should (js2-export-node-default export-node))))
+(js2-deftest export-function-no-semicolon "export default function foo() {}"
+ (js2-mode)
+ (should (equal nil js2-parsed-warnings)))
+(js2-deftest export-default-function-no-semicolon "export function foo() {}"
+ (js2-mode)
+ (should (equal nil js2-parsed-warnings)))
+(js2-deftest export-anything-else-does-require-a-semicolon "export var obj =
{}"
+ (js2-mode)
+ (should (not (equal nil js2-parsed-warnings))))
+
(js2-deftest-parse parse-export-rexport "export * from 'other/lib';")
(js2-deftest-parse parse-export-export-named-list "export {foo, bar as bang};")
(js2-deftest-parse parse-re-export-named-list "export {foo, bar as bang} from
'other/lib';")
@@ -673,6 +683,9 @@ the test."
(js2-deftest-parse parse-super-keyword
"class Foo {\n constructor() { super(42);\n}\n foo() {
super.foo();\n}\n}")
+(js2-deftest-parse parse-class-keywordlike-method
+ "class C {\n delete() {}\n if() {}\n}")
+
;;; Scopes
(js2-deftest ast-symbol-table-includes-fn-node "function foo() {}"
@@ -696,6 +709,20 @@ the test."
(should (= (js2-symbol-decl-type var-entry) js2-VAR))
(should (js2-name-node-p (js2-symbol-ast-node var-entry)))))
+(js2-deftest for-node-is-declaration-scope "for (let i = 0; i; ++i) {};"
+ (js2-mode)
+ (search-forward "i")
+ (forward-char -1)
+ (let ((scope (js2-node-get-enclosing-scope (js2-node-at-point))))
+ (should (js2-for-node-p (js2-get-defining-scope scope "i")))))
+
+(js2-deftest array-comp-is-result-scope "[x * 2 for (x in y)];"
+ (js2-mode)
+ (search-forward "x")
+ (forward-char -1)
+ (let ((scope (js2-node-get-enclosing-scope (js2-node-at-point))))
+ (should (js2-comp-loop-node-p (js2-get-defining-scope scope "x")))))
+
;;; Tokenizer
(js2-deftest get-token "(1+1)"
@@ -766,3 +793,15 @@ the test."
(js2-deftest function-without-parens-error "function b {}"
;; Should finish the parse.
(js2-mode))
+
+;;; Comments
+
+(js2-deftest comment-node-length "//"
+ (js2-mode)
+ (let ((node (js2-node-at-point (point-min))))
+ (should (= (js2-node-len node) 2))))
+
+(js2-deftest comment-node-length-newline "//\n"
+ (js2-mode)
+ (let ((node (js2-node-at-point (point-min))))
+ (should (= (js2-node-len node) 3))))
- [elpa] master 3b76567 12/22: Fix js2-node-get-enclosing-scope, (continued)
- [elpa] master 3b76567 12/22: Fix js2-node-get-enclosing-scope, Dmitry Gutov, 2015/04/23
- [elpa] master 458d3fe 14/22: Merge pull request #221 from jacksonrayhamilton/enclosing-scope, Dmitry Gutov, 2015/04/23
- [elpa] master a184642 13/22: Merge pull request #220 from jacksonrayhamilton/comment-length, Dmitry Gutov, 2015/04/23
- [elpa] master 2bb4db0 15/22: Assign quote syntax to backquotes, Dmitry Gutov, 2015/04/23
- [elpa] master 4de6f03 16/22: Don't indent in multiline strings, Dmitry Gutov, 2015/04/23
- [elpa] master ee4a202 18/22: Merge pull request #195 from jacksonrayhamilton/pretty-multiline-declarations, Dmitry Gutov, 2015/04/23
- [elpa] master d4d9c54 17/22: js2-pretty-multiline-declarations: Add 'dynamic option, Dmitry Gutov, 2015/04/23
- [elpa] master 9790b97 19/22: * js2-mode.el (js2-mode): Use cursor-sensor-mode if available., Dmitry Gutov, 2015/04/23
- [elpa] master ac93b9e 21/22: Address two FIXMEs; fix a regression flagged by tests, Dmitry Gutov, 2015/04/23
- [elpa] master 022ef95 20/22: Merge commit '9790b9781aa8ca1d4bdf94d06d4e8ff2e68d37e8' into js2-mode-master, Dmitry Gutov, 2015/04/23
- [elpa] master 54df259 22/22: Merge commit 'ac93b9eef9b6ac44d187b9688d68a7a5f205b3fe' from js2-mode,
Dmitry Gutov <=