Bug 571513 - Undo intermittently stops working causing permanent data loss
Summary: Undo intermittently stops working causing permanent data loss
Status: NEW
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Text (show other bugs)
Version: 4.20   Edit
Hardware: All All
: P3 major (vote)
Target Milestone: ---   Edit
Assignee: Platform-Text-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-02-25 13:00 EST by Markus Kuppe CLA
Modified: 2021-03-09 14:44 EST (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Kuppe CLA 2021-02-25 13:00:39 EST
With Eclipse IDE I20201202-1800 (IIRC other 2020/2021 versions as well), undo intermittently stops working causing a user to suffer permanent data loss.

The actual behavior can be seen in the two screencasts in https://github.com/tlaplus/tlaplus/issues/568#issuecomment-774079477, which have been recorded with an Eclipse RCP.  This issue applies there too.  Both the keyboard commands as well as the menu item no longer work.
Comment 1 Rolf Theunissen CLA 2021-02-26 05:42:11 EST
This might be related to Bug 559539.

Would you be able to see if the operation history gets flushed/disposed, and where that call originates from? 
That is, is this methed called and by who:
PlatformUI.getWorkbench().getOperationSupport().getOperationHistory().dispose()

Otherwise the IOperationHistory#dispose call would be a candidate to check it it gets called.
Comment 2 Markus Kuppe CLA 2021-02-26 11:55:35 EST
org.eclipse.core.commands.operations.DefaultOperationHistory.dispose(IUndoContext, boolean, boolean, boolean) doesn't get called during relevant user actions.

The screencasts below show some really strange behavior s.a. undo/redo applied to the inactive editor.  This is independent of undo/redo invoked via the menu or through the keyboard shortcut.

http://tla.msr-inria.inria.fr/kuppe/EclipseUndoRedo.gif
http://tla.msr-inria.inria.fr/kuppe/EclipseUndoRedo2.gif
http://tla.msr-inria.inria.fr/kuppe/EclipseUndoRedo3.gif
Comment 3 Rolf Theunissen CLA 2021-02-27 11:28:14 EST
It seems that the undo/redo actions of the editor first editor are not activated after an editor switch. Therefore the undo/redo actions of the previous editor remain active. What happens when more editors are open? Are indeed the undo/redo actions not activated on one editor only?

The undo/redo actions should be set when a part gets activated:
CompilationUnitEditorActionContributor(BasicTextEditorActionContributor).doSetActiveEditor(IEditorPart) line: 220	
CompilationUnitEditorActionContributor(BasicTextEditorActionContributor).setActiveEditor(IEditorPart) line: 255	
CompilationUnitEditorActionContributor(BasicJavaEditorActionContributor).setActiveEditor(IEditorPart) line: 180	
CompilationUnitEditorActionContributor(BasicCompilationUnitEditorActionContributor).setActiveEditor(IEditorPart) line: 148	
CompilationUnitEditorActionContributor.setActiveEditor(IEditorPart) line: 65	
EditorActionBars.partChanged(IWorkbenchPart) line: 335	
WorkbenchPage.updateActivations(MPart) line: 329	
WorkbenchPage$E4PartListener.partActivated(MPart) line: 218	
PartServiceImpl$2.run() line: 249	
...

Can you validate that this code is still executed for the editor in which the undo/redo actions are not working anymore? Are there any error in the error log that are triggered by switching the editor?
Comment 4 Rolf Theunissen CLA 2021-03-08 03:27:54 EST
I took the effort to connect a debugger to TLA+.

For the default text editor, global actions are installed when a part is activated by BasicTextEditorActionContributor#setActiveEditor and BasicTextEditorActionContributor#doSetActiveEditor.
In the TLA case, the TLAMultiPageEditorActionBarContributor is used. In this implementation, the global actions are not installed when a part is activated. If the TLAMultiPageEditorActionBarContributor would have extended MultiPageContributor instead of MultiPageEditorActionBarContributor some of the editor functionality would have been installed. However still much of the text editors would not have been installed.

Looking at the code, I am kind of surprised that the old code worked at all. For now I am inclined to say that it is not an Eclipse issue.

Did the old version have an undo-history that was shared among multiple editors? That is, would it first undo the last changes in the current editor, and then undo previous edits in another editor?
Comment 5 Rolf Theunissen CLA 2021-03-08 06:55:10 EST
After all, it does seem to be caused by different behavior of Eclipse. Not sure though if the old or the new behavior is the correct behavior. The old behavior might have hidden bugs in your code.

What I observe is that the undo-handler is registered two times, with different active when expressions. Probably, one is a global registered and the other is local to the editor. One expression is a AND expression of  LegacyHandlerSubmission and WorkbenchWindowExpression, the other is a AND expression of LegacyEditorActionBarExpression  and WorkbenchWindowExpression. The priority of the first expression seems to change in the newer Eclipse versions, therefore the priority of the two handlers is inversed. This inversion might uncover an existing problem in the previously low-priority handler.

Will look further when I have some more spare time left.
Comment 6 Rolf Theunissen CLA 2021-03-08 07:56:05 EST
The double registration happens inside AbstractTextEditor#registerUndoRedoAction, first as the result of setAction with on a command with a keybinding, second in setGlobalActionHandler.

The inversion of priority is the result of Bug 426557, that simplified the expression of the first registration which increased its priority.
Comment 7 Markus Kuppe CLA 2021-03-09 14:44:21 EST
Thanks for your efforts!  After some nire trial-and-error, it seems as if forcefully resetting the actionbar's global handlers with the editor's actions in org.eclipse.ui.part.MultiPageEditorActionBarContributor.setActivePage(IEditorPart) alleviates the issue:

> final IActionBars actionBars = getActionBars();
> actionBars.setGlobalActionHandler("undo", editor.getAction("undo"));
> actionBars.setGlobalActionHandler("redo", editor.getAction("redo"));


https://github.com/tlaplus/tlaplus/commit/be769427fd35b46d6bb0c14a4314df53523e294c