Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ public class CompareContentViewerSwitchingPane extends CompareViewerSwitchingPan

private ViewerDescriptor fSelectedViewerDescriptor;

/** Descriptors computed by getViewer, reused by setInput to avoid a second lookup. */
private ViewerDescriptor[] fViewerDescriptors;

private ToolBar toolBar;
private CLabel labelOptimized;
private Link recomputeLink;
Expand All @@ -79,9 +82,10 @@ private CompareConfiguration getCompareConfiguration() {
@Override
protected Viewer getViewer(Viewer oldViewer, Object input) {
if (fSelectedViewerDescriptor != null) {
ViewerDescriptor[] array = CompareUIPlugin.getDefault().findContentViewerDescriptor(
fViewerDescriptors = CompareUIPlugin.getDefault().findContentViewerDescriptor(
oldViewer, input, getCompareConfiguration());
List<ViewerDescriptor> list = array != null ? Arrays.asList(array) : Collections.emptyList();
List<ViewerDescriptor> list = fViewerDescriptors != null ? Arrays.asList(fViewerDescriptors)
: Collections.emptyList();
if (list.contains(fSelectedViewerDescriptor)) {
// use selected viewer only when appropriate for the new input
fCompareEditorInput
Expand All @@ -94,12 +98,19 @@ protected Viewer getViewer(Viewer oldViewer, Object input) {
fSelectedViewerDescriptor = null;
}
if (input instanceof ICompareInput) {
fCompareEditorInput.setContentViewerDescriptor(null);
fViewerDescriptors = CompareUIPlugin.getDefault().findContentViewerDescriptor(
oldViewer, input, getCompareConfiguration());
// Feeding the default descriptor avoids a second lookup inside findContentViewer.
ViewerDescriptor defaultDescriptor = fViewerDescriptors != null && fViewerDescriptors.length > 0
? fViewerDescriptors[0]
: null;
fCompareEditorInput.setContentViewerDescriptor(defaultDescriptor);
Viewer viewer =
fCompareEditorInput.findContentViewer(oldViewer, (ICompareInput) input, this);
fCompareEditorInput.setContentViewerDescriptor(fSelectedViewerDescriptor);
return viewer;
}
fViewerDescriptors = null;
return null;
}

Expand Down Expand Up @@ -203,8 +214,12 @@ public void setInput(Object input) {
if (getViewer() == null || !Utilities.okToUse(getViewer().getControl())) {
return;
}
ViewerDescriptor[] vd = CompareUIPlugin.getDefault()
.findContentViewerDescriptor(getViewer(), getInput(), getCompareConfiguration());
// Reuse the descriptors computed by getViewer; recompute only if the cache is empty.
ViewerDescriptor[] vd = fViewerDescriptors;
if (vd == null) {
vd = CompareUIPlugin.getDefault()
.findContentViewerDescriptor(getViewer(), getInput(), getCompareConfiguration());
}
boolean toolbarVisible = vd != null && vd.length > 1;
toolBar.setVisible(toolbarVisible);
((RowData) toolBar.getLayoutData()).exclude = !toolbarVisible;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ public class CompareStructureViewerSwitchingPane extends

private ViewerDescriptor fSelectedViewerDescriptor;

/** Descriptors computed by getViewer, reused by setInput to avoid a second lookup. */
private ViewerDescriptor[] fViewerDescriptors;

private ToolBar toolBar;

public CompareStructureViewerSwitchingPane(Composite parent, int style,
Expand All @@ -68,9 +71,10 @@ private CompareConfiguration getCompareConfiguration() {
protected Viewer getViewer(Viewer oldViewer, Object input) {
if (input instanceof ICompareInput) {
if (fSelectedViewerDescriptor != null) {
ViewerDescriptor[] array = CompareUIPlugin.getDefault().findStructureViewerDescriptor(
fViewerDescriptors = CompareUIPlugin.getDefault().findStructureViewerDescriptor(
oldViewer, (ICompareInput)input, getCompareConfiguration());
List<ViewerDescriptor> list = array != null ? Arrays.asList(array) : Collections.emptyList();
List<ViewerDescriptor> list = fViewerDescriptors != null ? Arrays.asList(fViewerDescriptors)
: Collections.emptyList();
if (list.contains(fSelectedViewerDescriptor)) {
// use selected viewer only when appropriate for the new input
fCompareEditorInput
Expand All @@ -83,12 +87,15 @@ protected Viewer getViewer(Viewer oldViewer, Object input) {
fSelectedViewerDescriptor = null;
}

// The default path computes no descriptors; invalidate so setInput recomputes.
fViewerDescriptors = null;
fCompareEditorInput.setStructureViewerDescriptor(null);
Viewer viewer = fCompareEditorInput.findStructureViewer(oldViewer,
(ICompareInput) input, this);
fCompareEditorInput.setStructureViewerDescriptor(fSelectedViewerDescriptor);
return viewer;
}
fViewerDescriptors = null;
return null;
}

Expand Down Expand Up @@ -141,8 +148,9 @@ public void setInput(Object input) {
if (getViewer() == null || !Utilities.okToUse(getViewer().getControl())) {
return;
}
ViewerDescriptor[] vd = null;
if (getInput() instanceof ICompareInput) {
// Reuse the descriptors computed by getViewer; recompute only if the cache is empty.
ViewerDescriptor[] vd = fViewerDescriptors;
if (vd == null && getInput() instanceof ICompareInput) {
vd = CompareUIPlugin.getDefault().findStructureViewerDescriptor(
getViewer(), (ICompareInput) getInput(),
getCompareConfiguration());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
Expand Down Expand Up @@ -261,6 +262,14 @@ Collection<T> getAll() {
// content type
private static final IContentTypeManager fgContentTypeManager= Platform.getContentTypeManager();

/**
* Per-open memoization of content-type sniffing, keyed by element identity and
* reset when a different input is examined. Only accessed on the UI thread.
*/
private static Object fSniffInput;
private static final Map<ITypedElement, IContentType> fContentTypeSniffCache= new IdentityHashMap<>();
private static final Map<ITypedElement, String> fGuessTypeSniffCache= new IdentityHashMap<>();

public static final int NO_DIFFERENCE = 10000;

/**
Expand Down Expand Up @@ -1060,6 +1069,7 @@ public IStreamMerger createStreamMerger(IContentType type) {

public ViewerDescriptor[] findStructureViewerDescriptor(Viewer oldViewer,
ICompareInput input, CompareConfiguration configuration) {
beginContentTypeSniffing(input);
// we don't show the structure of additions or deletions
if ((input == null) || input == null || input.getLeft() == null || input.getRight() == null) {
return null;
Expand Down Expand Up @@ -1245,6 +1255,7 @@ private Collection<Object> getContentTypes(Object in) {
}

public ViewerDescriptor[] findContentViewerDescriptor(Viewer oldViewer, Object in, CompareConfiguration cc) {
beginContentTypeSniffing(in);
LinkedHashSet<ViewerDescriptor> result = new LinkedHashSet<>();
if (in instanceof IStreamContentAccessor) {
String type= ITypedElement.TEXT_TYPE;
Expand Down Expand Up @@ -1469,10 +1480,28 @@ private static String[] getTypes(ICompareInput input) {
return tmp.toArray(new String[tmp.size()]);
}

/** Resets the sniffing caches when a different input is examined. */
private static void beginContentTypeSniffing(Object input) {
if (input != fSniffInput) {
fContentTypeSniffCache.clear();
fGuessTypeSniffCache.clear();
fSniffInput= input;
}
}

private static IContentType getContentType(ITypedElement element) {
if (element == null) {
return null;
}
if (fContentTypeSniffCache.containsKey(element)) {
return fContentTypeSniffCache.get(element);
}
IContentType ct= computeContentType(element);
fContentTypeSniffCache.put(element, ct);
return ct;
}

private static IContentType computeContentType(ITypedElement element) {
String name= element.getName();
IContentType ct= null;
if (element instanceof IResourceProvider) {
Expand Down Expand Up @@ -1603,6 +1632,18 @@ private static IContentType[] toFullPath(IContentType ct) {
* Returns <code>null</code> if the input isn't an <code>IStreamContentAccessor</code>.
*/
private static String guessType(ITypedElement input) {
if (input == null) {
return null;
}
if (fGuessTypeSniffCache.containsKey(input)) {
return fGuessTypeSniffCache.get(input);
}
String guessed= computeGuessType(input);
fGuessTypeSniffCache.put(input, guessed);
return guessed;
}

private static String computeGuessType(ITypedElement input) {
if (input instanceof IStreamContentAccessor sca) {
InputStream is= null;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ public class CompareOpenEfficiencyTest {

/**
* Upper bound for the {@code getContents()} calls per side during a single
* compare editor open, caused by repeated content-type sniffing and viewer
* descriptor lookups. The exact count is platform dependent (observed: 15 on
* Linux and Windows, 9 on macOS), so only the worst case is asserted.
* compare editor open: one read for content-type detection, one for the text
* heuristic, and one for the document shown in the viewer. Asserted as a bound
* because the exact count can vary by platform.
*/
private static final int MAX_GET_CONTENTS_PER_SIDE = 15;
private static final int MAX_GET_CONTENTS_PER_SIDE = 3;

private static final long TIMEOUT_MILLIS = 30_000;

Expand Down
Loading