Model decorators don't work with ViewRegistry


#1

For my project I want to decorate the TextEditorElement to provide some custom functionality. However in order to add a provider in the ViewRegistry I have to provide a modelConstructor so that I my callback is invoked. Something like:

@subscriptions.add atom.views.addViewProvider MyTextEditor, (myTextEditor) ->
   return atom.views.getView(### Um, no casting here ###)

I could create class MyTextEditor extends TextEditor however that causes two problems:

  1. Because MyTextEditor instanceof TextEditor would be true, in the ViewRegistry.findProvider() function, the view that would be created is the default TextEditorElement instead of my callback function being invoked. This is because the providers are an array and the TextEditor registers first so it wins.

  2. So I did something hacky to get around (1) and reordered the providers (after registering) to have my provider for MyTextEditor appear first in the providers list. Normal TextEditors are unaffected and my callback function wins for my model. However because I want to wrap the TextEditorElement I still want to create one, so in my callback I want to call atom.views.getView() with my editor instance “cast” so that the ViewRegistry would treat the argument as a TextEditor and return me a TextEditorElement and I can wrap it. But to the best of my knowledge the you can’t do that in JS

Any ideas on how to do custom views? I’m a n00b with Atom so on a learning experience. However it seems to me that the ViewRegistry is a bit simplistic in it’s mapping from model to view.


#2

Of course it hit me after I posted :smile:

In my addViewProvider callback I can temporarily cut my registration for MyTextEditor from the atom.views.providers array. So then when I call atom.views.getView(editorInstance) the instanceof TextEditor will match and a TextEditorElement will be returned. I just have to then restore the ViewRegistry providers afterwards.

However this all seems very hacky.


#3

Have you tried using composition over inheritance instead?

I believe you should be able to make it work quite simply using the delegato module. Given that Atom finally reached 1.0 milestone, you can be pretty confident that the current public API won’t change until 2.0.


#4

I did try a compositional approach, where MyTextEditor was a proxy to an underlying TextEditor. However this breaks the atom.workspace.getActiveTextEditor() call because that function does an instanceof TextEditor check, so I broke it. Functionality like the Grammar package broke as it relies on the result of atom.workspace.getActiveTextEditor()

Because parts of the editor rely on a “class hierarchy” through instanceof it makes it hard to use a compositional Decorator Pattern approach (which is my preferred mechanism).