DataProvider problem for EditorAction when in Toolwindow editor

In my plugin, I have a REPL which runs in a toolwindow. I received a bug report that the "Jump to matching brace" action doesn't work in the REPL editor. Investigating, the EditorActionHandler for MatchBraceAction starts with CommonDataKeys.PSI_FILE.getData(dataContext), and then returns immediately if that returns null. Indeed, this returns null, because TextEditorPsiDataProvider returns null if EditorEx.getVirtualFile() returns null, which it does for all console editors (I verified this bug also affects the Python console and the Kotlin console). I suspect this means that a large class of EditorActions won't work for console editors.

I tried to fix this by calling setFile() during my console creation, but that causes the EditorAction to not be called at all. In EditorAction.update(), it tries to get the data for CommonDataKeys.EDITOR, and that returns null because in EditorComponentImpl#getData() null is returned if myEditor.getVirtualFile() != null, with the comment that "for 'big' editors return null to allow injected editors - see TextEditorComponent.getData()". TextEditorComponent.getData() is never called. I have registered a DataProvider for a component above the EditorComponent where I call FileEditorManagerEx.getData() with my console editor, but this still doesn't return the right value because TextEditorPsiDataProvider.getData() only checks the injected ID for EDITOR, not the plain one.

This is amazingly confusing. I'm not sure what the correct place for me to fix these problems is, and I don't know what the impact of the various options is - I would never have expected setting the virtual file on the editor to break all EditorActions. I'd like to know the best way to fix my current problem, but it would also be really useful to have some documentation around how all this hangs together.

1 comment
Comment actions Permalink

I've worked around this by using FileEditorManager.registerExtraEditorDataProvider() and registering a subclass of TextEditorPsiDataProvider. This subclass checks if the editor is the one I'm interested in, and if so it calls setFile() on it, calls the superclass getData() and then resets the virtualFile on the editor in a finally block. This works and means I don't have to reimplement everything in TextEditorPsiDataProvider but feels very clunky and I have no idea what else it might break - I'd love a better solution.


Please sign in to leave a comment.