"Skipping this shortcut because it collides with another shortcut"

Hi,
I want to use keyboard shortcuts such as “Shift Enter” in my JupyterLab extension, however I get the console warning “Skipping this shortcut because it collides with another shortcut.” From looking at the code I see that shortcuts which are considered “default” will throw this warning, and I understand that “Shift Enter” is used in the notebook extension and thus is probably considered “default”.

However, my question remains how I can use such a shortcut and avoid this conflict? It seems reasonable to me that this should be possible: JupyterLab could check which is the active extension/widget and take the appropriate action…

Just to be clear, what is your shortcut, and what is the shortcut it is complaining about? And what exactly do you want to have happen (i.e., what is “avoiding this conflict” in this case)?

Thanks for your response Jason.

The extension I’m working on right now is a split-panel notebook: right hand side is a notebook, left hand side is a “canvas” where the user can drop nodes that represent python functions/classes. It works alongside the default notebook (at least for now – we’re also thinking about integrating with the default notebook but was having some difficulty overriding the content area of the NotebookPanel).
So, I need for all of the regular notebook commands to work in both the default notebook, as well as my split-panel notebook.

In the screenshot below I’m showing the “split panel” notebook next to the default notebook.

Thanks for sharing. Can you continue explaining exactly what keyboard shortcut you are registering, and what keyboard shortcut it is complaining about? In particular, what are the selectors for these shortcuts?

From your explanation above, I’m inferring that you are trying to reuse a notebook css class for your notebook, where you should maybe be setting up shortcuts for your new notebook yourself. Or perhaps you can reuse the notebook css class, but you have to be really careful about how you do so.

What we’ve done is copy the notebook-extension, and then change the shortcut names. The result is that our split panel notebook now “steals” the shortcuts: they now only work in the split panel notebook, but not the default notebook. I think you’re saying that in the “tracker.json” below I should change the selectors to also be different – not .jp-Notebook:focus, for example…?

Yes. A shortcut is identified by the (keys, selector) pair - that is what the system needs to identify for a given key press on a given DOM element what command to run. You are adding new shortcuts with the same (keys, selector) pairs, so the system wouldn’t know what to do - your command or the default command. The way to disambiguate is to recognize that your shortcuts apply to a completely different thing in the DOM, your widget, and so you should have your own selector, not reuse the existing selector.

1 Like

Thank you very much, I didn’t realize that, and will try it out!

Hey @jasongrout,

That fixed the shortcut conflict issue for me. Thank you.

One follow-up is that I’m also having trouble getting the Completer to work in my split panel notebook – no errors, it just tabs over instead of triggering the Completer. Do you have any recommendations for how to approach this?

I was thinking that I could just copy this portion of the Completer Extension, but I’m wondering if there’s a simpler way…

One further follow-up is that I’m having trouble getting ipywidgets to work in my extension. I get the error below Object 'jupyter.widget' not found in registry. Could you please provide some guidance as to what I might need to do to get ipywidgets to work in my extension?

The widgets are working properly for the regular notebook running at the same time:

I don’t have enough experience with the completer to know off the top of my head.

Probably ipywidgets does not know that it should be handling your document type. Currently it registers itself with notebook widgets specifically: https://github.com/jupyter-widgets/ipywidgets/blob/54941b7a4b54036d089652d91b39f937bde6b6cd/packages/jupyterlab-manager/src/plugin.ts#L223-L248

What would be the best way to implement registering my document type with the ipywidget jupyterlab-extension?
I think I would need access to executing the registerWidgetManager function, but I’m not sure how to access it.
I know it’s possible to extend extensions (https://jupyterlab.readthedocs.io/en/stable/developer/notebook.html#how-to-extend-the-notebook-plugin), but would I need to extend the jupyterlab-manager?

Check out how bqplot does it, for example: https://github.com/bqplot/bqplot/blob/eff67ba52bf1e9cae9a5663e0d86b06a8900b892/js/src/jupyterlab-plugin.ts

Or the cookiecutter: https://github.com/jupyter-widgets/widget-ts-cookiecutter/blob/bd6825f02bfd5dc34965024d68dc3f69700863c4/{{cookiecutter.github_project_name}}/src/plugin.ts#L41

Sorry, but I’m still a bit confused! The registerWidget() function takes the argument exports: ExportData but I’m not sure what argument to provide: my extension is based on a copy of the notebook extension and for my usecase I’m just trying to get ipywidgets to work in my notebook. It seems the registerWidget() function is used when you are building an ipywidget-style extension using DOMWidgetModel/DOMWidgetView, which I’m not doing…

In this link you shared (https://github.com/jupyter-widgets/ipywidgets/blob/54941b7a4b54036d089652d91b39f937bde6b6cd/packages/jupyterlab-manager/src/plugin.ts#L223-L248), I see how it takes a tracker and then executes the registerWidgetManager function for each panel. I think I need to do something similar, and I have access to my tracker.

The only problem (along my current way of thinking) is that, in order to have all of the logic work, I would need to fork the entire jupyterlab-manager extension with the only difference being that I would provide the INotebookTracker for my notebook. But I’m hoping there’s an easier way, and I think there is, I’m just not understanding yet. Any further help would be appreciated!

  if (tracker !== null) {
    tracker.forEach(panel => {
      registerWidgetManager(
        panel.context,
        panel.content.rendermime,
        chain(
          widgetRenderers(panel.content),
          outputViews(app, panel.context.path)
        )
      );

      bindUnhandledIOPubMessageSignal(panel);
    });
    tracker.widgetAdded.connect((sender, panel) => {
      registerWidgetManager(
        panel.context,
        panel.content.rendermime,
        chain(
          widgetRenderers(panel.content),
          outputViews(app, panel.context.path)
        )
      );

      bindUnhandledIOPubMessageSignal(panel);
    });
  }

Ah, yes, I forgot and got confused about what you were doing. You’re right that you should ignore my last reply, as it is solving a completely different issue.

You’re right that right now, you would need to fork jupyterlab-manager extension, as it is hardcoded to add itself to whatever the system INotebookTracker is.

Right now, the widgets jupyterlab manager is only exposing an object to the system that lets custom widgets register themselves. Perhaps the jlab manager should also provide the registerWidgetManager function to the system? Or perhaps the system can provide list of notebook-like trackers that the widget manager can iterate through? That would keep the widget registration logic in the widget manager.

Okay, makes sense now! Glad I wasn’t totally off track in my understanding.

Yes I agree. My usecase might be a corner case, but yes exposing that function would be great.
As an aside, I’m actually not sure why the jupyterlab-manager extension isn’t a core extension that is automatically shipped with JupyterLab. It seems to me that the number of people that want ipywidgets to work out of the box is much larger than those that don’t want the functionality. If that was the case, in the notebook-extension itself you could use the registerWidgetManager function, which would make it easier for developers to follow how to make ipywidgets work in their own extensions.

Just wanted to link this conversation to an issue that I’m having getting IPywidgets to work in my extension