Using Monaco editor - monaco branch now in fork


EDIT: Now on github for anyone to try.

notes: you can chose which editor to use by modifying your settings.js like this...


Hi all,

I'm certain people will ask why etc - I'll just start by saying I dislike the key bindings of ACE (i've developed strong muscle memory in vscode) & I just really prefer the feel of Monaco over ACE. The pallet, the minimap, the feel, & more (though I am certain ACE can do some of these things too)

Anyhow...

On a new node I am developing, I wanted the rich editing experience i'm used to in VSCode so I started playing with the monaco editor. More of an experiment than anything at first but I was pleased with the outcome.

I added a few snippets of things we all use often in function nodes (like node.send(), node.warn(), node.error(), etc) and I wanted to demo that and a couple of other things.

So, from this, i wondered how difficult it would be to replace the built in ACE editor so its available everywhere in node-red? :thinking:

I did try simply overriding the RED.editor.createEditor function & it partially worked (function node loaded etc) but as I am not familiar with the internals of node-red, there were issues with instancing, calls to getSession(), resize() etc. I'd need to create proxies to these in order to maintain compatibility with ACE.

If anyone can provide some pointers as to where I would need to start in replacing ACE for Monaco - I'll give it a go - if only to satisfy curiosity.

So far, I cant even find the require for "ace" haha.

7 Likes

Maybe Nick can provide a better answer, but as far as I can see it's all bundled into the vendor.js file during the build process (have a look at the Gruntfile). As the NR-Editor part is all web development and not NodeJS, you won't find any require (unless you use some kind of module system or dynamic loader for the browser).

I think you'd have to create a complete API wrapper, but I doubt that would work in all cases. Devil's in the details and the ACE editor seems highly integrated. Not to mention custom nodes that use the ACE editor... :see_no_evil:

The Monaco editor seems nice, though. :sweat_smile:

Hmm - nice work - though the point fo Node-RED is not to use a word processor if possible - so a bit of "resistance" may be a good thing :slight_smile:

As already pointed out maintaining backwards compatibility is/would be the hard part - especially for 3rd party nodes - as to do that we would then need to keep both installed... Also how large is Monaco these days ?

There was also the thought about could we envisage a plugin for VScode that was the Node-RED editor... so embedding the other way round... this would make it all very recursive ! Node-RED all the way down.

3 Likes

Certainly the Monaco tooling seems to have very rapidly matured. As I also use VScode almost exclusively for all code/markdown editing (except when I want to do WYSIWYG markdown, I use Typora for that), I would love to have Monaco as an editor option.

However, as you say, it would need to be an option, partly for people who use NR's editor on limited devices and partly for backward compatibility (I have ACE integration in uibuilder so I would need to do some work on that).

But it would be a tremendous feature to have.

hi Dave, thanks for casting an eye over this.

I agree - and although my original intent was not to replace ACE in node-red - it did cross my mind once I got it working. I thought - i'll see if it can be cleanly & compatibilitililiy done :wink:

So I tried. And I failed :slight_smile:

However, as a stubborn individual I am gonna spend a little more time on it (seeing if I can make it a clean & complete replacement) - if only to see if I can.

But, i need a leg up e.g. areas of interest in the source (where ACE is "included/required" for starters.

3 Likes

Well the main editor code is here - packages/node_modules/@node-red/editor-client/src/js/ui/editor.js and then there are some specific ones that it calls in packages/node_modules/@node-red/editor-client/src/js/ui/editors

4 Likes

Hi Steve,
This looks very user friendly! Cool stuff!!!
Did have a quick look at Monaco, to see whether it also supports svg syntax. But didn't find anything...
Do you think that is possible, because that could be useful for the svg node also.
Although from this discussion it is not clear to me if monaco has a large size to download? If so it might be useful if it could be shared 'somehow' between all nodes that want to use it?
Any thoughts about this?

1 Like

I will just jump in and say, if anyone decides to go ahead and embed monaco in a node, you need to make sure you do it in a way that is self contained and doesn't pollute global name spaces that could cause issues if another node decides to embed a different version of monaco.

This is why we provide the ACE component for all nodes to reuse. But I'm painfully aware the ACE development is slow - they still don't have complete ES6 syntax support. Monaco is a much more active and vibrant library. If I could wave a wand, I'd jump at moving over. But if we are going to consider it, we need to think about a migration path that could mean a year or more of having both versions.

Going back to Steve's original comment - I think there is more we could do to expose customisation options of the editor. Keybindings, tab/spaces, margin size etc. I'm sure there's more we could do to improve the integration of the editor.

5 Likes

That would definitely tide me over Nick.

As I see it some really useful additions would be...

  • snippets for common node-red patterns (send, done, warn, error etc)
  • intellisense for oft used functions
  • key bindings choice of ACE default and Monaco default
  • theme choice (light + dark)
3 Likes

There are already a bunch of snippets... if you know they are there. Use Ctrl-Space to trigger completion.

# Node-RED Specific Funcs
snippet nodes
	node.send(${1:msg})
snippet clone
	RED.util.cloneMessage(${1:msg})
snippet nodel
	node.log($1)
snippet nodew
	node.warn($1)
snippet nodee
	node.error($1)
snippet noded
	node.debug($1)
snippet done
	node.done($1)
snippet flowg
	flow.get($1)
snippet flows
	flow.set($1, $2)
snippet globalg
	global.get($1)
snippet globals
	global.set($1, $2)
3 Likes

Well, it is certainly recognised in VScode. I don't know enough about Monaco to say whether extensions might be usable - though of course, that opens yet more complexity. One of the strengths of VScode is that Microsoft brought the Intellisense features across from Visual Studio.

1 Like

Small update.

I have been playing some more (see GIFs below)

As it stands, its 95% working with all nodes (built in and contrib) (small bug on template node not remembering value upon editsave - but I've probably missed a proxy)

NOTE: none of the nodes were edited to make this work (only editor.js)

function node (demonstrating jsdoc abilities)...

change node - json + buffer (demonstrating sub editor works too)...

template (demonstrating excellent CSS intelliense)...

Still not sure where I will end up with this but i'm enjoying the playtime & challenge.

6 Likes

Hey Steve, are the remaining 5% unsolvable issues or is it just a matter of time?
It looks VERY promising!

Just awesome experimentation! Do you have a branch of this on GitHub by any chance?

unfortunately, this "project" morphed from a hackathon on an unrelated requirement :laughing: so no, it is not currently controlled under a fork/branch (for now).

If I iron out the remaining issues I will get a fresh fork download & do a branch (and after 1.1.0 release)

@BartButenaers remaining issues are...

  • cross talk on validation (e.g. when 1 function has error, other shows errors)
  • markdown highlighting not working
  • markdown (in node documentation) not saving / restoring.

Everything else seems to work even on contrib nodes e.g...

node-red-contrib-mssql-plus...
image

node-red-contrib-ui-svg

node-red-contrib-unsafe-function...
unsafe-fn

node-red-dashboard - ui_template
image

2 Likes

@TotallyInformation so one of the last contrib nodes I tested was UI_Builder

I had to do a bit more work in the ACE~Monaco compatibility code as you accessed a couple of things direct from ACE no one else did.

It turns out most contrib nodes are good citizens and only request the ACE editor through the API but as soon as a contrib node reaches for something in the ACE editor directly (something that node-red didn't already use in the core) I had to add an additional proxy function. There wasn't many TBH (about 10 in total across core + contrib nodes - so the ACE~Monaco layer is very light)

anyhow - you'll be pleased to know it works with ui_builder too...

however, i did notice 1 issue you might want to address. You attach to on('input'... event that i dont believe exists in ACE (I think it should be on('change'... )

image

image

EDIT
So It seems the on("input") event must work (since your node signals the user to save). So I hooked up the "input" event to operate the same as the "change" event. Works a treat.

1 Like

:sunglasses:

:mage:

Nice, well done.

Interesting. I believe that I took that code from somewhere else. I can't quite remember where. Actually, though I've a feeling that the input event may come from the editor rather than ACE?

Certainly everything seems to work as expected. - Ah, just seen your edit. I should have scrolled down further.

Great work.

Managed to fix the last few bits

markdown

The modification edits are in 3 files...

  • Gruntfile.js
  • packages\node_modules@node-red\editor-client\src\js\ui\editor.js
  • packages\node_modules@node-red\runtime\lib\api\settings.js

Additional files in

  • packages\node_modules@node-red\editor-client\src\vendor\monaco

Now on github for anyone to try.

notes: you can chose which editor to use by modifying your settings.js like this...


2 Likes

Are the changes on the monaco branch?

Yeah.

you'll need to switch to the monaco branch before build (best updated the post :+1:)