editors opened with IDE.openEditors don't persist restart if never activated
Let's make sure issue is not already fixed in latest builds first.
- [x] I verified I can reproduce this issue against latest Integration Build of Eclipse SDK
Steps to reproduce
From a fresh installation and clean workspace:
- Create a project called 'example' with two files, 'file1.txt' and 'file2.txt'
- Run the code below (only file1 editor will be active + created)
- Restart the IDE
- Click on file2's editor tab (an error editor will be opened)
Place this code in a command or similar to run it:
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("example");
var files = new IFile[] { project.getFile("file1.txt"), project.getFile("file2.txt") };
try {
IDE.openEditors(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), files);
} catch (MultiPartInitException e) {
e.printStackTrace();
}
Screenshots and stack trace
After the restart, when you click on the file2.txt tab you get this:
full stack trace from above screenshot's "Details..."
java.lang.Exception
at org.eclipse.ui.internal.EditorReference.createErrorPart(EditorReference.java:332)
at org.eclipse.ui.internal.EditorReference.createPart(EditorReference.java:313)
at org.eclipse.ui.internal.e4.compatibility.CompatibilityPart.createPart(CompatibilityPart.java:304)
at org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor.createPart(CompatibilityEditor.java:61)
at org.eclipse.ui.internal.e4.compatibility.CompatibilityPart.create(CompatibilityPart.java:342)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:56)
at org.eclipse.e4.core.internal.di.InjectorImpl.processAnnotated(InjectorImpl.java:977)
at org.eclipse.e4.core.internal.di.InjectorImpl.processAnnotated(InjectorImpl.java:939)
at org.eclipse.e4.core.internal.di.InjectorImpl.internalInject(InjectorImpl.java:139)
at org.eclipse.e4.core.internal.di.InjectorImpl.internalMake(InjectorImpl.java:386)
at org.eclipse.e4.core.internal.di.InjectorImpl.make(InjectorImpl.java:312)
at org.eclipse.e4.core.contexts.ContextInjectionFactory.make(ContextInjectionFactory.java:203)
at org.eclipse.e4.ui.internal.workbench.ReflectionContributionFactory.createFromBundle(ReflectionContributionFactory.java:90)
at org.eclipse.e4.ui.internal.workbench.ReflectionContributionFactory.doCreate(ReflectionContributionFactory.java:59)
at org.eclipse.e4.ui.internal.workbench.ReflectionContributionFactory.create(ReflectionContributionFactory.java:42)
at org.eclipse.e4.ui.workbench.renderers.swt.ContributedPartRenderer.createWidget(ContributedPartRenderer.java:134)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.createWidget(PartRenderingEngine.java:991)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.safeCreateGui(PartRenderingEngine.java:658)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.safeCreateGui(PartRenderingEngine.java:762)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$2.run(PartRenderingEngine.java:727)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:47)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.createGui(PartRenderingEngine.java:711)
at org.eclipse.e4.ui.internal.workbench.PartServiceImpl.lambda$0(PartServiceImpl.java:105)
at org.eclipse.e4.ui.services.internal.events.UIEventHandler.lambda$0(UIEventHandler.java:38)
at org.eclipse.swt.widgets.Synchronizer.syncExec(Synchronizer.java:183)
at org.eclipse.ui.internal.UISynchronizer.syncExec(UISynchronizer.java:133)
at org.eclipse.swt.widgets.Display.syncExec(Display.java:5962)
at org.eclipse.e4.ui.workbench.swt.DisplayUISynchronize.syncExec(DisplayUISynchronize.java:34)
at org.eclipse.e4.ui.services.internal.events.UIEventHandler.handleEvent(UIEventHandler.java:38)
at org.eclipse.equinox.internal.event.EventHandlerWrapper.handleEvent(EventHandlerWrapper.java:206)
at org.eclipse.equinox.internal.event.EventHandlerTracker.dispatchEvent(EventHandlerTracker.java:201)
at org.eclipse.equinox.internal.event.EventHandlerTracker.dispatchEvent(EventHandlerTracker.java:1)
at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:151)
at org.eclipse.equinox.internal.event.EventAdminImpl.dispatchEvent(EventAdminImpl.java:131)
at org.eclipse.equinox.internal.event.EventAdminImpl.sendEvent(EventAdminImpl.java:73)
at org.eclipse.equinox.internal.event.EventComponent.sendEvent(EventComponent.java:44)
at org.eclipse.e4.ui.services.internal.events.EventBroker.send(EventBroker.java:55)
at org.eclipse.e4.ui.internal.workbench.UIEventPublisher.notifyChanged(UIEventPublisher.java:60)
at org.eclipse.emf.common.notify.impl.BasicNotifierImpl.eNotify(BasicNotifierImpl.java:424)
at org.eclipse.e4.ui.model.application.ui.impl.ElementContainerImpl.setSelectedElementGen(ElementContainerImpl.java:168)
at org.eclipse.e4.ui.model.application.ui.impl.ElementContainerImpl.setSelectedElement(ElementContainerImpl.java:187)
at org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer.lambda$28(StackRenderer.java:1160)
at org.eclipse.swt.events.SelectionListener$1.widgetSelected(SelectionListener.java:84)
at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:265)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:91)
at org.eclipse.swt.widgets.Display.sendEvent(Display.java:5857)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1617)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1643)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1626)
at org.eclipse.swt.widgets.Widget.notifyListeners(Widget.java:1373)
at org.eclipse.swt.custom.CTabFolder.setSelection(CTabFolder.java:3258)
at org.eclipse.swt.custom.CTabFolder.onMouse(CTabFolder.java:1897)
at org.eclipse.swt.custom.CTabFolder.lambda$0(CTabFolder.java:331)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:91)
at org.eclipse.swt.widgets.Display.sendEvent(Display.java:5857)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1617)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:5067)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4519)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1151)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1042)
at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:153)
at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:663)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:570)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:173)
at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:178)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:208)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:143)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:109)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:439)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:271)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:668)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:605)
at org.eclipse.equinox.launcher.Main.run(Main.java:1481)
at org.eclipse.equinox.launcher.Main.main(Main.java:1454)
- [x] I understand reporting an issue to this OSS project does not mandate anyone to fix it. Other contributors may consider the issue, or not, at their own convenience. The most efficient way to get it fixed is that I fix it myself and contribute it back as a good quality patch to the project.
@jonahgraham : is this a regression in 4.35?
@jonahgraham : is this a regression in 4.35?
No.
(More details coming soon, I'm writing some of my findings)
IDE.openEditors uses IWorkbenchPage.openEditors(IEditorInput[], String[], int), which is where the bug "really" may be.
I think what is happening is that without the editor being activated, there is no memento being created for it, so nothing is being persisted on restart.
My guess is that IWorkbenchPage.openEditors(IEditorInput[], String[], IMemento[], int, int) works if you supply the IMemento array because then the persisted state is updated (i.e. editor.getPersistedState().put(WorkbenchPartReference.MEMENTO_KEY, writer.toString());)
On restart, without a Memento for the editor, EditorReference doesn't get its descriptor assigned.
I thought I could work around the problem by passing in an empty memento because that is what this code implies:
https://github.com/eclipse-platform/eclipse.platform.ui/blob/745385a64d99bfcf8c2a72139c72ee1829599ef2/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPage.java#L4706-L4716
But it turns out that if block contents is no-op, because outerMem is never used - and even if it was, the memento created is incomplete.
Creating the memento like this does work:
XMLMemento editorMem = XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_EDITOR);
editorMem.putString(IWorkbenchConstants.TAG_ID, editorDescriptions[i]);
IPersistableElement persistable = editorInputs[i].getPersistable();
IMemento inputMem = editorMem.createChild(IWorkbenchConstants.TAG_INPUT);
inputMem.putString(IWorkbenchConstants.TAG_FACTORY_ID, persistable.getFactoryId());
persistable.saveState(inputMem);
But I suspect the code is still incorrect/insufficient as it probably should create the editor reference and let it save the persistable state
I think I have tracked down the real problem - EditorRefernces are only being persisted if they have been activated in Workbench.persist:
https://github.com/eclipse-platform/eclipse.platform.ui/blob/5fa25b1127d9a90a2cc7604507845515a69b0d47/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java#L1213-L1214
But you can't just call reference.persist() because if the getEditor(false) is null, then org.eclipse.ui.internal.EditorReference.getEditorState() uses the previously persisted state as the current state - but the problem we have here is there is no previously persisted state. Somewhat of a Catch-22.
I don't think I can solve this issue in the near term - but perhaps an api note should be added to IDE.openEditors and IWorkbenchPage.openEditors that references this issue so extenders know that inactivated editors have a problem.
For my immediate issue (part of https://github.com/eclipse-cdt/cdt-lsp/pull/421) I am just going to activate all the editors immediately.