Skip to content

Commit

Permalink
Wrapping inline jsx element is now supported.
Browse files Browse the repository at this point in the history
  • Loading branch information
llemaitre19 committed Nov 24, 2023
1 parent 71c5274 commit dc8bd8b
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 13 deletions.
40 changes: 27 additions & 13 deletions jtsx.el
Original file line number Diff line number Diff line change
Expand Up @@ -521,30 +521,44 @@ ELEMENT-NAME is the name of the new wrapping element."
(interactive "sJSX element name: ")
(if (jtsx-jsx-context-p)
(let* ((start-pos (if (region-active-p) (plist-get (jtsx-trimmed-region) :start) (point)))
(end-pos (if (region-active-p) (plist-get (jtsx-trimmed-region) :end) (point)))
;; For the end position, it is safer to go back by one character as treesit looks at
;; the node after the position (excepted when at the end of the line).
;; This is usefull for inline elements.
(end-pos (if (region-active-p) (1- (plist-get (jtsx-trimmed-region) :end)) (point)))
(element-start (jtsx-enclosing-jsx-node (treesit-node-at start-pos)
jtsx-jsx-ts-root-keys nil t t))
(element-end (if (region-active-p)
(jtsx-enclosing-jsx-node (treesit-node-at end-pos)
jtsx-jsx-ts-root-keys nil t t)
element-start)))
(cl-assert (and element-start element-end) "Not able to retrieve node start or node end.")
(let ((opening-line (line-number-at-pos (treesit-node-start element-start)))
(closing-line (1+ (line-number-at-pos (treesit-node-end element-end)))) ; +1 for
;; insertion
(opening-tag (format "<%s>\n" element-name))
(closing-tag (format "</%s>\n" element-name)))
(let* ((final-start-pos (treesit-node-start element-start))
(final-end-pos (treesit-node-end element-end))
;; Opening tag is considered inline if something is before it on the same line.
;; Same consideration for closing tag, but after it.
(inline-opening (not (eq final-start-pos (save-excursion (goto-char final-start-pos)
(back-to-indentation)
(point)))))
(inline-closing (not (eq final-end-pos (save-excursion (goto-char final-end-pos)
(pos-eol)))))
(opening-line (line-number-at-pos (treesit-node-start element-start)))
(closing-line (+ (line-number-at-pos (treesit-node-end element-end))
(if inline-closing 0 1))) ; +1 for insertion if not inline
(opening-tag (format "<%s>%s" element-name (if inline-opening "" "\n")))
(closing-tag (format "</%s>%s" element-name (if inline-closing "" "\n"))))
(save-excursion
(jtsx-goto-line closing-line)
(if inline-closing (goto-char final-end-pos) (jtsx-goto-line closing-line))
(insert closing-tag)
(jtsx-goto-line opening-line)
(if inline-opening (goto-char final-start-pos) (jtsx-goto-line opening-line))
(insert opening-tag))
(indent-region (save-excursion (jtsx-goto-line opening-line) (pos-bol))
(save-excursion (jtsx-goto-line (1+ closing-line)) (pos-eol))) ; + 1
;; because of the opening tag insertion
(jtsx-goto-line opening-line)
;; Let the cursor ready to add attributes in the wrapping element
(goto-char final-start-pos)
(search-forward ">")
(backward-char 1))) ; Let the cursor ready to add attributes
(backward-char 1)
;; Finally indent modified region
(indent-region (save-excursion (jtsx-goto-line opening-line) (pos-bol))
(save-excursion (jtsx-goto-line (+ closing-line (if inline-opening 0 1)))
(pos-eol)))))
(message "Not inside jsx context.")))

(defun jtsx-hs-forward-sexp (n)
Expand Down
14 changes: 14 additions & 0 deletions tests/jtsx-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,20 @@ Turn this buffer in MODE mode if supplied or defaults to jtsx-tsx-mode."
(should (equal (wrap-in-jsx-element-into-buffer content set-region #'jtsx-jsx-mode) result))
(should (equal (wrap-in-jsx-element-into-buffer content set-region #'jtsx-tsx-mode) result))))

(ert-deftest jtsx-test-wrap-inline-element-at-point ()
(let ((move-point #'(lambda () (goto-char 4)))
(content "(<><A /></>);")
(result "(<><W><A /></W></>);"))
(should (equal (wrap-in-jsx-element-into-buffer content move-point #'jtsx-jsx-mode) result))
(should (equal (wrap-in-jsx-element-into-buffer content move-point #'jtsx-tsx-mode) result))))

(ert-deftest jtsx-test-wrap-inline-element-region ()
(let ((set-region #'(lambda () (find-and-set-region "<A />")))
(content "(<><A /></>);")
(result "(<><W><A /></W></>);"))
(should (equal (wrap-in-jsx-element-into-buffer content set-region #'jtsx-jsx-mode) result))
(should (equal (wrap-in-jsx-element-into-buffer content set-region #'jtsx-tsx-mode) result))))

;; TEST HIDESHOW CUSTOMIZATION
(ert-deftest jtsx-test-hs-forward-sexp-jsx-element ()
(let ((move-point #'(lambda () (goto-char 2)))
Expand Down

0 comments on commit dc8bd8b

Please sign in to comment.