[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master a7b8100 3/3: Merge commit '494c421bfa6f1b72b577267cb3841b0
From: |
Dmitry Gutov |
Subject: |
[elpa] master a7b8100 3/3: Merge commit '494c421bfa6f1b72b577267cb3841b0eff262250' from js2-mode |
Date: |
Sat, 18 Jul 2015 01:14:48 +0000 |
branch: master
commit a7b8100b52925d82aa1d6fd8606a537ea88b91b9
Merge: 2763c9a 494c421
Author: Dmitry Gutov <address@hidden>
Commit: Dmitry Gutov <address@hidden>
Merge commit '494c421bfa6f1b72b577267cb3841b0eff262250' from js2-mode
---
packages/js2-mode/js2-mode.el | 582 ++++-------------------------------
packages/js2-mode/js2-old-indent.el | 493 +++++++++++++++++++++++++++++
2 files changed, 549 insertions(+), 526 deletions(-)
diff --git a/packages/js2-mode/js2-mode.el b/packages/js2-mode/js2-mode.el
index 4a6e733..6ea2461 100644
--- a/packages/js2-mode/js2-mode.el
+++ b/packages/js2-mode/js2-mode.el
@@ -87,13 +87,14 @@
(require 'cl-lib)
(require 'imenu)
-(require 'cc-cmds) ; for `c-fill-paragraph'
+(require 'js)
(eval-and-compile
- (require 'cc-mode) ; (only) for `c-populate-syntax-table'
- (require 'cc-engine)) ; for `c-paragraph-start' et. al.
-
-(defvar electric-layout-rules)
+ (if (version< emacs-version "25.0")
+ (require 'js2-old-indent)
+ (defvaralias 'js2-basic-offset 'js-indent-level nil)
+ (defalias 'js2-proper-indentation 'js--proper-indentation)
+ (defalias 'js2-indent-line 'js-indent-line)))
;;; Externs (variables presumed to be defined by the host system)
@@ -235,78 +236,6 @@ variable with predicate PRED."
"An improved JavaScript mode."
:group 'languages)
-(defcustom js2-basic-offset (if (and (boundp 'c-basic-offset)
- (numberp c-basic-offset))
- c-basic-offset
- 4)
- "Number of spaces to indent nested statements.
-Similar to `c-basic-offset'."
- :group 'js2-mode
- :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
-based on heuristic guessing. If non-nil, then if the current line is
-already indented to that predetermined column, indenting will choose
-another likely column and indent to that spot. Repeated invocation of
-the indent-line function will cycle among the computed alternatives.
-See the function `js2-bounce-indent' for details. When it is non-nil,
-js2-mode also binds `js2-bounce-indent-backwards' to Shift-Tab."
- :type 'boolean
- :group 'js2-mode)
-
-(defcustom js2-pretty-multiline-declarations t
- "Non-nil to line up multiline declarations vertically:
-
- var a = 10,
- b = 20,
- c = 30;
-
-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; };
-
-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)
-
-(defcustom js2-indent-switch-body nil
- "When nil, case labels are indented on the same level as the
-containing switch statement. Otherwise, all lines inside
-switch statement body are indented one additional level."
- :type 'boolean
- :group 'js2-mode)
-(js2-mark-safe-local 'js2-indent-case-same-as-switch 'booleanp)
-
(defcustom js2-idle-timer-delay 0.2
"Delay in secs before re-parsing after user makes changes.
Multiplied by `js2-dynamic-idle-timer-adjust', which see."
@@ -1185,8 +1114,6 @@ information."
(define-key map (kbd "C-c C-o") #'js2-mode-toggle-element)
(define-key map (kbd "C-c C-w") #'js2-mode-toggle-warnings-and-errors)
(define-key map [down-mouse-3] #'js2-down-mouse-3)
- (when js2-bounce-indent-p
- (define-key map (kbd "<backtab>") #'js2-indent-bounce-backwards))
(define-key map [menu-bar javascript]
(cons "JavaScript" (make-sparse-keymap "JavaScript")))
@@ -1249,6 +1176,24 @@ information."
map)
"Keymap used in `js2-mode' buffers.")
+(defcustom js2-bounce-indent-p nil
+ "Non-nil to bind `js2-indent-bounce' and `js2-indent-bounce-backward'.
+They will augment the default indent-line behavior with cycling
+among several computed alternatives. See the function
+`js2-bounce-indent' for details. The above commands will be
+bound to TAB and backtab."
+ :type 'boolean
+ :group 'js2-mode
+ :set (lambda (sym value)
+ (set-default sym value)
+ (let ((map js2-mode-map))
+ (if (not value)
+ (progn
+ (define-key map "\t" nil)
+ (define-key map (kbd "<backtab>") nil))
+ (define-key map "\t" #'js2-indent-bounce)
+ (define-key map (kbd "<backtab>")
#'js2-indent-bounce-backward)))))
+
(defconst js2-mode-identifier-re "[[:alpha:]_$][[:alnum:]_$]*")
(defvar js2-mode-//-comment-re "^\\(\\s-*\\)//.+"
@@ -1271,32 +1216,6 @@ First match-group is the leading whitespace.")
(js2-deflocal js2-imenu-recorder nil "Private variable")
(js2-deflocal js2-imenu-function-map nil "Private variable")
-(defvar js2-paragraph-start
- "\\(@[[:alpha:]]+\\>\\|$\\)")
-
-;; Note that we also set a 'c-in-sws text property in html comments,
-;; so that `c-forward-sws' and `c-backward-sws' work properly.
-(defvar js2-syntactic-ws-start
- "\\s \\|/[*/]\\|[\n\r]\\|\\\\[\n\r]\\|\\s!\\|<!--\\|^\\s-*-->")
-
-(defvar js2-syntactic-ws-end
- "\\s \\|[\n\r/]\\|\\s!")
-
-(defvar js2-syntactic-eol
- (concat "\\s *\\(/\\*[^*\n\r]*"
- "\\(\\*+[^*\n\r/][^*\n\r]*\\)*"
- "\\*+/\\s *\\)*"
- "\\(//\\|/\\*[^*\n\r]*"
- "\\(\\*+[^*\n\r/][^*\n\r]*\\)*$"
- "\\|\\\\$\\|$\\)")
- "Copied from `java-mode'. Needed for some cc-engine functions.")
-
-(defvar js2-comment-prefix-regexp
- "//+\\|\\**")
-
-(defvar js2-comment-start-skip
- "\\(//+\\|/\\*+\\)\\s *")
-
(defvar js2-mode-verbose-parse-p js2-mode-dev-mode-p
"Non-nil to emit status messages during parsing.")
@@ -10907,22 +10826,19 @@ And, if CHECK-ACTIVATION-P is non-nil, use the value
of TOKEN."
(js2-check-activation-name s (or token js2-NAME)))
name))
-;;; Indentation support
+;;; Indentation support (bouncing)
-;; This indenter is based on Karl Landström's "javascript.el" indenter.
-;; Karl cleverly deduces that the desired indentation level is often a
-;; function of paren/bracket/brace nesting depth, which can be determined
-;; quickly via the built-in `parse-partial-sexp' function. His indenter
-;; then does some equally clever checks to see if we're in the context of a
-;; substatement of a possibly braceless statement keyword such as if, while,
-;; or finally. This approach yields pretty good results.
+;; In recent-enough Emacs, we reuse the indentation code from
+;; `js-mode'. To continue support for the older versions, some code
+;; that was here previously was moved to `js2-old-indent.el'.
-;; The indenter is often "wrong", however, and needs to be overridden.
-;; The right long-term solution is probably to emulate (or integrate
-;; with) cc-engine, but it's a nontrivial amount of coding. Even when a
-;; parse tree from `js2-parse' is present, which is not true at the
-;; moment the user is typing, computing indentation is still thousands
-;; of lines of code to handle every possible syntactic edge case.
+;; Whichever indenter is used, it's often "wrong", however, and needs
+;; to be overridden. The right long-term solution is probably to
+;; emulate (or integrate with) cc-engine, but it's a nontrivial amount
+;; of coding. Even when a parse tree from `js2-parse' is present,
+;; which is not true at the moment the user is typing, computing
+;; indentation is still thousands of lines of code to handle every
+;; possible syntactic edge case.
;; In the meantime, the compromise solution is that we offer a "bounce
;; indenter", configured with `js2-bounce-indent-p', which cycles the
@@ -10931,359 +10847,6 @@ And, if CHECK-ACTIVATION-P is non-nil, use the value
of TOKEN."
;; move the line towards its desired indentation when manually
;; overriding Karl's heuristic nesting guesser.
-;; I've made miscellaneous tweaks to Karl's code to handle some Ecma
-;; extensions such as `let' and Array comprehensions. Major kudos to
-;; Karl for coming up with the initial approach, which packs a lot of
-;; punch for so little code.
-
-(defconst js2-possibly-braceless-keywords-re
- (concat "else[ \t]+if\\|for[ \t]+each\\|"
- (regexp-opt '("catch" "do" "else" "finally" "for" "if"
- "try" "while" "with" "let")))
- "Regular expression matching keywords that are optionally
-followed by an opening brace.")
-
-(defconst js2-indent-operator-re
- (concat "[-+*/%<>&^|?:.]\\([^-+*/]\\|$\\)\\|!?=\\|"
- (regexp-opt '("in" "instanceof") 'words))
- "Regular expression matching operators that affect indentation
-of continued expressions.")
-
-(defconst js2-declaration-keyword-re
- (regexp-opt '("var" "let" "const") 'words)
- "Regular expression matching variable declaration keywords.")
-
-(defun js2-re-search-forward-inner (regexp &optional bound count)
- "Auxiliary function for `js2-re-search-forward'."
- (let (parse saved-point)
- (while (> count 0)
- (re-search-forward regexp bound)
- (setq parse (if saved-point
- (parse-partial-sexp saved-point (point))
- (syntax-ppss (point))))
- (cond ((nth 3 parse)
- (re-search-forward
- (concat "\\(\\=\\|[^\\]\\|^\\)" (string (nth 3 parse)))
- (save-excursion (end-of-line) (point)) t))
- ((nth 7 parse)
- (forward-line))
- ((or (nth 4 parse)
- (and (eq (char-before) ?\/) (eq (char-after) ?\*)))
- (re-search-forward "\\*/"))
- (t
- (setq count (1- count))))
- (setq saved-point (point))))
- (point))
-
-(defun js2-re-search-forward (regexp &optional bound noerror count)
- "Search forward but ignore strings and comments.
-Invokes `re-search-forward' but treats the buffer as if strings
-and comments have been removed."
- (let ((saved-point (point)))
- (condition-case err
- (cond ((null count)
- (js2-re-search-forward-inner regexp bound 1))
- ((< count 0)
- (js2-re-search-backward-inner regexp bound (- count)))
- ((> count 0)
- (js2-re-search-forward-inner regexp bound count)))
- (search-failed
- (goto-char saved-point)
- (unless noerror
- (error (error-message-string err)))))))
-
-(defun js2-re-search-backward-inner (regexp &optional bound count)
- "Auxiliary function for `js2-re-search-backward'."
- (let (parse)
- (while (> count 0)
- (re-search-backward regexp bound)
- (setq parse (syntax-ppss (point)))
- (cond ((nth 3 parse)
- (re-search-backward
- (concat "\\([^\\]\\|^\\)" (string (nth 3 parse)))
- (line-beginning-position) t))
- ((nth 7 parse)
- (goto-char (nth 8 parse)))
- ((or (nth 4 parse)
- (and (eq (char-before) ?/) (eq (char-after) ?*)))
- (re-search-backward "/\\*"))
- (t
- (setq count (1- count))))))
- (point))
-
-(defun js2-re-search-backward (regexp &optional bound noerror count)
- "Search backward but ignore strings and comments.
-Invokes `re-search-backward' but treats the buffer as if strings
-and comments have been removed."
- (let ((saved-point (point)))
- (condition-case err
- (cond ((null count)
- (js2-re-search-backward-inner regexp bound 1))
- ((< count 0)
- (js2-re-search-forward-inner regexp bound (- count)))
- ((> count 0)
- (js2-re-search-backward-inner regexp bound count)))
- (search-failed
- (goto-char saved-point)
- (unless noerror
- (error (error-message-string err)))))))
-
-(defun js2-looking-at-operator-p ()
- "Return non-nil if text after point is a non-comma operator."
- (and (looking-at js2-indent-operator-re)
- (or (not (looking-at ":"))
- (save-excursion
- (and (js2-re-search-backward "[?:{]\\|\\_<case\\_>" nil t)
- (looking-at "?"))))))
-
-(defun js2-continued-expression-p ()
- "Return non-nil if the current line continues an expression."
- (save-excursion
- (back-to-indentation)
- (or (js2-looking-at-operator-p)
- (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)
- (not (looking-at "\\*\\|\\+\\+\\|--\\|/[/*]")))))))
-
-(defun js2-end-of-do-while-loop-p ()
- "Return non-nil if word after point is `while' of a do-while
-statement, else returns nil. A braceless do-while statement
-spanning several lines requires that the start of the loop is
-indented to the same column as the current line."
- (interactive)
- (save-excursion
- (when (looking-at "\\s-*\\_<while\\_>")
- (if (save-excursion
- (skip-chars-backward "[ \t\n]*}")
- (looking-at "[ \t\n]*}"))
- (save-excursion
- (backward-list) (backward-word 1) (looking-at "\\_<do\\_>"))
- (js2-re-search-backward "\\_<do\\_>" (point-at-bol) t)
- (or (looking-at "\\_<do\\_>")
- (let ((saved-indent (current-indentation)))
- (while (and (js2-re-search-backward "^[ \t]*\\_<" nil t)
- (/= (current-indentation) saved-indent)))
- (and (looking-at "[ \t]*\\_<do\\_>")
- (not (js2-re-search-forward
- "\\_<while\\_>" (point-at-eol) t))
- (= (current-indentation) saved-indent))))))))
-
-(defun js2-multiline-decl-indentation ()
- "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)
- (save-excursion
- (back-to-indentation)
- (when (not (looking-at js2-declaration-keyword-re))
- (when (looking-at js2-indent-operator-re)
- (goto-char (match-end 0))) ; continued expressions are ok
- (while (and (not at-opening-bracket)
- (not (bobp))
- (let ((pos (point)))
- (save-excursion
- (js2-backward-sws)
- (or (eq (char-before) ?,)
- (and (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 _
- (backward-sexp)
- (scan-error (setq at-opening-bracket t))))
- (when (looking-at js2-declaration-keyword-re)
- (goto-char (match-end 0))
- (1+ (current-column)))))))
-
-(defun js2-ctrl-statement-indentation ()
- "Return the proper indentation of current line if it is a control statement.
-Returns an indentation if this line starts the body of a control
-statement without braces, else returns nil."
- (let (forward-sexp-function)
- (save-excursion
- (back-to-indentation)
- (when (and (not (js2-same-line (point-min)))
- (not (looking-at "{"))
- (js2-re-search-backward "[[:graph:]]" nil t)
- (not (looking-at "[{([]"))
- (progn
- (forward-char)
- (when (= (char-before) ?\))
- ;; scan-sexps sometimes throws an error
- (ignore-errors (backward-sexp))
- (skip-chars-backward " \t" (point-at-bol)))
- (let ((pt (point)))
- (back-to-indentation)
- (when (looking-at "}[ \t]*")
- (goto-char (match-end 0)))
- (and (looking-at js2-possibly-braceless-keywords-re)
- (= (match-end 0) pt)
- (not (js2-end-of-do-while-loop-p))))))
- (+ (current-indentation) js2-basic-offset)))))
-
-(defun js2-indent-in-array-comp (parse-status)
- "Return non-nil if we think we're in an array comprehension.
-In particular, return the buffer position of the first `for' kwd."
- (let ((bracket (nth 1 parse-status))
- (end (point)))
- (when bracket
- (save-excursion
- (goto-char bracket)
- (when (looking-at "\\[")
- (forward-char 1)
- (js2-forward-sws)
- (if (looking-at "[[{]")
- (let (forward-sexp-function) ; use Lisp version
- (forward-sexp) ; skip destructuring form
- (js2-forward-sws)
- (if (and (/= (char-after) ?,) ; regular array
- (looking-at "for"))
- (match-beginning 0)))
- ;; to skip arbitrary expressions we need the parser,
- ;; so we'll just guess at it.
- (if (and (> end (point)) ; not empty literal
- (re-search-forward "[^,]]* \\(for\\) " end t)
- ;; not inside comment or string literal
- (let ((state (parse-partial-sexp bracket (point))))
- (not (or (nth 3 state) (nth 4 state)))))
- (match-beginning 1))))))))
-
-(defun js2-array-comp-indentation (parse-status for-kwd)
- (if (js2-same-line for-kwd)
- ;; first continuation line
- (save-excursion
- (goto-char (nth 1 parse-status))
- (forward-char 1)
- (skip-chars-forward " \t")
- (current-column))
- (save-excursion
- (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
- (back-to-indentation)
- (let* ((ctrl-stmt-indent (js2-ctrl-statement-indentation))
- (at-closing-bracket (looking-at "[]})]"))
- (same-indent-p (or at-closing-bracket
- (looking-at "\\_<case\\_>[^:]")
- (and (looking-at "\\_<default:")
- (save-excursion
- (js2-backward-sws)
- (not (memq (char-before) '(?, ?{)))))))
- (continued-expr-p (js2-continued-expression-p))
- (declaration-indent (and js2-pretty-multiline-declarations
- (js2-multiline-decl-indentation)))
- (bracket (nth 1 parse-status))
- beg indent)
- (cond
- ;; indent array comprehension continuation lines specially
- ((and bracket
- (>= js2-language-version 170)
- (not (js2-same-line bracket))
- (setq beg (js2-indent-in-array-comp parse-status))
- (>= (point) (save-excursion
- (goto-char beg)
- (point-at-bol)))) ; at or after first loop?
- (js2-array-comp-indentation parse-status beg))
-
- (ctrl-stmt-indent)
-
- ((and declaration-indent continued-expr-p)
- (+ declaration-indent js2-basic-offset))
-
- (declaration-indent)
-
- (bracket
- (goto-char bracket)
- (cond
- ((looking-at "[({[][ \t]*\\(/[/*]\\|$\\)")
- (when (save-excursion (skip-chars-backward " \t)")
- (looking-at ")"))
- (backward-list))
- (back-to-indentation)
- (js2-maybe-goto-declaration-keyword-end bracket)
- (setq indent
- (cond (same-indent-p
- (current-column))
- (continued-expr-p
- (+ (current-column) (* 2 js2-basic-offset)))
- (t
- (+ (current-column) js2-basic-offset))))
- (if (and js2-indent-switch-body
- (not at-closing-bracket)
- (looking-at "\\_<switch\\_>"))
- (+ indent js2-basic-offset)
- indent))
- (t
- (unless same-indent-p
- (forward-char)
- (skip-chars-forward " \t"))
- (current-column))))
-
- (continued-expr-p js2-basic-offset)
-
- (t 0)))))
-
-(defun js2-lineup-comment (parse-status)
- "Indent a multi-line block comment continuation line."
- (let* ((beg (nth 8 parse-status))
- (first-line (js2-same-line beg))
- (offset (save-excursion
- (goto-char beg)
- (if (looking-at "/\\*")
- (+ 1 (current-column))
- 0))))
- (unless first-line
- (indent-line-to offset))))
-
(defun js2-backward-sws ()
"Move backward through whitespace and comments."
(interactive)
@@ -11341,7 +10904,7 @@ indentation is aligned to that column."
(skip-chars-forward " \t")
(looking-at "case\\s-.+:")))
-(defun js2-bounce-indent (normal-col parse-status &optional backwards)
+(defun js2-bounce-indent (normal-col parse-status &optional backward)
"Cycle among alternate computed indentation positions.
PARSE-STATUS is the result of `parse-partial-sexp' from the beginning
of the buffer to the current point. NORMAL-COL is the indentation
@@ -11451,8 +11014,8 @@ in reverse."
(js2-indent-objlit-arg-p parse-status))
(setq main-pos basic-offset))
- ;; if bouncing backwards, reverse positions list
- (if backwards
+ ;; if bouncing backward, reverse positions list
+ (if backward
(setq positions (reverse positions)))
;; record whether we're already sitting on one of the alternatives
@@ -11496,12 +11059,6 @@ in reverse."
;; see commentary for `js2-mode-last-indented-line'
(setq js2-mode-last-indented-line current-line))))
-(defun js2-indent-bounce-backwards ()
- "Calls `js2-indent-line'. When `js2-bounce-indent-p',
-cycles between the computed indentation positions in reverse order."
- (interactive)
- (js2-indent-line t))
-
(defun js2-1-line-comment-continuation-p ()
"Return t if we're in a 1-line comment continuation.
If so, we don't ever want to use bounce-indent."
@@ -11517,8 +11074,8 @@ If so, we don't ever want to use bounce-indent."
(forward-line 0))
(looking-at "\\s-*//")))))
-(defun js2-indent-line (&optional bounce-backwards)
- "Indent the current line as JavaScript source text."
+(defun js2-indent-bounce (&optional backward)
+ "Indent the current line, bouncing between several positions."
(interactive)
(let (parse-status offset indent-col
;; Don't whine about errors/warnings when we're indenting.
@@ -11531,22 +11088,23 @@ If so, we don't ever want to use bounce-indent."
(point))))
;; Don't touch multiline strings.
(unless (nth 3 parse-status)
- (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))))
+ (setq indent-col (js2-proper-indentation parse-status))
+ (cond
+ ;; It doesn't work well on first line of buffer.
+ ((and (not (nth 4 parse-status))
+ (not (js2-same-line (point-min)))
+ (not (js2-1-line-comment-continuation-p)))
+ (js2-bounce-indent indent-col parse-status backward))
+ ;; just indent to the guesser's likely spot
+ (t (indent-line-to indent-col)))
(when (cl-plusp offset)
(forward-char offset)))))
+(defun js2-indent-bounce-backward ()
+ "Indent the current line, bouncing between positions in reverse."
+ (interactive)
+ (js2-indent-bounce t))
+
(defun js2-indent-region (start end)
"Indent the region, but don't use bounce indenting."
(let ((js2-bounce-indent-p nil)
@@ -11718,18 +11276,14 @@ Selecting an error will jump it to the corresponding
source-buffer error.
(message msg))))))
;;;###autoload
-(define-derived-mode js2-mode prog-mode "Javascript-IDE"
- ;; FIXME: Should derive from js-mode.
+(define-derived-mode js2-mode js-mode "Javascript-IDE"
"Major mode for editing JavaScript code."
;; Used by comment-region; don't change it.
- (set (make-local-variable 'comment-start) "//")
- (set (make-local-variable 'comment-end) "")
- (set (make-local-variable 'comment-start-skip) js2-comment-start-skip)
(set (make-local-variable 'max-lisp-eval-depth)
(max max-lisp-eval-depth 3000))
(set (make-local-variable 'indent-line-function) #'js2-indent-line)
(set (make-local-variable 'indent-region-function) #'js2-indent-region)
- (set (make-local-variable 'fill-paragraph-function) #'c-fill-paragraph)
+ (set (make-local-variable 'syntax-propertize-function) nil)
(set (make-local-variable 'comment-line-break-function) #'js2-line-break)
(set (make-local-variable 'beginning-of-defun-function)
#'js2-beginning-of-defun)
(set (make-local-variable 'end-of-defun-function) #'js2-end-of-defun)
@@ -11741,30 +11295,6 @@ Selecting an error will jump it to the corresponding
source-buffer error.
;; needed for M-x rgrep, among other things
(put 'js2-mode 'find-tag-default-function #'js2-mode-find-tag)
- (set (make-local-variable 'electric-indent-chars)
- (append "{}()[]:;,*." electric-indent-chars))
- (set (make-local-variable 'electric-layout-rules)
- '((?\; . after) (?\{ . after) (?\} . before)))
-
- ;; some variables needed by cc-engine for paragraph-fill, etc.
- (setq c-comment-prefix-regexp js2-comment-prefix-regexp
- c-comment-start-regexp "/[*/]\\|\\s|"
- c-line-comment-starter "//"
- c-paragraph-start js2-paragraph-start
- c-paragraph-separate "$"
- c-syntactic-ws-start js2-syntactic-ws-start
- c-syntactic-ws-end js2-syntactic-ws-end
- c-syntactic-eol js2-syntactic-eol)
-
- (let ((c-buffer-is-cc-mode t))
- ;; Copied from `js-mode'. Also see Bug#6071.
- (make-local-variable 'paragraph-start)
- (make-local-variable 'paragraph-separate)
- (make-local-variable 'paragraph-ignore-fill-prefix)
- (make-local-variable 'adaptive-fill-mode)
- (make-local-variable 'adaptive-fill-regexp)
- (c-setup-paragraph-variables))
-
(setq font-lock-defaults '(nil t))
;; Experiment: make reparse-delay longer for longer files.
diff --git a/packages/js2-mode/js2-old-indent.el
b/packages/js2-mode/js2-old-indent.el
new file mode 100644
index 0000000..9b1c929
--- /dev/null
+++ b/packages/js2-mode/js2-old-indent.el
@@ -0,0 +1,493 @@
+;;; js2-old-indent.el --- Indentation code kept for compatibility
+
+;; Copyright (C) 2015 Free Software Foundation, Inc.
+
+;; 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:
+
+;; All features of this indentation code have been ported to Emacs's
+;; built-in `js-mode' by now, so we derive from it. An older
+;; commentary follows.
+
+;; This code is kept for Emacs 24.5 and ealier.
+
+;; This indenter is based on Karl Landström's "javascript.el" indenter.
+;; Karl cleverly deduces that the desired indentation level is often a
+;; function of paren/bracket/brace nesting depth, which can be determined
+;; quickly via the built-in `parse-partial-sexp' function. His indenter
+;; then does some equally clever checks to see if we're in the context of a
+;; substatement of a possibly braceless statement keyword such as if, while,
+;; or finally. This approach yields pretty good results.
+
+;; The indenter is often "wrong", however, and needs to be overridden.
+;; The right long-term solution is probably to emulate (or integrate
+;; with) cc-engine, but it's a nontrivial amount of coding. Even when a
+;; parse tree from `js2-parse' is present, which is not true at the
+;; moment the user is typing, computing indentation is still thousands
+;; of lines of code to handle every possible syntactic edge case.
+
+;; In the meantime, the compromise solution is that we offer a "bounce
+;; indenter", configured with `js2-bounce-indent-p', which cycles the
+;; current line indent among various likely guess points. This approach
+;; is far from perfect, but should at least make it slightly easier to
+;; move the line towards its desired indentation when manually
+;; overriding Karl's heuristic nesting guesser.
+
+;; I've made miscellaneous tweaks to Karl's code to handle some Ecma
+;; extensions such as `let' and Array comprehensions. Major kudos to
+;; Karl for coming up with the initial approach, which packs a lot of
+;; punch for so little code. -- Steve
+
+;;; Code:
+
+(defvar js2-language-version)
+
+(declare-function js2-mark-safe-local "js2-mode")
+(declare-function js2-backward-sws "js2-mode")
+(declare-function js2-forward-sws "js2-mode")
+(declare-function js2-same-line "js2-mode")
+
+(defcustom js2-basic-offset (if (and (boundp 'c-basic-offset)
+ (numberp c-basic-offset))
+ c-basic-offset
+ 4)
+ "Number of spaces to indent nested statements.
+Similar to `c-basic-offset'."
+ :group 'js2-mode
+ :safe 'integerp
+ :type 'integer)
+
+(defcustom js2-pretty-multiline-declarations t
+ "Non-nil to line up multiline declarations vertically:
+
+ var a = 10,
+ b = 20,
+ c = 30;
+
+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; };
+
+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
+ :safe 'symbolp
+ :type 'symbol)
+
+(defcustom js2-indent-switch-body nil
+ "When nil, case labels are indented on the same level as the
+containing switch statement. Otherwise, all lines inside
+switch statement body are indented one additional level."
+ :type 'boolean
+ :safe 'booleanp
+ :group 'js2-mode)
+
+(defconst js2-possibly-braceless-keywords-re
+ (concat "else[ \t]+if\\|for[ \t]+each\\|"
+ (regexp-opt '("catch" "do" "else" "finally" "for" "if"
+ "try" "while" "with" "let")))
+ "Regular expression matching keywords that are optionally
+followed by an opening brace.")
+
+(defconst js2-indent-operator-re
+ (concat "[-+*/%<>&^|?:.]\\([^-+*/]\\|$\\)\\|!?=\\|"
+ (regexp-opt '("in" "instanceof") 'words))
+ "Regular expression matching operators that affect indentation
+of continued expressions.")
+
+(defconst js2-declaration-keyword-re
+ (regexp-opt '("var" "let" "const") 'words)
+ "Regular expression matching variable declaration keywords.")
+
+(defun js2-re-search-forward-inner (regexp &optional bound count)
+ "Auxiliary function for `js2-re-search-forward'."
+ (let (parse saved-point)
+ (while (> count 0)
+ (re-search-forward regexp bound)
+ (setq parse (if saved-point
+ (parse-partial-sexp saved-point (point))
+ (syntax-ppss (point))))
+ (cond ((nth 3 parse)
+ (re-search-forward
+ (concat "\\(\\=\\|[^\\]\\|^\\)" (string (nth 3 parse)))
+ (save-excursion (end-of-line) (point)) t))
+ ((nth 7 parse)
+ (forward-line))
+ ((or (nth 4 parse)
+ (and (eq (char-before) ?\/) (eq (char-after) ?\*)))
+ (re-search-forward "\\*/"))
+ (t
+ (setq count (1- count))))
+ (setq saved-point (point))))
+ (point))
+
+(defun js2-re-search-forward (regexp &optional bound noerror count)
+ "Search forward but ignore strings and comments.
+Invokes `re-search-forward' but treats the buffer as if strings
+and comments have been removed."
+ (let ((saved-point (point)))
+ (condition-case err
+ (cond ((null count)
+ (js2-re-search-forward-inner regexp bound 1))
+ ((< count 0)
+ (js2-re-search-backward-inner regexp bound (- count)))
+ ((> count 0)
+ (js2-re-search-forward-inner regexp bound count)))
+ (search-failed
+ (goto-char saved-point)
+ (unless noerror
+ (error (error-message-string err)))))))
+
+(defun js2-re-search-backward-inner (regexp &optional bound count)
+ "Auxiliary function for `js2-re-search-backward'."
+ (let (parse)
+ (while (> count 0)
+ (re-search-backward regexp bound)
+ (setq parse (syntax-ppss (point)))
+ (cond ((nth 3 parse)
+ (re-search-backward
+ (concat "\\([^\\]\\|^\\)" (string (nth 3 parse)))
+ (line-beginning-position) t))
+ ((nth 7 parse)
+ (goto-char (nth 8 parse)))
+ ((or (nth 4 parse)
+ (and (eq (char-before) ?/) (eq (char-after) ?*)))
+ (re-search-backward "/\\*"))
+ (t
+ (setq count (1- count))))))
+ (point))
+
+(defun js2-re-search-backward (regexp &optional bound noerror count)
+ "Search backward but ignore strings and comments.
+Invokes `re-search-backward' but treats the buffer as if strings
+and comments have been removed."
+ (let ((saved-point (point)))
+ (condition-case err
+ (cond ((null count)
+ (js2-re-search-backward-inner regexp bound 1))
+ ((< count 0)
+ (js2-re-search-forward-inner regexp bound (- count)))
+ ((> count 0)
+ (js2-re-search-backward-inner regexp bound count)))
+ (search-failed
+ (goto-char saved-point)
+ (unless noerror
+ (error (error-message-string err)))))))
+
+(defun js2-looking-at-operator-p ()
+ "Return non-nil if text after point is a non-comma operator."
+ (and (looking-at js2-indent-operator-re)
+ (or (not (looking-at ":"))
+ (save-excursion
+ (and (js2-re-search-backward "[?:{]\\|\\_<case\\_>" nil t)
+ (looking-at "?"))))))
+
+(defun js2-continued-expression-p ()
+ "Return non-nil if the current line continues an expression."
+ (save-excursion
+ (back-to-indentation)
+ (or (js2-looking-at-operator-p)
+ (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)
+ (not (looking-at "\\*\\|\\+\\+\\|--\\|/[/*]")))))))
+
+(defun js2-end-of-do-while-loop-p ()
+ "Return non-nil if word after point is `while' of a do-while
+statement, else returns nil. A braceless do-while statement
+spanning several lines requires that the start of the loop is
+indented to the same column as the current line."
+ (interactive)
+ (save-excursion
+ (when (looking-at "\\s-*\\_<while\\_>")
+ (if (save-excursion
+ (skip-chars-backward "[ \t\n]*}")
+ (looking-at "[ \t\n]*}"))
+ (save-excursion
+ (backward-list) (backward-word 1) (looking-at "\\_<do\\_>"))
+ (js2-re-search-backward "\\_<do\\_>" (point-at-bol) t)
+ (or (looking-at "\\_<do\\_>")
+ (let ((saved-indent (current-indentation)))
+ (while (and (js2-re-search-backward "^[ \t]*\\_<" nil t)
+ (/= (current-indentation) saved-indent)))
+ (and (looking-at "[ \t]*\\_<do\\_>")
+ (not (js2-re-search-forward
+ "\\_<while\\_>" (point-at-eol) t))
+ (= (current-indentation) saved-indent))))))))
+
+(defun js2-multiline-decl-indentation ()
+ "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)
+ (save-excursion
+ (back-to-indentation)
+ (when (not (looking-at js2-declaration-keyword-re))
+ (when (looking-at js2-indent-operator-re)
+ (goto-char (match-end 0))) ; continued expressions are ok
+ (while (and (not at-opening-bracket)
+ (not (bobp))
+ (let ((pos (point)))
+ (save-excursion
+ (js2-backward-sws)
+ (or (eq (char-before) ?,)
+ (and (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 _
+ (backward-sexp)
+ (scan-error (setq at-opening-bracket t))))
+ (when (looking-at js2-declaration-keyword-re)
+ (goto-char (match-end 0))
+ (1+ (current-column)))))))
+
+(defun js2-ctrl-statement-indentation ()
+ "Return the proper indentation of current line if it is a control statement.
+Returns an indentation if this line starts the body of a control
+statement without braces, else returns nil."
+ (let (forward-sexp-function)
+ (save-excursion
+ (back-to-indentation)
+ (when (and (not (js2-same-line (point-min)))
+ (not (looking-at "{"))
+ (js2-re-search-backward "[[:graph:]]" nil t)
+ (not (looking-at "[{([]"))
+ (progn
+ (forward-char)
+ (when (= (char-before) ?\))
+ ;; scan-sexps sometimes throws an error
+ (ignore-errors (backward-sexp))
+ (skip-chars-backward " \t" (point-at-bol)))
+ (let ((pt (point)))
+ (back-to-indentation)
+ (when (looking-at "}[ \t]*")
+ (goto-char (match-end 0)))
+ (and (looking-at js2-possibly-braceless-keywords-re)
+ (= (match-end 0) pt)
+ (not (js2-end-of-do-while-loop-p))))))
+ (+ (current-indentation) js2-basic-offset)))))
+
+(defun js2-indent-in-array-comp (parse-status)
+ "Return non-nil if we think we're in an array comprehension.
+In particular, return the buffer position of the first `for' kwd."
+ (let ((bracket (nth 1 parse-status))
+ (end (point)))
+ (when bracket
+ (save-excursion
+ (goto-char bracket)
+ (when (looking-at "\\[")
+ (forward-char 1)
+ (js2-forward-sws)
+ (if (looking-at "[[{]")
+ (let (forward-sexp-function) ; use Lisp version
+ (forward-sexp) ; skip destructuring form
+ (js2-forward-sws)
+ (if (and (/= (char-after) ?,) ; regular array
+ (looking-at "for"))
+ (match-beginning 0)))
+ ;; to skip arbitrary expressions we need the parser,
+ ;; so we'll just guess at it.
+ (if (and (> end (point)) ; not empty literal
+ (re-search-forward "[^,]]* \\(for\\) " end t)
+ ;; not inside comment or string literal
+ (let ((state (parse-partial-sexp bracket (point))))
+ (not (or (nth 3 state) (nth 4 state)))))
+ (match-beginning 1))))))))
+
+(defun js2-array-comp-indentation (parse-status for-kwd)
+ (if (js2-same-line for-kwd)
+ ;; first continuation line
+ (save-excursion
+ (goto-char (nth 1 parse-status))
+ (forward-char 1)
+ (skip-chars-forward " \t")
+ (current-column))
+ (save-excursion
+ (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))))))))
+
+(cl-defun js2-proper-indentation (parse-status)
+ "Return the proper indentation for the current line."
+ (save-excursion
+ (back-to-indentation)
+ (when (nth 4 parse-status)
+ (cl-return (js2-lineup-comment parse-status)))
+ (let* ((at-closing-bracket (looking-at "[]})]"))
+ (same-indent-p (or at-closing-bracket
+ (looking-at "\\_<case\\_>[^:]")
+ (and (looking-at "\\_<default:")
+ (save-excursion
+ (js2-backward-sws)
+ (not (memq (char-before) '(?, ?{)))))))
+ (continued-expr-p (js2-continued-expression-p))
+ (declaration-indent (and js2-pretty-multiline-declarations
+ (js2-multiline-decl-indentation)))
+ (bracket (nth 1 parse-status))
+ beg indent)
+ (cond
+ ;; indent array comprehension continuation lines specially
+ ((and bracket
+ (>= js2-language-version 170)
+ (not (js2-same-line bracket))
+ (setq beg (js2-indent-in-array-comp parse-status))
+ (>= (point) (save-excursion
+ (goto-char beg)
+ (point-at-bol)))) ; at or after first loop?
+ (js2-array-comp-indentation parse-status beg))
+
+ ((js2-ctrl-statement-indentation))
+
+ ((and declaration-indent continued-expr-p)
+ (+ declaration-indent js2-basic-offset))
+
+ (declaration-indent)
+
+ (bracket
+ (goto-char bracket)
+ (cond
+ ((looking-at "[({[][ \t]*\\(/[/*]\\|$\\)")
+ (when (save-excursion (skip-chars-backward " \t)")
+ (looking-at ")"))
+ (backward-list))
+ (back-to-indentation)
+ (js2-maybe-goto-declaration-keyword-end bracket)
+ (setq indent
+ (cond (same-indent-p
+ (current-column))
+ (continued-expr-p
+ (+ (current-column) (* 2 js2-basic-offset)))
+ (t
+ (+ (current-column) js2-basic-offset))))
+ (if (and js2-indent-switch-body
+ (not at-closing-bracket)
+ (looking-at "\\_<switch\\_>"))
+ (+ indent js2-basic-offset)
+ indent))
+ (t
+ (unless same-indent-p
+ (forward-char)
+ (skip-chars-forward " \t"))
+ (current-column))))
+
+ (continued-expr-p js2-basic-offset)
+
+ (t 0)))))
+
+(defun js2-lineup-comment (parse-status)
+ "Indent a multi-line block comment continuation line."
+ (let* ((beg (nth 8 parse-status))
+ (first-line (js2-same-line beg))
+ (offset (save-excursion
+ (goto-char beg)
+ (if (looking-at "/\\*")
+ (+ 1 (current-column))
+ 0))))
+ (unless first-line
+ (indent-line-to offset))))
+
+(defun js2-indent-line (&optional bounce-backwards)
+ "Indent the current line as JavaScript source text."
+ (interactive)
+ (let (parse-status offset
+ ;; Don't whine about errors/warnings when we're indenting.
+ ;; 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)))
+ offset (- (point) (save-excursion
+ (back-to-indentation)
+ (point))))
+ ;; Don't touch multiline strings.
+ (unless (nth 3 parse-status)
+ (indent-line-to (js2-proper-indentation parse-status))
+ (when (cl-plusp offset)
+ (forward-char offset)))))
+
+(provide 'js2-old-indent)
+
+;;; js2-old-indent.el ends here