In the 3.3 release, we are planning on working on some of the outstanding defects that have accumulated for the Compare component. Some of the areas we plan on looking at are:
- Asynchronous loading and update of compare editors
- Improving the save life-cycling
- Improving difference and change Navigation
- Use of text buffers when comparing local content
- Upgrade to use the new Commands/Key bindings framework
- Switch to using the History view for local history operations (Compare/Replace/Restore)
The following sections outline some thoughts on each of these areas.
Saving properly in the Compare framework has always been a bit of a black art. See bug 125538 for a description of one way of making it work. The reason for this is the layered nature of the Compare framework. For a local file, the layers are:
- The file (instance of IFile)
- The ResourceNode (instance of IEditableContent)
- The TextMergeViewer
Assume you have an merge viewer open and edit the left side. A save is triggered by a Save operation or selecting another element to edit. What happens in this case is the following:
- Save is called on ContentMergeViewer
- Save obtains the content from the left side of the content merge viewer and passes it to the viewer content provider (instance of MergeViewerContentProvider).
- The content provider calls saveContent on the left typed element of the compare input (if the compare input is an IEditableContent).
- the ResourceNode updates its buffer to contain the new content and fire a change event
- if you want the file to be saved, you need to listen to that event and call commit on the ResourceDiffNode
There are a couple of observations that can be made about this:
- The ContentMergeViewer portion of the above only works with byte oriented content.
- Both the document in the TextMergeViewer and the ResourceNode buffer the contents of the file (that means there are at least two in-memory versions of the file for each side (and the ancestor if there is one).
- the save method of ContentMergeViewer is really a flush.
- However most client (e.g. Team Synchronize) treat the flush as an indication that a save should occur.
There are a few other issues to consider here:
- Implementors of custom ContentMergeViewers need to be able to participate in the saving of ContentMergeViewers (see bug 143852)
- The Saveable API was introduced in Eclipse 3.2 and could potentially be used by merge viewers.
Here are some thoughts on how this would work.
- Each CompareInput may have one or more Saveables associated with them (they could be ISaveableSources).
- The CompareEditorInput would keep track of what Saveables it contained and would keep the workbench view of them up-to-date.
- If the ContentMergeViewer or subclass wants to save, they can flush and then invoke save on the appropriate Saveables (i.e. it may only be a subset of the Saveables in the CompareEditorInput).
- If the editor is saved, again, a flush is required before the save is issued to all dirty saveables of the CompareEditorInput.
- Of course, backwards compatibility must be maintained.
There are two different styles at odds here:
- The current style involes a merge viewer that buffers the changes in the viewer's document and flushes them to the compare input (or diff node) before a save or if the comapre input changes.
- An alternate style involves the changes being recording into the compare input (i.e. Saveable or file buffer) immediately.
The second style, in combination with the use of file buffers, would make the Compare editor save lifecycle more in-line with the workbench. The problem is backwards compatibility. We can modify ContentMergeViewer, TextMergeViewer and all other SDK subclasses to work with Saveables but the old behavior must remain for other ContentMergeViewer subclasses. Similarly, CompareEditorInputs that don't use Saveables and require viewer flushes must still work as well.