Commit ae0ee9bc authored by Jackson Ray Hamilton's avatar Jackson Ray Hamilton Committed by Marcin Borkowski

Split JSX indentation calculation into several functions

* lisp/progmodes/js.el (js-jsx--contextual-indentation)
(js-jsx--expr-attribute-pos, js-jsx--expr-indentation): Extract logic
from js-jsx--indentation, and improve the logic’s documentation.
(js-jsx--indentation): Simplify by splitting into several
functions (see above) and improve the logic’s documentation.
parent 2b4cc702
......@@ -2575,40 +2575,10 @@ current line is the \"=>\" token (of an arrow function)."
(list 'tag (nth 0 enclosing-tag-pos) (nth 1 enclosing-tag-pos)))
(list 'text (nth 0 enclosing-tag-pos) (nth 2 enclosing-tag-pos))))))
(defvar js-jsx--indent-col nil
"Baseline column for JS indentation within JSX.")
(defvar js-jsx--indent-attribute-line nil
"Line relative to which indentation uses JSX as a baseline.")
(defun js-jsx--indentation (parse-status)
"Helper function for `js--proper-indentation'.
Return the proper indentation of the current line if it is part
of a JSXElement expression spanning multiple lines; otherwise,
return nil."
(let ((current-line (line-number-at-pos))
(curly-pos (js-jsx--enclosing-curly-pos))
nth-context context expr-p beg-line col
forward-sexp-function) ; Use the Lisp version.
;; Find the immediate context for indentation information, but
;; keep going to determine that point is at the N+1th line of
;; multiline JSX.
(save-excursion
(while
(and
(setq nth-context (js-jsx--context))
(progn
(unless context
(setq context nth-context)
(setq expr-p (and curly-pos (< (point) curly-pos))))
(setq beg-line (line-number-at-pos))
(and
(= beg-line current-line)
(or (not curly-pos) (> (point) curly-pos)))))))
(when (and context (> current-line beg-line))
(save-excursion
;; The column calculation is based on `sgml-calculate-indent'.
(setq col (pcase (nth 0 context)
(defun js-jsx--contextual-indentation (line context)
"Calculate indentation column for LINE from CONTEXT.
The column calculation is based off of `sgml-calculate-indent'."
(pcase (nth 0 context)
('string
;; Go back to previous non-empty line.
......@@ -2622,14 +2592,13 @@ return nil."
(1+ (current-column))))
('tag
;; Special JSX indentation rule: a “dangling”
;; closing angle bracket on its own line is
;; indented at the same level as the opening
;; angle bracket of the JSXElement. Otherwise,
;; indent JSXAttribute space like SGML.
;; Special JSX indentation rule: a “dangling” closing angle
;; bracket on its own line is indented at the same level as the
;; opening angle bracket of the JSXElement. Otherwise, indent
;; JSXAttribute space like SGML.
(if (progn
(goto-char (nth 2 context))
(and (= current-line (line-number-at-pos))
(and (= line (line-number-at-pos))
(looking-back "^\\s-*/?>" (line-beginning-position))))
(progn
(goto-char (nth 1 context))
......@@ -2652,27 +2621,74 @@ return nil."
(+ (current-column)
;; The last line isn’t nested, but the rest are.
(if (or (not (nth 2 context)) ; Unclosed.
(< current-line (line-number-at-pos (nth 2 context))))
(< line (line-number-at-pos (nth 2 context))))
js-indent-level
0)))
)))
;; To indent a JSXExpressionContainer’s expression, calculate
;; the JS indentation, possibly using JSX indentation as the
;; base column.
(if expr-p
(let* ((js-jsx--indent-col col)
(expr-attribute-pos
))
(defun js-jsx--expr-attribute-pos (start limit)
"Look back from START to LIMIT for a JSXAttribute."
(save-excursion
(goto-char curly-pos) ; Skip first curly.
;; Skip any remaining enclosing curlies up until
;; the contextual JSXElement’s beginning position.
(js-jsx--goto-outermost-enclosing-curly (nth 1 context))
(goto-char start) ; Skip the first curly.
;; Skip any remaining enclosing curlies until the JSXElement’s
;; beginning position; the last curly ought to be one of a
;; JSXExpressionContainer, which may refer to its JSXAttribute’s
;; beginning position (if it has one).
(js-jsx--goto-outermost-enclosing-curly limit)
(get-text-property (point) 'js-jsx-expr-attribute)))
(defvar js-jsx--indent-col nil
"Baseline column for JS indentation within JSX.")
(defvar js-jsx--indent-attribute-line nil
"Line relative to which indentation uses JSX as a baseline.")
(defun js-jsx--expr-indentation (parse-status pos col)
"Indent using PARSE-STATUS; relative to POS, use base COL.
To indent a JSXExpressionContainer’s expression, calculate the JS
indentation, using JSX indentation as the base column when
indenting relative to the beginning line of the
JSXExpressionContainer’s JSXAttribute (if any)."
(let* ((js-jsx--indent-col col)
(js-jsx--indent-attribute-line
(when expr-attribute-pos
(line-number-at-pos expr-attribute-pos))))
(js--proper-indentation parse-status))
(if pos (line-number-at-pos pos))))
(js--proper-indentation parse-status)))
(defun js-jsx--indentation (parse-status)
"Helper function for `js--proper-indentation'.
Return the proper indentation of the current line if it is part
of a JSXElement expression spanning multiple lines; otherwise,
return nil."
(let ((current-line (line-number-at-pos))
(curly-pos (js-jsx--enclosing-curly-pos))
nth-context context expr-p beg-line col
forward-sexp-function) ; Use the Lisp version.
;; Find the immediate context for indentation information, but
;; keep going to determine that point is at the N+1th line of
;; multiline JSX.
(save-excursion
(while
(and
(setq nth-context (js-jsx--context))
(progn
(unless context
(setq context nth-context)
(setq expr-p (and curly-pos (< (point) curly-pos))))
(setq beg-line (line-number-at-pos))
(and
(= beg-line current-line)
(or (not curly-pos) (> (point) curly-pos)))))))
;; When on the second or later line of JSX, indent as JSX,
;; possibly switching back to JS indentation within
;; JSXExpressionContainers, possibly using the JSX as a base
;; column while switching back to JS indentation.
(when (and context (> current-line beg-line))
(save-excursion
(setq col (js-jsx--contextual-indentation current-line context)))
(if expr-p
(js-jsx--expr-indentation
parse-status (js-jsx--expr-attribute-pos curly-pos (nth 1 context)) col)
col))))
(defun js--proper-indentation (parse-status)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment