Skip to content

Instantly share code, notes, and snippets.

@rangeoshun
Last active June 12, 2023 15:45
Show Gist options
  • Save rangeoshun/67cb17392c523579bc6cbd758b2315c1 to your computer and use it in GitHub Desktop.
Save rangeoshun/67cb17392c523579bc6cbd758b2315c1 to your computer and use it in GitHub Desktop.
Typescript with CSS in JS (styled-components, Emotion), JSX and graphql highlight and major mode for Emacs Doom with `mmm-mode` for *.tsx
;; Assign typescript-mode to .tsx files
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . typescript-mode))
(require 'mmm-mode)
(setq mmm-global-mode t)
(setq mmm-submode-decoration-level 0) ;; Turn off background highlight
;; Add css mode for CSS in JS blocks
(mmm-add-classes
'((mmm-styled-mode
:submode css-mode
:front "\\(styled\\|css\\)[.()<>[:alnum:]]?+`"
:back "`;")))
(mmm-add-mode-ext-class 'typescript-mode nil 'mmm-styled-mode)
;; Add submodule for graphql blocks
(mmm-add-classes
'((mmm-graphql-mode
:submode graphql-mode
:front "gr?a?p?h?ql`"
:back "`;")))
(mmm-add-mode-ext-class 'typescript-mode nil 'mmm-graphql-mode)
;; Add JSX submodule, because typescript-mode is not that great at it
(mmm-add-classes
'((mmm-jsx-mode
:front "\\(return\s\\|n\s\\|(\n\s*\\)<"
:front-offset -1
:back ">\n?\s*)"
:back-offset 1
:submode web-mode)))
(mmm-add-mode-ext-class 'typescript-mode nil 'mmm-jsx-mode)
(defun mmm-reapply ()
(mmm-mode)
(mmm-mode))
(add-hook 'after-save-hook
(lambda ()
(when (string-match-p "\\.tsx?" buffer-file-name)
(mmm-reapply))))
;; Packages used in config.el for regular emacs you'll need `use-package` I guess
(package! mmm-mode)
(package! typescript-mode)
(package! web-mode)
(package! graphql-mode)
@rangeoshun
Copy link
Author

rangeoshun commented Oct 21, 2019

Screenshot 2019-10-22 at 8 50 45

@i-oliva
Copy link

i-oliva commented Jan 25, 2020

Is this still working for you?

@abelvarga
Copy link

@Pavilion, yes it does. Are you having issues?

@abelvarga
Copy link

abelvarga commented Jan 28, 2020

@Pavilion, note, sometimes it gets scrambled, I don't quite know why, yet! It has something to do with the reapplying which I implemented a while back. You can checkout my latest configs here: https://github.com/rangeoshun/dot-doom-d

This part did not change tho.

@rangeoshun
Copy link
Author

@Pavilion I updated this gist with some augmentations

@rangeoshun
Copy link
Author

Updated to work with latest doom and typescript-mode.
The magic was setting these opts in mmm-jsx-mode:

(
 :front-offset -1
 :back-offset 1
)

@rangeoshun
Copy link
Author

rangeoshun commented Mar 6, 2020

Updated handling of JSX oneliners.

(
 :front "\\(return\s\\|n\s\\|(\n\s*\\)<"
)

@zerinoid
Copy link

zerinoid commented Jul 30, 2020

I have altered this to use with rjsx-mode and it gave my funky results, just so you know.

@rangeoshun
Copy link
Author

@zerinoid How did you manage? Although it lacks typescript support which currently I need, would be really interested! Care to share? :)

@katspaugh
Copy link

Thanks so much @rangeoshun! Works like a charm ✨

@vmsp
Copy link

vmsp commented Jul 3, 2021

I'm trying this with js-mode but can't that initial 2 space offset.

I get this

const RepositoryNameQuery = graphql`
query AppRepositoryNameQuery {
  repository(owner: "facebook", name: "relay") {
    name
  }
}
`;

instead of this

const RepositoryNameQuery = graphql`
  query AppRepositoryNameQuery {
    repository(owner: "facebook", name: "relay") {
      name
    }
  }
`;

@rangeoshun
Copy link
Author

@vmsp, try installing prettier and prettier-mode, I use that for all my formatting stuff.

@arichiardi
Copy link

Thanks for your work on this. I think the mmm-jsx-mode is not taking care of inline javascript for components...i.e. this could happen:

<Table {...getTableProps()} className={className}>
      <TableHead>
        {headerGroups.map((headerGroup) => (
          <TableRow {...headerGroup.getHeaderGroupProps()}>
            {headerGroup.headers.map((header) =>
              header.render('Header', { key: header.getHeaderProps().key }),
            )}
          </TableRow>
        ))} <-- the :back regex will match here
...
</Table>

Trying to work it out as we speak.

@arichiardi
Copy link

This is what worked for me

(mmm-add-classes
   '((mmm-jsx-mode
      :include-front t
      :front "<\\([a-zA-Z0-9_-]+\\)"
      :include-back t
      :back "~1>"
      :save-matches t
      :submode web-mode)))

EDIT: That's what I thought...for some reason it breaks with mmm-parse-buffer - it does work if I use mmm-mode with mmm-parse-region though

@arichiardi
Copy link

This one is better, still no perfect though:

(mmm-add-classes
   '((mmm-jsx-mode
      :include-front t
      :front "\\(return\s\\|=>\s\\|\n\s\\|\\s(\n\s*\\)<\\([a-zA-Z0-9_-]+\\)"
      :include-back t
      :back "~2>"
      :save-matches t
      :submode web-mode)))

Also, it does not match tags ending with />

@peter-wd-1
Copy link

peter-wd-1 commented Nov 27, 2021

@rangeoshun, I'm using RJSX with this config and it looks not that awful and indenting works. But auto suggestion is not working with it.
Do you have any recommendations for this config to putting up auto suggestion list buffer? I'm using company and tide.
Screen Shot 2021-11-27 at 12 16 50 AM

@rangeoshun
Copy link
Author

@peter-wd-1 For some reason it stopped working a while back. I'll look into it!

@rangeoshun
Copy link
Author

@arichiardi Am I assuming correctly that this will make every tag a separate little sub mode?

@peter-wd-1
Copy link

;; use css in js with polymode
(use-package! polymode
   :ensure t
   :after rjsx-mode
   :config
   (define-hostmode poly-rjsx-hostmode nil
     "RJSX hostmode."
     :mode 'rjsx-mode)
   (define-innermode poly-rjsx-cssinjs-innermode nil
     :mode 'css-mode
     :head-matcher "\\(styled\\|css\\)[.()<>[:alnum:]]?+`"
     :tail-matcher "\`"
     :head-mode 'host
     :tail-mode 'host)
   (define-polymode poly-rjsx-mode
     :hostmode 'poly-rjsx-hostmode
     :innermodes '(poly-rjsx-cssinjs-innermode))
   (add-to-list 'auto-mode-alist '("\\.js?\\'" . poly-rjsx-mode)))

Now I'm using this instead
Not a perfect solution but I just excepted there isn't such a reliable solution with RSJX mode yet
Thank you!

@jvrmalv
Copy link

jvrmalv commented Apr 1, 2022

Hello, I'm trying to use this previous snippet with typescript-mode, but it really just doesn't work right for me. It does change the mode to css-mode when I enter between the two backticks, but syntax highlight and code completion still is from typescript

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment