Rescript emacs support with rescript-vscode

Hi

I got rescript-vscode working with emacs.

I’ve not pushed it yet, if any emacs users here want to use this: if you let me know you exist it’ll encourage me to finish it off!

I changed two things to get it working:

  • Add support to rescript-vscode’s server.ts to add a --stdio switch. I used vscode-jsonrpc to implement that. In my patch, VS code and vim clients would still use process.on etc., the changes are quite localised – does that sound an acceptable approach to you @chenglou ? (will put up a PR later but I need to clean it up first)
  • Copy-paste things out of reason-mode.el to make a rescript-mode.el and tweak some things e.g. for multi-line string syntax changes

Also, not needed to be pushed upstream to make it work, but I’ll do if the rescript-vscode changes are accepted:

  • Add the server definition to lsp-mode.el default config
  • Probably will be some minimal config for spacemacs users too (I use spacemacs)

Things I know are broken:

  • Currently I have to force the prompt to trigger a build rather than just having that happen on opening a file
  • I should test the stuff about empty responses does what it’s supposed to (the code is clear, I just need to read it and test)
  • Check if refmt is exposed over LSP and see if that works
  • I have to copy over some more stuff from reason-mode.el – notably tab doesn’t do the right thing yet
  • Syntax highlighting (font-lock) for plain backtick multiline strings (the kind without the j) is broken
  • Syntax highlighting (font-lock) for assignment to quoted keywords is broken (like \"try" = true)
20 Likes

This sounds awesome, I would really like to give this a try when it is available publicly. I’ve been grudgingly using VSCode and looking forward to having a language server that works with Emacs.

3 Likes

It depends on how much complexity this introduces. If vscode-jsonrpc pulls in a whole bunch of other dependencies, I am not sure. I’d generally be interested in having a --stdio mode, but I also understand e.g. Cheng’s concern on keeping the LSP compact (stability over features right now).

I can have a look on the patch if you want.

Thanks for the effort. We don’t officially support emacs, so no promises regarding catering to it in our vscode plugin. The fact that our plugin uses LSP under the hood is an implementation detail we don’t really guarantee.

vscode-jsonrpc is already a dependency of rescript-vscode.

The changes are localised to replacing process.on, process.send – the patch basically does:

