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

[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))))



reply via email to

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