felipeochoa / rjsx-mode

A JSX major mode for Emacs
https://github.com/felipeochoa/rjsx-mode
MIT License
639 stars 32 forks source link

Embedded languages #71

Open felipeochoa opened 6 years ago

felipeochoa commented 6 years ago

There have been a several requests for this before (#70, #69, #63), and I've closed them because I felt them to be out of scope for rjsx. However, given this is a recurring issue, I'm now thinking it might make sense to add this to rjsx.

This wouldn't be an easy task, and is not something I use, so there would need be significant community support for getting this done. There are a few things that would help move this along without having to sit and code the entire thing start to finish, so please weigh in with information/opinions on these topics:

carloscheddar commented 6 years ago
Wesitos commented 6 years ago
LaloHao commented 6 years ago

https://github.com/mooz/js2-mode/issues/288 I know the parser is not this plugin's area and it shouldn't be when focus is on the front/editor. But i've been gathering info on the subject and the babel parser AST seems well-defined [1]. The plugin handbook [2] gave me a good crash course, and i think it could be useful to perform semantic analysis (even on a project basis) instead of relying on complex/nested regex in emacs [9].

It could solve the jsx indentation issue , since it has "start", "end" character wise location and even "line" and "column" [3] <div>

                    "type": "JSXIdentifier",
                    "start": 277,
                    "end": 280,
                    "loc": {
                      "start": {
                        "line": 16,
                        "column": 11
                      },
                      "end": {
                        "line": 16,
                        "column": 14
                      }
                    },
                    "name": "div"

^ also useful for coloring tokens/keywords

IMHO using external tools ie node shouldn't be a problem since we are already developing jsx and most likely already using the babel transpiler directly or indirectly, else we wouldn't be using rjsx-mode.

css ast [4] @Wesitos

[9] Connecting emacs to a node process is already done: https://github.com/kiwanami/emacs-epc https://github.com/kiwanami/node-elrpc

[1] https://github.com/babel/babel/blob/master/packages/babel-parser/ast/spec.md [2] https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#toc-building-nodes [3] https://github.com/facebook/jsx/blob/master/AST.md [4] https://github.com/csstree/csstree/blob/master/docs/ast.md

haywirez commented 6 years ago

Support for styled-components 👍

LaloHao commented 6 years ago

Here's a quick hack for editing in another buffer like org-mode does, using fence-edit and rx

(modify-syntax-entry ?` "\"" js-mode-syntax-table)

(setq
 styled-component-start
 (rx-to-string '(: (1+ (and (+ word) (0+ "\.") (0+ "(" (+ alpha) ")"))) "`" eol)))

(setq
 styled-component-end
 (rx-to-string '(: "`;" eol)))

(setq
 fence-edit-blocks `((,styled-component-start ,styled-component-end)))

(setq fence-edit-default-mode 'css-mode)

with cursor inside string template call fence-edit-code-at-point

minor-mode maybe?

EDIT:

Catches; objects, properties and their method calls

export const Container = styled.div`
`;
Container.Settings = Container.Row.extend`
`;
export const Scrollbar = styled(Scrollbars)`
`;
export const Scrollbar = aaaa.styled(Scrollbars)`
`;
Wesitos commented 5 years ago

I was trying to implement this with polymode. Indentation works, but syntax highlighting does not. Looks like mmm-mode has the same problem with rjsx-mode (and js2-mode).

mnewt commented 5 years ago

+1 for graphql.

I'm currently using fence-edit like this:

(add-to-list 'fence-edit-blocks '("graphql[ \t\n]*(?`" "`" graphql))

(bind-key "C-c '" #'fence-edit-dwim)

My full config: https://gitlab.com/mnewt/dotemacs/blob/master/.emacs.d/init.el#L2777

wyuenho commented 5 years ago

Polymode works for me, despite its documentation claims otherwise. I just have to make sure polymode is loaded after rjsx-mode, otherwise the graphql block will still be using rjsx-mode's string face.

This is my config:

(use-package polymode
  :after rjsx-mode
  :config
  (define-hostmode poly-rjsx-hostmode nil
    "RJSX hostmode."
    :mode 'rjsx-mode)
  (define-innermode poly-rjsx-graphql-innermode nil
    :mode 'graphql-mode
    :head-matcher "graphql\`"
    :tail-matcher "\`"
    :head-mode 'host
    :tail-mode 'host)
  (define-polymode poly-rjsx-mode
    :hostmode 'poly-rjsx-hostmode
    :innermodes '(poly-rjsx-graphql-innermode))
  (add-to-list 'auto-mode-alist '("\\.jsx?\\'" . poly-rjsx-mode)))

(use-package rjsx-mode
  :mode ("\\.jsx?\\'" "\\.mjs\\'"))
littlehome-eugene commented 4 years ago

Based on wyuenho's answer

styled-components or emotion.js css-in-js can be done via


(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 "css\`\\|styled\.[[: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 '("\\.jsx?\\'" . poly-rjsx-mode)))
wyuenho commented 4 years ago

I might have spoken too soon. While that's the correct way to set up a poly mode, it doesn't work very well since every time rjsx reparses, the font lock will be wiped out

rangeoshun commented 4 years ago

I opted to use typescript-mode instead of rjsx-mode and augmented its JSX handling with web-mode. Used css-mode for styled components and added graphql-mode. I used mmm-mode, but this could be done with polymode I guess. But I had issues with polymode only highlighting the first block. Actual mode switch worked tho, but I like fancy colors. Here's my gist: https://gist.github.com/rangeoshun/67cb17392c523579bc6cbd758b2315c1

deviantfero commented 4 years ago

@rangeoshun, I was taking a look at your snippet, any idea of how this could work with something like tide?, I often use variables defined in typescript sections of my code on JSX, any help would be appreciated, I currently use web-mode with tide as a completion engine

rangeoshun commented 4 years ago

@deviantfero, I think it just works as far as I can tell:

Screenshot 2019-12-04 at 12 55 52 Screenshot 2019-12-04 at 12 56 16

~Also tide-fix works with one little caveat. When applied, mmm does not repaint the block right away. But it starts working again when you edit the block. This could be fixed by forcing mmm to reapply the modes if tide has a hook for this. I did not have the time to look into this tho.~

Also by adding an after-save-hook, you can reapply mmm mode by toggling it. There may be a better way, but that was the one I came up with with the little time I put into this just now. This also allows prettier to do its thing and not screw up highlighting at all. My complete doom config is here, if you're interested: https://github.com/rangeoshun/dot-doom-d/blob/master/config.el

Hope I answered your question :)

deviantfero commented 4 years ago

Thank you so much, I'll have a look, I've been looking into improving performance when editing JSX and this seems to be the appropriate answer

On Wed, 4 Dec 2019 at 06:02, rangeoshun notifications@github.com wrote:

@deviantfero https://github.com/deviantfero, I think it just works as far as I can tell:

[image: Screenshot 2019-12-04 at 12 55 52] https://user-images.githubusercontent.com/1267842/70140799-cf2d1d80-1695-11ea-8003-544c62ddfb73.png

[image: Screenshot 2019-12-04 at 12 56 16] https://user-images.githubusercontent.com/1267842/70140801-d0f6e100-1695-11ea-9c6a-35a67cbd66cd.png

Also tide-fix works with one little caveat. When applied, mmm does not repaint the block right away. But it starts working again when you edit the block. This could be fixed by forcing mmm to reapply the modes if tide has a hook for this. I did not have the time to look into this tho.

My complete doom config is here, if you're interested: https://github.com/rangeoshun/dot-doom-d/blob/master/config.el

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/felipeochoa/rjsx-mode/issues/71?email_source=notifications&email_token=ACVCGSO27LA6OA7MNF43IK3QW6L5VA5CNFSM4E47FAOKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEF4Y3XY#issuecomment-561614303, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACVCGSOW6UTE3OW3KDPGZULQW6L5VANCNFSM4E47FAOA .

ColemanGariety commented 4 years ago

I'm using @rangeoshun's solution for .tsx files and it works except for inline functions:

function foo() {
  return (
    <MyComponent>
      {() => (
      <div> {/* <- indentation fails here */}
        <div></div>
      </div> 
      )()}
    </MyComponent>
  )
}

Is it possible to modify the RegExp to use web mode for the entire return block? Web-mode is quite unperformant when using it on the whole file for some reason.

EDIT: @deviantfero did you ever manage so solve your performance issues?

rangeoshun commented 4 years ago

@JacksonGariety I see now what you mean! To be honest, I had issues with tide, so in work, we opted to just use typescript-mode for JSX, which is subpar compared to web-mode but still does some highlighting, with a bit of autocomplete.

I have tried to create multiple mmm-class to cover this, but have not succeeded with emacs' regexp.

rangeoshun commented 4 years ago

@JacksonGariety Also, we use prettier-js, so I did not even notice the indentation issue.

ColemanGariety commented 4 years ago

@rangeoshun how do you get typescript-mode to indent JSX? For me it doesn't indent at all.

rangeoshun commented 4 years ago

@JacksonGariety I simply turned on prettier-js-mode for typescript-mode like so:

(add-hook 'typescript-mode-hook 'prettier-js-mode)
Sleepful commented 3 years ago

@rangeoshun how does it fare with string interpolation inside template literals?

rangeoshun commented 3 years ago

@rangeoshun how does it fare with string interpolation inside template literals?

If I understand your question correctly, you'll lose some company-mode features. But generally, I like to define my functions outside the literal, and interpolate the function by reference. Please tell me if I got your question wrong 😄

rangeoshun commented 3 years ago

Also anyone checking this topic, it might worth to try this repo here:

https://github.com/orzechowskid/css-in-js.el