From 196b3d2b78d55e140036f50fbf2a363cba5f69d0 Mon Sep 17 00:00:00 2001 From: Andrey Loskutov Date: Fri, 29 Mar 2024 18:53:18 +0100 Subject: [PATCH] Add support for "editor" content types for compare editor Extend `contentMergeViewers` extension point: add an attribute to consider "linked" editor content type associations. The code checks if contentMergeViewers contribution refers to such "linked" editor id in extension, and check if editor supports other content types. In case there are more content types supported by same "linked" editor, these would be automatically considered as valid contentTypes for the contentMergeViewers. Updated CompareViewerSwitchingPane to consider more precise title calculations for ContentMergeViewer instances (where concrete type info is available after instantiation of a particular viewer). Fixes https://github.com/eclipse-jdt/eclipse.jdt.ui/issues/1294 --- .../.settings/.api_filters | 11 +++ .../org.eclipse.compare/META-INF/MANIFEST.MF | 2 +- .../compare/CompareViewerSwitchingPane.java | 13 ++- .../compare/internal/CompareUIPlugin.java | 88 +++++++++++++++++-- .../compare/internal/ViewerDescriptor.java | 39 ++++++++ .../schema/contentMergeViewers.exsd | 10 +++ 6 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 team/bundles/org.eclipse.compare/.settings/.api_filters diff --git a/team/bundles/org.eclipse.compare/.settings/.api_filters b/team/bundles/org.eclipse.compare/.settings/.api_filters new file mode 100644 index 00000000000..e4b95513f05 --- /dev/null +++ b/team/bundles/org.eclipse.compare/.settings/.api_filters @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/team/bundles/org.eclipse.compare/META-INF/MANIFEST.MF b/team/bundles/org.eclipse.compare/META-INF/MANIFEST.MF index af701cfc318..c3ee0dcfb6d 100644 --- a/team/bundles/org.eclipse.compare/META-INF/MANIFEST.MF +++ b/team/bundles/org.eclipse.compare/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.compare; singleton:=true -Bundle-Version: 3.10.100.qualifier +Bundle-Version: 3.11.0.qualifier Bundle-Activator: org.eclipse.compare.internal.CompareUIPlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/CompareViewerSwitchingPane.java b/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/CompareViewerSwitchingPane.java index 8e18f3cdb5c..0a088604e79 100644 --- a/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/CompareViewerSwitchingPane.java +++ b/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/CompareViewerSwitchingPane.java @@ -15,6 +15,7 @@ import java.text.MessageFormat; +import org.eclipse.compare.contentmergeviewer.ContentMergeViewer; import org.eclipse.compare.contentmergeviewer.IFlushable; import org.eclipse.compare.internal.CompareMessages; import org.eclipse.compare.internal.IFlushable2; @@ -279,9 +280,15 @@ public void setInput(Object input) { if (fViewer != null) { Control c= fViewer.getControl(); if (c != null) { - Object data= c.getData(CompareUI.COMPARE_VIEWER_TITLE); - if (data instanceof String) - title= (String) data; + if (fViewer instanceof ContentMergeViewer cmv) { + title = cmv.getTitle(); + } + if (title == null || title.isBlank()) { + Object data = c.getData(CompareUI.COMPARE_VIEWER_TITLE); + if (data instanceof String) { + title = (String) data; + } + } if (hadFocus) c.setFocus(); } diff --git a/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareUIPlugin.java b/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareUIPlugin.java index aeb4584e558..6704edff1ef 100644 --- a/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareUIPlugin.java +++ b/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareUIPlugin.java @@ -33,9 +33,12 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.ResourceBundle; import java.util.Set; import java.util.StringTokenizer; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.eclipse.compare.CompareConfiguration; import org.eclipse.compare.CompareEditorInput; @@ -77,6 +80,7 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorDescriptor; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorRegistry; @@ -192,12 +196,16 @@ List searchAll(String extension) { return fExtensionMap.get(normalizeCase(extension)); return null; } + + Collection getAll() { + return fIdMap.values(); + } } /** Status code describing an internal error */ public static final int INTERNAL_ERROR= 1; - private static boolean NORMALIZE_CASE= true; + private static boolean NORMALIZE_CASE = true; public static final String PLUGIN_ID= "org.eclipse.compare"; //$NON-NLS-1$ @@ -983,7 +991,7 @@ private Collection getContentTypes(Object in) { } public ViewerDescriptor[] findContentViewerDescriptor(Viewer oldViewer, Object in, CompareConfiguration cc) { - Set result = new LinkedHashSet<>(); + LinkedHashSet result = new LinkedHashSet<>(); if (in instanceof IStreamContentAccessor) { String type= ITypedElement.TEXT_TYPE; @@ -1007,6 +1015,7 @@ public ViewerDescriptor[] findContentViewerDescriptor(Viewer oldViewer, Object i List list = fContentViewers.searchAll(type); if (list != null) result.addAll(list); + // fallback result.add(fContentViewers.search(Platform.getContentTypeManager().getContentType(IContentTypeManager.CT_TEXT))); return result.toArray(new ViewerDescriptor[0]); @@ -1016,6 +1025,7 @@ public ViewerDescriptor[] findContentViewerDescriptor(Viewer oldViewer, Object i return null; ICompareInput input= (ICompareInput) in; + String name = input.getName(); IContentType ctype = getCommonType(input); if (ctype != null) { @@ -1054,6 +1064,9 @@ public ViewerDescriptor[] findContentViewerDescriptor(Viewer oldViewer, Object i result.addAll(list); } + Set editorLinkedDescriptors = findEditorLinkedDescriptors(name, ctype, false); + result.addAll(editorLinkedDescriptors); + // fallback String leftType= guessType(input.getLeft()); String rightType= guessType(input.getRight()); @@ -1069,14 +1082,74 @@ public ViewerDescriptor[] findContentViewerDescriptor(Viewer oldViewer, Object i result.addAll(list); } List list = fContentMergeViewers.searchAll(ITypedElement.TEXT_TYPE); - if (list != null) + if (list != null) { result.addAll(list); - - return result.toArray(new ViewerDescriptor[0]); + } } + + ensureTextIsLast(result); return result.isEmpty() ? null : result.toArray(new ViewerDescriptor[0]); } + /** + * Modifies given set to move "fallback" text descriptor to be the last one. + * This is needed because we want more specific descriptors used first by default. + */ + private static void ensureTextIsLast(LinkedHashSet result) { + if (result.size() > 1) { + ViewerDescriptor first = result.iterator().next(); + if (TextMergeViewerCreator.class.getName().equals(first.getViewerClass())) { + result.remove(first); + result.add(first); + } + } + } + + /** + * @param fileName possible file name for content in compare editor, may be + * null + * @param contentType possible content type for content in compare editor, may + * be null + * @param firstIsEnough stop searching once first match is found + * @return set of descriptors which could be found for given content type via + * "linked" editor + */ + Set findEditorLinkedDescriptors(String fileName, IContentType contentType, + boolean firstIsEnough) { + if (fileName == null) { + if (contentType == null) { + contentType = fgContentTypeManager.findContentTypeFor(fileName); + } else { + return Collections.emptySet(); + } + } + IEditorRegistry editorReg = PlatformUI.getWorkbench().getEditorRegistry(); + LinkedHashSet result = new LinkedHashSet<>(); + IEditorDescriptor[] editors = editorReg.getEditors(fileName, contentType); + for (IEditorDescriptor ed : editors) { + addLinkedEditorContentTypes(firstIsEnough, ed.getId(), result); + if (firstIsEnough && !result.isEmpty()) { + return result; + } + } + return result; + } + + private void addLinkedEditorContentTypes(boolean firstIsEnough, String editorId, Set result) { + Collection viewers = new LinkedHashSet<>(fContentMergeViewers.getAll()); + Stream stream = viewers.stream() + .filter(vd -> vd.getLinkedEditorId() != null) + .filter(vd -> editorId.equals(vd.getLinkedEditorId())); + if (firstIsEnough) { + Optional first = stream.findFirst(); + if (first.isPresent()) { + result.add(first.get()); + } + } else { + stream.collect(Collectors.toCollection(() -> result)); + } + } + /** * Returns a content compare viewer based on an old viewer and an input object. * If the old viewer is suitable for showing the input the old viewer @@ -1483,6 +1556,11 @@ String findContentTypeNameOrType(ICompareInput input, ViewerDescriptor vd, Compa return type; } + Set editorLinkedDescriptors = findEditorLinkedDescriptors(input.getName(), ctype, true); + if (!editorLinkedDescriptors.isEmpty()) { + return type; + } + // fallback String leftType= guessType(input.getLeft()); String rightType= guessType(input.getRight()); diff --git a/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/ViewerDescriptor.java b/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/ViewerDescriptor.java index a9b2c57dfcf..2bfec2bb9d9 100644 --- a/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/ViewerDescriptor.java +++ b/team/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/ViewerDescriptor.java @@ -27,6 +27,7 @@ public class ViewerDescriptor implements IViewerDescriptor { private final static String CLASS_ATTRIBUTE= "class"; //$NON-NLS-1$ private final static String EXTENSIONS_ATTRIBUTE= "extensions"; //$NON-NLS-1$ + private final static String LINKED_EDITOR_ATTRIBUTE = "linkedEditor"; //$NON-NLS-1$ private final static String LABEL_ATTRIBUTE = "label"; //$NON-NLS-1$ private final IConfigurationElement fConfiguration; @@ -79,4 +80,42 @@ public String getExtension() { String getLabel() { return fConfiguration.getAttribute(LABEL_ATTRIBUTE); } + + String getLinkedEditorId() { + return fConfiguration.getAttribute(LINKED_EDITOR_ATTRIBUTE); + } + + String getViewerClass() { + return fConfiguration.getAttribute(CLASS_ATTRIBUTE); + } + + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("ViewerDescriptor ["); + if (fViewerClass != null) { + sb.append("viewerClass="); + sb.append(fViewerClass); + sb.append(", "); + } + if (fViewerCreator != null) { + sb.append("viewerCreator="); + sb.append(fViewerCreator); + sb.append(", "); + } + String viewerClass = getViewerClass(); + if (viewerClass != null) { + sb.append("viewerClass="); + sb.append(viewerClass); + sb.append(", "); + } + if (fConfiguration != null) { + sb.append("configuration="); + sb.append(fConfiguration); + } + sb.append("]"); + return sb.toString(); + } + } diff --git a/team/bundles/org.eclipse.compare/schema/contentMergeViewers.exsd b/team/bundles/org.eclipse.compare/schema/contentMergeViewers.exsd index bcf883b8313..a470ec13d51 100644 --- a/team/bundles/org.eclipse.compare/schema/contentMergeViewers.exsd +++ b/team/bundles/org.eclipse.compare/schema/contentMergeViewers.exsd @@ -90,6 +90,16 @@ content merge viewer and implements <samp>org.eclipse.compare.IViewerCreat + + + + Since 3.11. Editor id to consider editor content type associations to be used also for content type bindings of this viewer + + + + + +