+ let onMessage = (func: any) => {
+   process.on("message", (msg: m.Message) => {
+     func(process.send!, process.send!, msg);
+   })
+ };
-process.on("message", (msg: m.Message) => {
+onMessage((sendResponse: any, send: any, msg: m.Message) => {

plus an alternative implementation of onMessage that writes to stdio using vscode-jsonrpc.

Thanks! I’ll get it into a reviewable state.

I’m a Doom Emacs user, awesome work! I would very much appreciate a ReScript module, is there anything I can help with(my elisp is weak though)?

Thanks for putting your hand up and encouraging me, I just need to tidy things up. I worked on it today, I realized while fixing a bug that I can make the server changes even simpler, I’ll put that in a PR soon.

If that’s accepted then I think when I’ve copied over the old reason-mode.el code into rescript-mode.el to make the tab key work it’ll be useable, with types, compiler errors and completion (plus non-LSP font-lock syntax highlighting like ordinary emacs modes, apparently doing that in LSP is a new thing and rescript-vscode in VS code doesn’t use LSP for that either). So I’ll do some sort of release.

Will take more time: refmt-style formatting (works but needs minor lsp-mode.el fix), font-lock bugs, nice elisp packaging, easy config. As will the “Start a build?” feature (requires an lsp-mode.el change that may not be accepted upstream since it’s dependent on undocumented VS code client behaviour I think) – but you can just start a build yourself as workaround.

Before doing that I recommend opening an issue first to gauge if the changes are wanted.

1 Like

@ryyppy patch here: https://github.com/rescript-lang/rescript-vscode/pull/88

I’m not taking for granted that this will be accepted by the way nor ignoring @yawaramin’s comment (we talked off the thread and I concluded I probably should have opened a github issue instead of raising it here – but now I’ve done it this way I guess there’s no point in raising an issue too).

But obviously I think the patch should be applied :slight_smile:

The rescript-vscode LSP server change has been merged and I’m planning to work a bit on the emacs side of this this weekend.

Only now do I remember ah yes, ReScript syntax eliminates semicolons, so I’ve probably cut out more work for myself than I expected :wink: (I still plan to do it!)

In particular, indentation from reason-mode.el (in fact, reason-indent.el) may require a bigger rewrite than I imagined (this part is unrelated to LSP and rescript-vscode, it’s pure elisp; I haven’t yet read the code but I expect it’s relying on the presence of semicolons heavily).

If anybody here has advice for how to implement indenting ReScript code I’d love to hear what you think, because right now I’m fairly clueless about it.

2 Likes

@rewrangler do you have a fork of reason-mode.el you could share? I’m interested in trying out rescript and would like to use emacs too :slight_smile:

Regarding formatting I just used the reformatter emacs package

(reformatter-define rescript
  :program "resfmt")

Where resfmt is a shim so that bsb -format can work with stdin: https://pypi.org/project/resfmt/

I’m totally interested too. Just discovered last week that Rescript happened while I was waiting for Reason to get little more friendly. I really would like to try it in my current project but it is unpleasant to work without nice editor integration.

Btw. it would be great if you can share even your uncomplete work with some TODOs. Maybe we can even give you a hand (no promises :slight_smile: ).

Regarding formatting I just used the reformatter emacs package

Another alternative is format-all package which rescript support already (I believe it is where that resfmt shim comes from too).

1 Like

On master: bsc -o MyFile.res -format MyFile.res

I’d like to still set the expectations that I’ve cleaned and merged that diff as an experiment. As long as you folks are ok with that status then go ahead. But please advertise this as an unstable thing that might break, including on these published wrapper libs. Otherwise we’ll end up having to cater to some expectation mismatches which are much more troublesome than a PR. Thanks =)

3 Likes

Thanks

Feel free to comment on any of the following if you think it’s better to do it differently.

One thing I’m not sure of from this page is whether you regard vim/neovim (etc.?) as in an intermediate category (between emacs and VS Code/Sublime), so not sure if that part of my wording below is best from your point of view.

I guess my default is to try and publish what I have quickly when it’s minimally useable (in a standalone repo) and then iterate on that, but label it loudly as unsupported by ReScript or rescript-vscode – something like:

Emacs is NOT SUPPORTED by the ReScript core team, nor rescript-vscode. The core ReScript team’s focus for editor support is currently on supporting VS Code and Sublime Text well. So, if you want something that you can be confident is going to work smoothly and will not go away, use one of the editors listed as supported by the core ReScript team (currently VS Code and Sublime Text). In particular, the emacs support here depends on the LSP server from rescript-vscode and its --stdio switch, neither of which are officially supported and could be removed in a later version.

So if you have problems with Emacs and ReScript, please report your issues here, not upstream with ReScript or rescript-vscode (neither on the forum nor the github issues) and please don’t complain if you used ReScript with Emacs and had a bad time – if you did that, you’re going it alone and you really didn’t try the official ReScript experience – that’s unfair and a good way to annoy everybody.

This code is also early pre-release software, expect to run into issues if you choose to use it.

Perhaps it’s also best if discussion were kept to github issues (and github discussions maybe) on the repo I will create rather than here on this forum (I’ll still announce in this thread when I’ve published of course).

To be clear, I believe format-all runs bsb -format (via this non-official resfmt PyPI project that kepi mentioned). No published code to my knowledge is yet using the LSP server and --stdio (except if you just point the existing lsp-mode.el at it of course).

What I personally expect these days with most languages in emacs is:

  1. Formatting: This means that you run say lsp-format-buffer (, = b in spacemacs), or one of the tools mentioned (format-all, reformatter) and your whole buffer (or some section of it that you specify maybe) is magically formatted correctly.

  2. Indentation: This means that hitting the tab key or the return key (depending how you have things configured I guess) gives you an approximation of the “official” formatting of a tool like bsc -format. It’s never identical to what something like bsc -format produces, but it stops you thinking much about formatting when writing code or having to hit the tab key much.

Item 1. works already via LSP, 2. does not because I have to write elisp code to support it.

Do you have a different expectation?

I’ll do a bit today I hope (so far today I’ve been on this forum when I hoped to be doing that :wink: )

Edit: now I recall that formatting via LSP only works because of a hack I made to lsp-mode.el that I need to fix and upstream. I did mention that here, so presumably that’s why people were posting about how to format a different way!

Yeah we’re fine with it as long as there’s such disclaimer! =)

1 Like

Today having tried some simpleminded hacks to reason-indent.el, I see that indeed it looks pretty tricky to start from there, due to the semicolon issue. js.el actually produces mostly reasonable indentation from the file I tested it on, not miles away from what bsc -format produces, at least if I remove the quoted infix operators that I just posted about elsewhere. js.el is the more simple-minded mode that comes with emacs, as opposed to the fancier and much more correct js2-mode.el. I think I should start just by doing a straight copy of the indentation code from js.el (therefore relicensing to GPL v3) and doing a release as soon as I can, rather than trying to rescue reason-indent.el.

Comments/advice about that still welcome though.