Update packages
This commit is contained in:
349
elpa/js2-mode-20180724.801/js2-imenu-extras.el
Normal file
349
elpa/js2-mode-20180724.801/js2-imenu-extras.el
Normal file
@@ -0,0 +1,349 @@
|
||||
;;; js2-imenu-extras.el --- Imenu support for additional constructs
|
||||
|
||||
;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Dmitry Gutov <dgutov@yandex.ru>
|
||||
;; Keywords: languages, javascript, imenu
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This package adds Imenu support for additional framework constructs and
|
||||
;; structural patterns to `js2-mode'.
|
||||
|
||||
;; Usage:
|
||||
|
||||
;; (add-hook 'js2-mode-hook 'js2-imenu-extras-mode)
|
||||
|
||||
;; To customize how it works:
|
||||
;; M-x customize-group RET js2-imenu RET
|
||||
|
||||
(eval-when-compile
|
||||
(require 'cl))
|
||||
|
||||
(require 'js2-mode)
|
||||
|
||||
(defvar js2-imenu-extension-styles
|
||||
`((:framework jquery
|
||||
:call-re "\\_<\\(?:jQuery\\|\\$\\|_\\)\\.extend\\s-*("
|
||||
:recorder js2-imenu-record-jquery-extend)
|
||||
|
||||
(:framework jquery-ui
|
||||
:call-re "^\\s-*\\(?:jQuery\\|\\$\\)\\.widget\\s-*("
|
||||
:recorder js2-imenu-record-string-declare)
|
||||
|
||||
(:framework dojo
|
||||
:call-re "^\\s-*dojo.declare\\s-*("
|
||||
:recorder js2-imenu-record-string-declare)
|
||||
|
||||
(:framework backbone
|
||||
:call-re ,(concat "\\_<" js2-mode-identifier-re "\\.extend\\s-*(")
|
||||
:recorder js2-imenu-record-backbone-extend)
|
||||
|
||||
(:framework enyo
|
||||
:call-re "\\_<enyo\\.kind\\s-*("
|
||||
:recorder js2-imenu-record-enyo-kind)
|
||||
|
||||
(:framework react
|
||||
:call-re "\\_<React\\.createClass\\s-*("
|
||||
:recorder js2-imenu-record-react-class)
|
||||
|
||||
(:framework sencha
|
||||
:call-re "^\\s-*Ext\\.define\\s-*("
|
||||
:recorder js2-imenu-record-sencha-class))
|
||||
"List of JavaScript class definition or extension styles.
|
||||
|
||||
:framework is a valid value in `js2-imenu-enabled-frameworks'.
|
||||
|
||||
:call-re is a regular expression that has no capturing groups.
|
||||
|
||||
:recorder is a function name that will be called when the regular
|
||||
expression matches some text in the buffer. When it's called, point will be
|
||||
at the end of the match. The function must keep the point position.")
|
||||
|
||||
(defconst js2-imenu-available-frameworks
|
||||
(mapcar (lambda (style) (plist-get style :framework)) js2-imenu-extension-styles)
|
||||
"List of available JavaScript framework symbols.")
|
||||
|
||||
(defcustom js2-imenu-enabled-frameworks js2-imenu-available-frameworks
|
||||
"Frameworks to be recognized by `js2-mode'."
|
||||
:type (cons 'set (mapcar (lambda (x) (list 'const x))
|
||||
js2-imenu-available-frameworks))
|
||||
:group 'js2-imenu)
|
||||
|
||||
(defcustom js2-imenu-show-other-functions t
|
||||
"Non-nil to show functions not recognized by other mechanisms,
|
||||
in a shared namespace."
|
||||
:type 'boolean
|
||||
:group 'js2-imenu)
|
||||
|
||||
(defcustom js2-imenu-other-functions-ns "?"
|
||||
"Namespace name to use for other functions."
|
||||
:type 'string
|
||||
:group 'js2-imenu)
|
||||
|
||||
(defcustom js2-imenu-show-module-pattern t
|
||||
"Non-nil to recognize the module pattern:
|
||||
|
||||
var foobs = (function(a) {
|
||||
return {fib: function() {}, fub: function() {}};
|
||||
})(b);
|
||||
|
||||
We record the returned hash as belonging to the named module, and
|
||||
prefix any functions defined inside the IIFE with the module name."
|
||||
:type 'boolean
|
||||
:group 'js2-imenu)
|
||||
|
||||
(defcustom js2-imenu-split-string-identifiers t
|
||||
"When non-nil, split string identifiers on dots.
|
||||
Currently used for jQuery widgets, Dojo and Enyo declarations."
|
||||
:type 'boolean
|
||||
:group 'js2-imenu)
|
||||
|
||||
;;;###autoload
|
||||
(defun js2-imenu-extras-setup ()
|
||||
(when js2-imenu-enabled-frameworks
|
||||
(add-hook 'js2-build-imenu-callbacks 'js2-imenu-record-declarations t t))
|
||||
(when (or js2-imenu-show-other-functions js2-imenu-show-module-pattern)
|
||||
(add-hook 'js2-build-imenu-callbacks 'js2-imenu-walk-ast t t)))
|
||||
|
||||
(defun js2-imenu-extras-remove ()
|
||||
(remove-hook 'js2-build-imenu-callbacks 'js2-imenu-record-declarations t)
|
||||
(remove-hook 'js2-build-imenu-callbacks 'js2-imenu-walk-ast t))
|
||||
|
||||
(defun js2-imenu-record-declarations ()
|
||||
(let* ((styles (loop for style in js2-imenu-extension-styles
|
||||
when (memq (plist-get style :framework)
|
||||
js2-imenu-enabled-frameworks)
|
||||
collect style))
|
||||
(re (mapconcat (lambda (style)
|
||||
(concat "\\(" (plist-get style :call-re) "\\)"))
|
||||
styles "\\|")))
|
||||
(goto-char (point-min))
|
||||
(while (js2-re-search-forward re nil t)
|
||||
(loop for i from 0 to (1- (length styles))
|
||||
when (match-beginning (1+ i))
|
||||
return (funcall (plist-get (nth i styles) :recorder))))))
|
||||
|
||||
(defun js2-imenu-record-jquery-extend ()
|
||||
(let ((pred (lambda (subject)
|
||||
(and
|
||||
(js2-prop-get-node-p subject)
|
||||
(string= (js2-name-node-name (js2-prop-get-node-right subject))
|
||||
"prototype")))))
|
||||
(js2-imenu-record-extend-first-arg (1- (point)) pred
|
||||
'js2-compute-nested-prop-get)))
|
||||
|
||||
(defun js2-imenu-record-string-declare ()
|
||||
(js2-imenu-record-extend-first-arg
|
||||
(1- (point)) 'js2-string-node-p
|
||||
(lambda (node)
|
||||
(if js2-imenu-split-string-identifiers
|
||||
(split-string (js2-string-node-value node) "\\." t)
|
||||
(list (js2-string-node-value node))))))
|
||||
|
||||
(defun js2-imenu-record-extend-first-arg (point pred qname-fn)
|
||||
(let* ((node (js2-node-at-point point))
|
||||
(args (js2-call-node-args node))
|
||||
(subject (first args)))
|
||||
(when (funcall pred subject)
|
||||
(loop for arg in (cdr args)
|
||||
when (js2-object-node-p arg)
|
||||
do (js2-record-object-literal
|
||||
arg (funcall qname-fn subject) (js2-node-abs-pos arg))))))
|
||||
|
||||
(defun js2-imenu-record-backbone-or-react ()
|
||||
(let* ((node (js2-node-at-point (1- (point))))
|
||||
(args (js2-call-node-args node))
|
||||
(methods (first args))
|
||||
(parent (js2-node-parent node)))
|
||||
(when (js2-object-node-p methods)
|
||||
(let ((subject (cond ((js2-var-init-node-p parent)
|
||||
(js2-var-init-node-target parent))
|
||||
((js2-assign-node-p parent)
|
||||
(js2-assign-node-left parent)))))
|
||||
(when subject
|
||||
(js2-record-object-literal methods
|
||||
(js2-compute-nested-prop-get subject)
|
||||
(js2-node-abs-pos methods)))))))
|
||||
|
||||
(defalias 'js2-imenu-record-backbone-extend 'js2-imenu-record-backbone-or-react)
|
||||
|
||||
(defalias 'js2-imenu-record-react-class 'js2-imenu-record-backbone-or-react)
|
||||
|
||||
(defun js2-imenu-record-enyo-kind ()
|
||||
(let* ((node (js2-node-at-point (1- (point))))
|
||||
(args (js2-call-node-args node))
|
||||
(options (first args)))
|
||||
(when (js2-object-node-p options)
|
||||
(let ((name-value
|
||||
(loop for elem in (js2-object-node-elems options)
|
||||
thereis
|
||||
(let ((key (js2-object-prop-node-left elem))
|
||||
(value (js2-object-prop-node-right elem)))
|
||||
(when (and (equal
|
||||
(cond ((js2-name-node-p key)
|
||||
(js2-name-node-name key))
|
||||
((js2-string-node-p key)
|
||||
(js2-string-node-value key)))
|
||||
"name")
|
||||
(js2-string-node-p value))
|
||||
(js2-string-node-value value))))))
|
||||
(when name-value
|
||||
(js2-record-object-literal options
|
||||
(if js2-imenu-split-string-identifiers
|
||||
(split-string name-value "\\.")
|
||||
(list name-value))
|
||||
(js2-node-abs-pos options)))))))
|
||||
|
||||
(defun js2-imenu-record-sencha-class ()
|
||||
(let* ((node (js2-node-at-point (1- (point))))
|
||||
(args (js2-call-node-args node))
|
||||
(name (first args))
|
||||
(methods (second args)))
|
||||
(when (and (js2-string-node-p name) (js2-object-node-p methods))
|
||||
(let ((name-value (js2-string-node-value name)))
|
||||
(js2-record-object-literal methods
|
||||
(if js2-imenu-split-string-identifiers
|
||||
(split-string name-value "\\." t)
|
||||
(list name-value))
|
||||
(js2-node-abs-pos methods))))))
|
||||
|
||||
(defun js2-imenu-walk-ast ()
|
||||
(js2-visit-ast
|
||||
js2-mode-ast
|
||||
(lambda (node end-p)
|
||||
(unless end-p
|
||||
(cond
|
||||
((and js2-imenu-show-other-functions
|
||||
(js2-object-prop-node-p node))
|
||||
(js2-imenu-record-orphan-prop-node-function node))
|
||||
((js2-assign-node-p node)
|
||||
(cond
|
||||
((and js2-imenu-show-other-functions
|
||||
(js2-function-node-p
|
||||
(js2-assign-node-right node)))
|
||||
(js2-imenu-record-orphan-assign-node-function
|
||||
(js2-assign-node-left node)
|
||||
(js2-assign-node-right node)))
|
||||
((and js2-imenu-show-module-pattern
|
||||
(js2-call-node-p
|
||||
(js2-assign-node-right node)))
|
||||
(js2-imenu-record-module-pattern
|
||||
(js2-assign-node-left node)
|
||||
(js2-assign-node-right node)))))
|
||||
((js2-var-init-node-p node)
|
||||
(cond
|
||||
((and js2-imenu-show-other-functions
|
||||
(js2-function-node-p
|
||||
(js2-var-init-node-initializer node)))
|
||||
(js2-imenu-record-orphan-assign-node-function
|
||||
(js2-var-init-node-target node)
|
||||
(js2-var-init-node-initializer node)))
|
||||
((and js2-imenu-show-module-pattern
|
||||
(js2-call-node-p
|
||||
(js2-var-init-node-initializer node)))
|
||||
(js2-imenu-record-module-pattern
|
||||
(js2-var-init-node-target node)
|
||||
(js2-var-init-node-initializer node))))))
|
||||
t))))
|
||||
|
||||
(defun js2-imenu-parent-key-names (node)
|
||||
"Get the list of parent key names of NODE.
|
||||
|
||||
For example, for code
|
||||
|
||||
{rules: {password: {required: function() {}}}}
|
||||
|
||||
when NODE is the inner `js2-object-prop-mode',
|
||||
it returns `(\"rules\" \"password\")'."
|
||||
(let (rlt (n node))
|
||||
(while (setq n (js2-imenu-parent-prop-node n))
|
||||
(push (js2-prop-node-name (js2-object-prop-node-left n)) rlt))
|
||||
rlt))
|
||||
|
||||
(defun js2-imenu-parent-prop-node (node)
|
||||
"When the parent of NODE is `js2-object-node',
|
||||
and the grandparent is `js2-object-prop-node',
|
||||
return the grandparent."
|
||||
;; Suppose the code is:
|
||||
;; {parent-key: {required: function() {}}}
|
||||
;; NODE is `required: function() {}'.
|
||||
(let (p2 p3)
|
||||
;; Parent is `{required: function() {}}'.
|
||||
(setq p2 (js2-node-parent node))
|
||||
;; GP is `parent-key: {required: function() {}}'.
|
||||
(when (and p2 (js2-object-node-p p2))
|
||||
(setq p3 (js2-node-parent p2))
|
||||
(if (and p3 (js2-object-prop-node-p p3)) p3))))
|
||||
|
||||
(defun js2-imenu-record-orphan-prop-node-function (node)
|
||||
"Record orphan function when it's the value of NODE.
|
||||
NODE must be `js2-object-prop-node'."
|
||||
(when (js2-function-node-p (js2-object-prop-node-right node))
|
||||
(let ((fn-node (js2-object-prop-node-right node)))
|
||||
(unless (and js2-imenu-function-map
|
||||
(gethash fn-node js2-imenu-function-map))
|
||||
(let ((key-node (js2-object-prop-node-left node))
|
||||
(parent-prop-node (js2-imenu-parent-prop-node node))
|
||||
chain)
|
||||
(setq chain (nconc (js2-imenu-parent-key-names node)
|
||||
(list (js2-prop-node-name key-node))))
|
||||
(push js2-imenu-other-functions-ns chain)
|
||||
(js2-record-imenu-entry fn-node chain
|
||||
(js2-node-abs-pos key-node)))))))
|
||||
|
||||
(defun js2-imenu-record-orphan-assign-node-function (target-node fn-node)
|
||||
"Record orphan function FN-NODE assigned to node TARGET."
|
||||
(when (or (not js2-imenu-function-map)
|
||||
(eq 'skip
|
||||
(gethash fn-node js2-imenu-function-map 'skip)))
|
||||
(let ((chain (js2-compute-nested-prop-get target-node)))
|
||||
(when chain
|
||||
(push js2-imenu-other-functions-ns chain)
|
||||
(js2-record-imenu-entry fn-node chain (js2-node-abs-pos fn-node))))))
|
||||
|
||||
(defun js2-imenu-record-module-pattern (target init)
|
||||
"Recognize and record module pattern use instance.
|
||||
INIT must be `js2-call-node'."
|
||||
(let ((callt (js2-call-node-target init)))
|
||||
;; Just basic call form: (function() {...})();
|
||||
;; TODO: Handle variations without duplicating `js2-wrapper-function-p'?
|
||||
(when (and (js2-paren-node-p callt)
|
||||
(js2-function-node-p (js2-paren-node-expr callt)))
|
||||
(let* ((fn (js2-paren-node-expr callt))
|
||||
(blk (js2-function-node-body fn))
|
||||
(ret (car (last (js2-block-node-kids blk)))))
|
||||
(when (and (js2-return-node-p ret)
|
||||
(js2-object-node-p (js2-return-node-retval ret)))
|
||||
;; TODO: Map function names when revealing module pattern is used.
|
||||
(let ((retval (js2-return-node-retval ret))
|
||||
(target-qname (js2-compute-nested-prop-get target)))
|
||||
(js2-record-object-literal retval target-qname
|
||||
(js2-node-abs-pos retval))
|
||||
(js2-record-imenu-entry fn target-qname
|
||||
(js2-node-abs-pos target))))))))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode js2-imenu-extras-mode
|
||||
"Toggle Imenu support for frameworks and structural patterns."
|
||||
:lighter ""
|
||||
(if js2-imenu-extras-mode
|
||||
(js2-imenu-extras-setup)
|
||||
(js2-imenu-extras-remove)))
|
||||
|
||||
(provide 'js2-imenu-extras)
|
||||
82
elpa/js2-mode-20180724.801/js2-mode-autoloads.el
Normal file
82
elpa/js2-mode-20180724.801/js2-mode-autoloads.el
Normal file
@@ -0,0 +1,82 @@
|
||||
;;; js2-mode-autoloads.el --- automatically extracted autoloads
|
||||
;;
|
||||
;;; Code:
|
||||
|
||||
(add-to-list 'load-path (directory-file-name
|
||||
(or (file-name-directory #$) (car load-path))))
|
||||
|
||||
|
||||
;;;### (autoloads nil "js2-imenu-extras" "js2-imenu-extras.el" (0
|
||||
;;;;;; 0 0 0))
|
||||
;;; Generated autoloads from js2-imenu-extras.el
|
||||
|
||||
(autoload 'js2-imenu-extras-setup "js2-imenu-extras" "\
|
||||
|
||||
|
||||
\(fn)" nil nil)
|
||||
|
||||
(autoload 'js2-imenu-extras-mode "js2-imenu-extras" "\
|
||||
Toggle Imenu support for frameworks and structural patterns.
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "js2-imenu-extras" '("js2-imenu-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "js2-mode" "js2-mode.el" (0 0 0 0))
|
||||
;;; Generated autoloads from js2-mode.el
|
||||
|
||||
(autoload 'js2-highlight-unused-variables-mode "js2-mode" "\
|
||||
Toggle highlight of unused variables.
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(autoload 'js2-minor-mode "js2-mode" "\
|
||||
Minor mode for running js2 as a background linter.
|
||||
This allows you to use a different major mode for JavaScript editing,
|
||||
such as `js-mode', while retaining the asynchronous error/warning
|
||||
highlighting features of `js2-mode'.
|
||||
|
||||
\(fn &optional ARG)" t nil)
|
||||
|
||||
(autoload 'js2-mode "js2-mode" "\
|
||||
Major mode for editing JavaScript code.
|
||||
|
||||
\(fn)" t nil)
|
||||
|
||||
(autoload 'js2-jsx-mode "js2-mode" "\
|
||||
Major mode for editing JSX code.
|
||||
|
||||
To customize the indentation for this mode, set the SGML offset
|
||||
variables (`sgml-basic-offset' et al) locally, like so:
|
||||
|
||||
(defun set-jsx-indentation ()
|
||||
(setq-local sgml-basic-offset js2-basic-offset))
|
||||
(add-hook \\='js2-jsx-mode-hook #\\='set-jsx-indentation)
|
||||
|
||||
\(fn)" t nil)
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "js2-mode" '("js2-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "js2-old-indent" "js2-old-indent.el" (0 0 0
|
||||
;;;;;; 0))
|
||||
;;; Generated autoloads from js2-old-indent.el
|
||||
|
||||
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "js2-old-indent" '("js2-")))
|
||||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil nil ("js2-mode-pkg.el") (0 0 0 0))
|
||||
|
||||
;;;***
|
||||
|
||||
;; Local Variables:
|
||||
;; version-control: never
|
||||
;; no-byte-compile: t
|
||||
;; no-update-autoloads: t
|
||||
;; coding: utf-8
|
||||
;; End:
|
||||
;;; js2-mode-autoloads.el ends here
|
||||
15
elpa/js2-mode-20180724.801/js2-mode-pkg.el
Normal file
15
elpa/js2-mode-20180724.801/js2-mode-pkg.el
Normal file
@@ -0,0 +1,15 @@
|
||||
(define-package "js2-mode" "20180724.801" "Improved JavaScript editing mode"
|
||||
'((emacs "24.1")
|
||||
(cl-lib "0.5"))
|
||||
:keywords
|
||||
'("languages" "javascript")
|
||||
:authors
|
||||
'(("Steve Yegge" . "steve.yegge@gmail.com")
|
||||
("mooz" . "stillpedant@gmail.com")
|
||||
("Dmitry Gutov" . "dgutov@yandex.ru"))
|
||||
:maintainer
|
||||
'("Steve Yegge" . "steve.yegge@gmail.com")
|
||||
:url "https://github.com/mooz/js2-mode/")
|
||||
;; Local Variables:
|
||||
;; no-byte-compile: t
|
||||
;; End:
|
||||
12856
elpa/js2-mode-20180724.801/js2-mode.el
Normal file
12856
elpa/js2-mode-20180724.801/js2-mode.el
Normal file
File diff suppressed because it is too large
Load Diff
712
elpa/js2-mode-20180724.801/js2-old-indent.el
Normal file
712
elpa/js2-mode-20180724.801/js2-old-indent.el
Normal file
@@ -0,0 +1,712 @@
|
||||
;;; 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:
|
||||
|
||||
(require 'sgml-mode)
|
||||
|
||||
(defvar js2-language-version)
|
||||
|
||||
(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") 'symbols))
|
||||
"Regular expression matching operators that affect indentation
|
||||
of continued expressions.")
|
||||
|
||||
(defconst js2-declaration-keyword-re
|
||||
(regexp-opt '("var" "let" "const") 'symbols)
|
||||
"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."
|
||||
(defvar js2-mode-identifier-re)
|
||||
(and (looking-at js2-indent-operator-re)
|
||||
(or (not (eq (char-after) ?:))
|
||||
(save-excursion
|
||||
(and (js2-re-search-backward "[?:{]\\|\\_<case\\_>" nil t)
|
||||
(eq (char-after) ??))))
|
||||
(not (and
|
||||
(eq (char-after) ?/)
|
||||
(save-excursion
|
||||
(eq (nth 3 (syntax-ppss)) ?/))))
|
||||
(not (and
|
||||
(eq (char-after) ?*)
|
||||
;; Generator method (possibly using computed property).
|
||||
(looking-at (concat "\\* *\\(?:\\[\\|"
|
||||
js2-mode-identifier-re
|
||||
" *(\\)"))
|
||||
(save-excursion
|
||||
(js2-backward-sws)
|
||||
;; We might misindent some expressions that would
|
||||
;; return NaN anyway. Shouldn't be a problem.
|
||||
(memq (char-before) '(?, ?} ?{)))))))
|
||||
|
||||
(defun js2-continued-expression-p ()
|
||||
"Return non-nil if the current line continues an expression."
|
||||
(save-excursion
|
||||
(back-to-indentation)
|
||||
(if (js2-looking-at-operator-p)
|
||||
(or (not (memq (char-after) '(?- ?+)))
|
||||
(progn
|
||||
(forward-comment (- (point)))
|
||||
(not (memq (char-before) '(?, ?\[ ?\()))))
|
||||
(forward-comment (- (point)))
|
||||
(or (bobp) (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))))
|
||||
(and (= 1 (car state))
|
||||
(not (nth 8 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-from js2-proper-indentation (js2--comment-indent 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\n)")
|
||||
(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--comment-indent (parse-status)
|
||||
"Indentation inside a multi-line block comment continuation line."
|
||||
(save-excursion
|
||||
(goto-char (nth 8 parse-status))
|
||||
(if (looking-at "/\\*")
|
||||
(+ 1 (current-column))
|
||||
0)))
|
||||
|
||||
(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)))))
|
||||
|
||||
;;; JSX Indentation
|
||||
|
||||
;; The following JSX indentation code is copied basically verbatim from js.el at
|
||||
;; 958da7f, except that the prefixes on the functions/variables are changed.
|
||||
|
||||
(defsubst js2--jsx-find-before-tag ()
|
||||
"Find where JSX starts.
|
||||
|
||||
Assume JSX appears in the following instances:
|
||||
- Inside parentheses, when returned or as the first argument
|
||||
to a function, and after a newline
|
||||
- When assigned to variables or object properties, but only
|
||||
on a single line
|
||||
- As the N+1th argument to a function
|
||||
|
||||
This is an optimized version of (re-search-backward \"[(,]\n\"
|
||||
nil t), except set point to the end of the match. This logic
|
||||
executes up to the number of lines in the file, so it should be
|
||||
really fast to reduce that impact."
|
||||
(let (pos)
|
||||
(while (and (> (point) (point-min))
|
||||
(not (progn
|
||||
(end-of-line 0)
|
||||
(when (or (eq (char-before) 40) ; (
|
||||
(eq (char-before) 44)) ; ,
|
||||
(setq pos (1- (point))))))))
|
||||
pos))
|
||||
|
||||
(defconst js2--jsx-end-tag-re
|
||||
(concat "</" sgml-name-re ">\\|/>")
|
||||
"Find the end of a JSX element.")
|
||||
|
||||
(defconst js2--jsx-after-tag-re "[),]"
|
||||
"Find where JSX ends.
|
||||
This complements the assumption of where JSX appears from
|
||||
`js--jsx-before-tag-re', which see.")
|
||||
|
||||
(defun js2--jsx-indented-element-p ()
|
||||
"Determine if/how the current line should be indented as JSX.
|
||||
|
||||
Return `first' for the first JSXElement on its own line.
|
||||
Return `nth' for subsequent lines of the first JSXElement.
|
||||
Return `expression' for an embedded JS expression.
|
||||
Return `after' for anything after the last JSXElement.
|
||||
Return nil for non-JSX lines.
|
||||
|
||||
Currently, JSX indentation supports the following styles:
|
||||
|
||||
- Single-line elements (indented like normal JS):
|
||||
|
||||
var element = <div></div>;
|
||||
|
||||
- Multi-line elements (enclosed in parentheses):
|
||||
|
||||
function () {
|
||||
return (
|
||||
<div>
|
||||
<div></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
- Function arguments:
|
||||
|
||||
React.render(
|
||||
<div></div>,
|
||||
document.querySelector('.root')
|
||||
);"
|
||||
(let ((current-pos (point))
|
||||
(current-line (line-number-at-pos))
|
||||
last-pos
|
||||
before-tag-pos before-tag-line
|
||||
tag-start-pos tag-start-line
|
||||
tag-end-pos tag-end-line
|
||||
after-tag-line
|
||||
parens paren type)
|
||||
(save-excursion
|
||||
(and
|
||||
;; Determine if we're inside a jsx element
|
||||
(progn
|
||||
(end-of-line)
|
||||
(while (and (not tag-start-pos)
|
||||
(setq last-pos (js2--jsx-find-before-tag)))
|
||||
(while (forward-comment 1))
|
||||
(when (= (char-after) 60) ; <
|
||||
(setq before-tag-pos last-pos
|
||||
tag-start-pos (point)))
|
||||
(goto-char last-pos))
|
||||
tag-start-pos)
|
||||
(progn
|
||||
(setq before-tag-line (line-number-at-pos before-tag-pos)
|
||||
tag-start-line (line-number-at-pos tag-start-pos))
|
||||
(and
|
||||
;; A "before" line which also starts an element begins with js, so
|
||||
;; indent it like js
|
||||
(> current-line before-tag-line)
|
||||
;; Only indent the jsx lines like jsx
|
||||
(>= current-line tag-start-line)))
|
||||
(cond
|
||||
;; Analyze bounds if there are any
|
||||
((progn
|
||||
(while (and (not tag-end-pos)
|
||||
(setq last-pos (re-search-forward js2--jsx-end-tag-re nil t)))
|
||||
(while (forward-comment 1))
|
||||
(when (looking-at js2--jsx-after-tag-re)
|
||||
(setq tag-end-pos last-pos)))
|
||||
tag-end-pos)
|
||||
(setq tag-end-line (line-number-at-pos tag-end-pos)
|
||||
after-tag-line (line-number-at-pos after-tag-line))
|
||||
(or (and
|
||||
;; Ensure we're actually within the bounds of the jsx
|
||||
(<= current-line tag-end-line)
|
||||
;; An "after" line which does not end an element begins with
|
||||
;; js, so indent it like js
|
||||
(<= current-line after-tag-line))
|
||||
(and
|
||||
;; Handle another case where there could be e.g. comments after
|
||||
;; the element
|
||||
(> current-line tag-end-line)
|
||||
(< current-line after-tag-line)
|
||||
(setq type 'after))))
|
||||
;; They may not be any bounds (yet)
|
||||
(t))
|
||||
;; Check if we're inside an embedded multi-line js expression
|
||||
(cond
|
||||
((not type)
|
||||
(goto-char current-pos)
|
||||
(end-of-line)
|
||||
(setq parens (nth 9 (syntax-ppss)))
|
||||
(while (and parens (not type))
|
||||
(setq paren (car parens))
|
||||
(cond
|
||||
((and (>= paren tag-start-pos)
|
||||
;; Curly bracket indicates the start of an embedded expression
|
||||
(= (char-after paren) 123) ; {
|
||||
;; The first line of the expression is indented like sgml
|
||||
(> current-line (line-number-at-pos paren))
|
||||
;; Check if within a closing curly bracket (if any)
|
||||
;; (exclusive, as the closing bracket is indented like sgml)
|
||||
(cond
|
||||
((progn
|
||||
(goto-char paren)
|
||||
(ignore-errors (let (forward-sexp-function)
|
||||
(forward-sexp))))
|
||||
(< current-line (line-number-at-pos)))
|
||||
(t)))
|
||||
;; Indicate this guy will be indented specially
|
||||
(setq type 'expression))
|
||||
(t (setq parens (cdr parens)))))
|
||||
t)
|
||||
(t))
|
||||
(cond
|
||||
(type)
|
||||
;; Indent the first jsx thing like js so we can indent future jsx things
|
||||
;; like sgml relative to the first thing
|
||||
((= current-line tag-start-line) 'first)
|
||||
('nth))))))
|
||||
|
||||
(defmacro js2--as-sgml (&rest body)
|
||||
"Execute BODY as if in sgml-mode."
|
||||
`(with-syntax-table sgml-mode-syntax-table
|
||||
(let (forward-sexp-function
|
||||
parse-sexp-lookup-properties)
|
||||
,@body)))
|
||||
|
||||
(defun js2--expression-in-sgml-indent-line ()
|
||||
"Indent the current line as JavaScript or SGML (whichever is farther)."
|
||||
(let* (indent-col
|
||||
(savep (point))
|
||||
;; 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)
|
||||
(parse-status (save-excursion
|
||||
(syntax-ppss (point-at-bol)))))
|
||||
;; Don't touch multiline strings.
|
||||
(unless (nth 3 parse-status)
|
||||
(setq indent-col (save-excursion
|
||||
(back-to-indentation)
|
||||
(if (>= (point) savep) (setq savep nil))
|
||||
(js2--as-sgml (sgml-calculate-indent))))
|
||||
(if (null indent-col)
|
||||
'noindent
|
||||
;; Use whichever indentation column is greater, such that the sgml
|
||||
;; column is effectively a minimum
|
||||
(setq indent-col (max (js2-proper-indentation parse-status)
|
||||
(+ indent-col js2-basic-offset)))
|
||||
(if savep
|
||||
(save-excursion (indent-line-to indent-col))
|
||||
(indent-line-to indent-col))))))
|
||||
|
||||
(defun js2-jsx-indent-line ()
|
||||
"Indent the current line as JSX (with SGML offsets).
|
||||
i.e., customize JSX element indentation with `sgml-basic-offset'
|
||||
et al."
|
||||
(interactive)
|
||||
(let ((indentation-type (js2--jsx-indented-element-p)))
|
||||
(cond
|
||||
((eq indentation-type 'expression)
|
||||
(js2--expression-in-sgml-indent-line))
|
||||
((or (eq indentation-type 'first)
|
||||
(eq indentation-type 'after))
|
||||
;; Don't treat this first thing as a continued expression (often a "<" or
|
||||
;; ">" causes this misinterpretation)
|
||||
(cl-letf (((symbol-function #'js2-continued-expression-p) 'ignore))
|
||||
(js2-indent-line)))
|
||||
((eq indentation-type 'nth)
|
||||
(js2--as-sgml (sgml-indent-line)))
|
||||
(t (js2-indent-line)))))
|
||||
|
||||
(provide 'js2-old-indent)
|
||||
|
||||
;;; js2-old-indent.el ends here
|
||||
Reference in New Issue
Block a user