rjsx-mode
rjsx-mode copied to clipboard
[Not a bug] How could I get rjsx-mode to newline and indent when I'm in between tags?
When you press RET between {} it does the following (where | is the cursor):
{|}
{
[indent-level] |
}
How can I get rjsx-mode to do the same with html/react component tags
<component>|</component>
RET
<component>
[indent-level] |
</component>
Seems like I managed to bring this functionality from web-mode in a very hackish way.
And I'm using Doom Emacs, but this shouldn't be too hard to modify for vanilla emacs:
(when (featurep! :lang javascript)
(setq-default js-indent-level 2)
(when (featurep! :lang web)
;; Web mode tag expansion in rjsx
(after! rjsx-mode
(defun ~+javascript-rjsx-mode-h ()
(require 'web-mode)
(setq web-mode-markup-indent-offset 2)
(add-hook 'after-change-functions 'web-mode-on-after-change nil t)
(add-hook 'post-command-hook 'web-mode-on-post-command nil t))
(setq ~+javascript-rjsx-do-web-mode-indent nil)
(defun ~+javascript-rjsx-newline-and-indent-a ()
(when (derived-mode-p 'rjsx-mode)
(setq ~+javascript-rjsx-do-web-mode-indent t)))
(defun ~+javascript-rjsx-indent-line-a ()
(when (and (derived-mode-p 'rjsx-mode)
~+javascript-rjsx-do-web-mode-indent)
(web-mode-indent-line)
(setq ~+javascript-rjsx-do-web-mode-indent nil)))
(advice-add 'newline-and-indent :before #'~+javascript-rjsx-newline-and-indent-a)
(advice-add 'rjsx-indent-line :before #'~+javascript-rjsx-indent-line-a)
(add-hook 'rjsx-mode-hook #'~+javascript-rjsx-mode-h))))
Seems like a very heavyweight solution. Here's what electric-pair does in case you want to adapt. (Check out electric-pair-post-self-insert-function)
- Use
post-self-insert-hookand check for newline(eq last-command-event ?\n) - Check if we are in a region of whitespace between two matchings "pairs". This would be the rjsx-specific bit. You could do a quick regex/syntax check for
>preceding and</following followed by confirmation via the AST (save-excursion (newline 1 t))
(when (and (if (functionp electric-pair-open-newline-between-pairs)
(funcall electric-pair-open-newline-between-pairs)
electric-pair-open-newline-between-pairs)
(eq last-command-event ?\n)
(< (1+ (point-min)) (point) (point-max))
(eq (save-excursion
(skip-chars-backward "\t\s")
(char-before (1- (point))))
(matching-paren (char-after))))
(save-excursion (newline 1 t)))
For some reason this doesn't work at all. Even (matching-paren (char-after)) is failing right before the <. It only works for (){}.
And I've now mapped a lot of refactoring functions from web-mode so I think I'll stick to it for now.
Thanks for the idea though.
For those that want a quick fix that just works similarly to web-mode
(defun tag-expand ()
(interactive)
(if (and
(looking-at "[ \t]*<")
(looking-back ">[ \t]*"))
(progn (newline-and-indent)
(save-excursion (newline-and-indent))
(indent-according-to-mode))
(newline-and-indent)))
(add-hook 'rjsx-mode-hook (lambda () (local-set-key (kbd "RET") 'tag-expand)))