diff options
author | Mickael Istria | 2017-08-08 14:33:41 +0000 |
---|---|---|
committer | Mickael Istria | 2017-08-08 23:00:38 +0000 |
commit | 1ba9040176a1bdaf3c47df85728ae4ab5b0d2a93 (patch) | |
tree | f15d6c6e94d1f07e3c163a9e8c94321f6ad75ce8 | |
parent | 896e9624a30afb9e3f75daa648707b808d26ae0b (diff) | |
download | eclipse.platform.text-1ba9040176a1bdaf3c47df85728ae4ab5b0d2a93.tar.gz eclipse.platform.text-1ba9040176a1bdaf3c47df85728ae4ab5b0d2a93.tar.xz eclipse.platform.text-1ba9040176a1bdaf3c47df85728ae4ab5b0d2a93.zip |
Bug 520685 - [Generic Editor] Sort ext. by most specialized content-typeI20170809-2000
Factorize extensions and registry polling (can be continued).
This allows most registries to return first the extension that applies
to the most specialized content-types.
Change-Id: Icfd5d0c2e72cd579e9fe8c034420d88c628f39a6
Signed-off-by: Mickael Istria <mistria@redhat.com>
16 files changed, 243 insertions, 198 deletions
diff --git a/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/NaturesAndProjectsContentAssistProcessor.java b/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/NaturesAndProjectsContentAssistProcessor.java index 1f8fd98bb90..c78d9cc5158 100644 --- a/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/NaturesAndProjectsContentAssistProcessor.java +++ b/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/NaturesAndProjectsContentAssistProcessor.java @@ -14,7 +14,6 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectNatureDescriptor; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; - import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.contentassist.CompletionProposal; import org.eclipse.jface.text.contentassist.ICompletionProposal; @@ -24,6 +23,10 @@ import org.eclipse.jface.text.contentassist.IContextInformationValidator; public class NaturesAndProjectsContentAssistProcessor implements IContentAssistProcessor { + public NaturesAndProjectsContentAssistProcessor() { + // TODO Auto-generated constructor stub + } + @Override public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { String text = viewer.getDocument().get(); diff --git a/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/TagAutoEditStrategy.java b/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/TagAutoEditStrategy.java index c997bae69d6..a8c689e9ed8 100644 --- a/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/TagAutoEditStrategy.java +++ b/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/TagAutoEditStrategy.java @@ -18,6 +18,10 @@ import org.eclipse.jface.text.IRegion; public class TagAutoEditStrategy implements IAutoEditStrategy { + public TagAutoEditStrategy() { + // TODO Auto-generated constructor stub + } + @Override public void customizeDocumentCommand(IDocument document, DocumentCommand command) { if (!">".equals(command.text)) { //$NON-NLS-1$ diff --git a/org.eclipse.ui.genericeditor.tests/plugin.xml b/org.eclipse.ui.genericeditor.tests/plugin.xml index a6b4124536f..4d02c03dfc1 100644 --- a/org.eclipse.ui.genericeditor.tests/plugin.xml +++ b/org.eclipse.ui.genericeditor.tests/plugin.xml @@ -36,14 +36,22 @@ class="org.eclipse.ui.genericeditor.tests.contributions.TheReconciler" contentType="org.eclipse.ui.genericeditor.tests.content-type"> </reconciler> - </extension> - <extension + </extension> + <extension point="org.eclipse.ui.genericeditor.presentationReconcilers"> <presentationReconciler - class="org.eclipse.ui.genericeditor.tests.contributions.ThePresentationReconciler" - contentType="org.eclipse.ui.genericeditor.tests.content-type"> + class="org.eclipse.ui.genericeditor.tests.contributions.ThePresentationReconcilerBlue" + contentType="org.eclipse.core.runtime.text"> + </presentationReconciler> + <presentationReconciler + class="org.eclipse.ui.genericeditor.tests.contributions.ThePresentationReconcilerRed" + contentType="org.eclipse.ui.genericeditor.tests.specialized-content-type"> + </presentationReconciler> + <presentationReconciler + class="org.eclipse.ui.genericeditor.tests.contributions.ThePresentationReconcilerGreen" + contentType="org.eclipse.ui.genericeditor.tests.content-type"> </presentationReconciler> - </extension> + </extension> <extension point="org.eclipse.ui.ide.markerResolution"> <markerResolutionGenerator @@ -60,6 +68,13 @@ name="Generic Editor Test content-type" priority="normal"> </content-type> + <content-type + base-type="org.eclipse.ui.genericeditor.tests.content-type" + file-names="foo.txt" + id="org.eclipse.ui.genericeditor.tests.specialized-content-type" + name="Specialized Generic Editor content-type" + priority="normal"> + </content-type> </extension> <extension point="org.eclipse.ui.genericeditor.autoEditStrategies"> @@ -69,11 +84,11 @@ </autoEditStrategy> <autoEditStrategy class="org.eclipse.ui.genericeditor.tests.contributions.TheAutoEditStrategySecond" - contentType="org.eclipse.core.runtime.text"> + contentType="org.eclipse.ui.genericeditor.tests.content-type"> </autoEditStrategy> <autoEditStrategy class="org.eclipse.ui.genericeditor.tests.contributions.TheAutoEditStrategyThird" - contentType="org.eclipse.core.runtime.text"> + contentType="org.eclipse.ui.genericeditor.tests.specialized-content-type"> </autoEditStrategy> </extension> diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/AutoEditTest.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/AutoEditTest.java index 8a30f57a70d..1aa3a3e5146 100644 --- a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/AutoEditTest.java +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/AutoEditTest.java @@ -25,7 +25,8 @@ public class AutoEditTest extends AbstratGenericEditorTest { IDocument document= editor.getDocumentProvider().getDocument(editor.getEditorInput()); StyledText control= (StyledText) editor.getAdapter(Control.class); control.setText(""); - Assert.assertEquals("AutoAddedFirst! AutoAddedSecond! AutoAddedThird!", document.get()); + // order of auto-edits from most specialized to least specialized + Assert.assertEquals("AutoAddedThird!AutoAddedSecond!AutoAddedFirst!", document.get()); } } diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/TheAutoEditStrategySecond.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/TheAutoEditStrategySecond.java index 37e2587d8ed..92c0ec64b10 100644 --- a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/TheAutoEditStrategySecond.java +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/TheAutoEditStrategySecond.java @@ -18,7 +18,7 @@ public class TheAutoEditStrategySecond implements IAutoEditStrategy { @Override public void customizeDocumentCommand(IDocument document, DocumentCommand command) { - command.text = command.text + " AutoAddedSecond!"; + command.text = command.text + "AutoAddedSecond!"; } } diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/TheAutoEditStrategyThird.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/TheAutoEditStrategyThird.java index c7882aaf446..5c4ef8c8d3e 100644 --- a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/TheAutoEditStrategyThird.java +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/TheAutoEditStrategyThird.java @@ -18,7 +18,7 @@ public class TheAutoEditStrategyThird implements IAutoEditStrategy { @Override public void customizeDocumentCommand(IDocument document, DocumentCommand command) { - command.text = command.text + " AutoAddedThird!"; + command.text = command.text + "AutoAddedThird!"; } } diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/ThePresentationReconcilerBlue.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/ThePresentationReconcilerBlue.java new file mode 100644 index 00000000000..44ce5c58b31 --- /dev/null +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/ThePresentationReconcilerBlue.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2016 Red Hat Inc. and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sopot Cela (Red Hat Inc.) + *******************************************************************************/ +package org.eclipse.ui.genericeditor.tests.contributions; + +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Display; + +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.TextAttribute; +import org.eclipse.jface.text.presentation.PresentationReconciler; +import org.eclipse.jface.text.rules.DefaultDamagerRepairer; +import org.eclipse.jface.text.rules.IRule; +import org.eclipse.jface.text.rules.RuleBasedScanner; +import org.eclipse.jface.text.rules.SingleLineRule; +import org.eclipse.jface.text.rules.Token; + +public class ThePresentationReconcilerBlue extends PresentationReconciler { + + public ThePresentationReconcilerBlue() { + RuleBasedScanner scanner= new RuleBasedScanner(); + IRule[] rules = new IRule[1]; + rules[0]= new SingleLineRule("'", "'", new Token(new TextAttribute(new Color(Display.getCurrent(), new RGB(0, 0, 255))))); //$NON-NLS-1$ //$NON-NLS-2$ + scanner.setRules(rules); + DefaultDamagerRepairer dr= new DefaultDamagerRepairer(scanner); + this.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE); + this.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE); + } + +} diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/ThePresentationReconcilerGreen.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/ThePresentationReconcilerGreen.java new file mode 100644 index 00000000000..2c6d8c41b54 --- /dev/null +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/ThePresentationReconcilerGreen.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2016-2017 Red Hat Inc. and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sopot Cela (Red Hat Inc.) + *******************************************************************************/ +package org.eclipse.ui.genericeditor.tests.contributions; + +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Display; + +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.TextAttribute; +import org.eclipse.jface.text.presentation.PresentationReconciler; +import org.eclipse.jface.text.rules.DefaultDamagerRepairer; +import org.eclipse.jface.text.rules.IRule; +import org.eclipse.jface.text.rules.RuleBasedScanner; +import org.eclipse.jface.text.rules.SingleLineRule; +import org.eclipse.jface.text.rules.Token; + +/** + * This presentation reconciler is associated to a more "basic" content-type so it + * shouldn't be used. + */ +public class ThePresentationReconcilerGreen extends PresentationReconciler { + + public ThePresentationReconcilerGreen() { + RuleBasedScanner scanner= new RuleBasedScanner(); + IRule[] rules = new IRule[1]; + rules[0]= new SingleLineRule("'", "'", new Token(new TextAttribute(new Color(Display.getCurrent(), new RGB(0, 255, 0))))); //$NON-NLS-1$ //$NON-NLS-2$ + scanner.setRules(rules); + DefaultDamagerRepairer dr= new DefaultDamagerRepairer(scanner); + this.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE); + this.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE); + } + +} diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/ThePresentationReconciler.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/ThePresentationReconcilerRed.java index c2ee68a7417..abfd5cb0e1a 100644 --- a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/ThePresentationReconciler.java +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/ThePresentationReconcilerRed.java @@ -23,9 +23,9 @@ import org.eclipse.jface.text.rules.RuleBasedScanner; import org.eclipse.jface.text.rules.SingleLineRule; import org.eclipse.jface.text.rules.Token; -public class ThePresentationReconciler extends PresentationReconciler { +public class ThePresentationReconcilerRed extends PresentationReconciler { - public ThePresentationReconciler() { + public ThePresentationReconcilerRed() { RuleBasedScanner scanner= new RuleBasedScanner(); IRule[] rules = new IRule[1]; rules[0]= new SingleLineRule("'", "'", new Token(new TextAttribute(new Color(Display.getCurrent(), new RGB(255, 0, 0))))); //$NON-NLS-1$ //$NON-NLS-2$ diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/AutoEditStrategyRegistry.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/AutoEditStrategyRegistry.java index 349f455d7ba..425415a953b 100644 --- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/AutoEditStrategyRegistry.java +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/AutoEditStrategyRegistry.java @@ -10,14 +10,13 @@ *******************************************************************************/ package org.eclipse.ui.internal.genericeditor; -import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IRegistryChangeEvent; import org.eclipse.core.runtime.IRegistryChangeListener; @@ -39,36 +38,9 @@ public class AutoEditStrategyRegistry { private static final String EXTENSION_POINT_ID = GenericEditorPlugin.BUNDLE_ID + ".autoEditStrategies"; //$NON-NLS-1$ - private Map<IConfigurationElement, AutoEditStrategyExtension> extensions = new LinkedHashMap<>(); + private Map<IConfigurationElement, GenericContentTypeRelatedExtension<IAutoEditStrategy>> extensions = new LinkedHashMap<>(); private boolean outOfSync = true; - static class AutoEditStrategyExtension { - private static final String CONTENT_TYPE_ATTRIBUTE = "contentType"; //$NON-NLS-1$ - private static final String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$ - - private IConfigurationElement extension; - private IContentType targetContentType; - - public AutoEditStrategyExtension(IConfigurationElement extension) throws Exception { - this.extension = extension; - this.targetContentType = Platform.getContentTypeManager() - .getContentType(extension.getAttribute(CONTENT_TYPE_ATTRIBUTE)); - } - - public IAutoEditStrategy createStrategy() { - try { - return (IAutoEditStrategy) extension.createExecutableExtension(CLASS_ATTRIBUTE); - } catch (CoreException e) { - GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, e.getMessage(), e)); - return null; - } - } - - IConfigurationElement getConfigurationElement() { - return this.extension; - } - } - /** * Creates the registry and binds it to the extension point. */ @@ -96,16 +68,11 @@ public class AutoEditStrategyRegistry { if (this.outOfSync) { sync(); } - List<IAutoEditStrategy> res = new ArrayList<>(); - for (AutoEditStrategyExtension ext : this.extensions.values()) { - if (contentTypes.contains(ext.targetContentType)) { - IAutoEditStrategy strategy = ext.createStrategy(); - if (strategy != null) { - res.add(strategy); - } - } - } - return res; + return this.extensions.values().stream() + .filter(ext -> contentTypes.contains(ext.targetContentType)) + .sorted(new ContentTypeSpecializationComparator<IAutoEditStrategy>()) + .map(GenericContentTypeRelatedExtension<IAutoEditStrategy>::createDelegate) + .collect(Collectors.toList()); } private void sync() { @@ -115,7 +82,7 @@ public class AutoEditStrategyRegistry { toRemoveExtensions.remove(extension); if (!this.extensions.containsKey(extension)) { try { - this.extensions.put(extension, new AutoEditStrategyExtension(extension)); + this.extensions.put(extension, new GenericContentTypeRelatedExtension<IAutoEditStrategy>(extension)); } catch (Exception ex) { GenericEditorPlugin.getDefault().getLog() .log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, ex.getMessage(), ex)); diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentAssistProcessorRegistry.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentAssistProcessorRegistry.java index 0da557bfef7..187de272595 100644 --- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentAssistProcessorRegistry.java +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentAssistProcessorRegistry.java @@ -10,15 +10,14 @@ *******************************************************************************/ package org.eclipse.ui.internal.genericeditor; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.eclipse.core.filebuffers.FileBuffers; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IRegistryChangeEvent; @@ -127,39 +126,7 @@ public class ContentAssistProcessorRegistry { } } - /** - * This class wraps and proxies an {@link IContentAssistProcessor} provided through extensions - * and loads it lazily when it can contribute to the editor, then delegates all operations to - * actual processor. - * When the contribution cannot contribute to the editor, this wrapper will return neutral values - * that don't affect editor behavior. - */ - private static class ContentAssistProcessorExtension { - private static final String CONTENT_TYPE_ATTRIBUTE = "contentType"; //$NON-NLS-1$ - private static final String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$ - - private IConfigurationElement extension; - private IContentType targetContentType; - - private ContentAssistProcessorExtension(IConfigurationElement element) throws Exception { - this.extension = element; - this.targetContentType = Platform.getContentTypeManager().getContentType(element.getAttribute(CONTENT_TYPE_ATTRIBUTE)); - } - - public ContentAssistProcessorDelegate createDelegate() { - try { - IContentAssistProcessor delegate = (IContentAssistProcessor) extension.createExecutableExtension(CLASS_ATTRIBUTE); - if (delegate != null) { - return new ContentAssistProcessorDelegate(delegate, targetContentType); - } - } catch (CoreException e) { - GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, e.getMessage(), e)); - } - return null; - } - } - - private Map<IConfigurationElement, ContentAssistProcessorExtension> extensions = new HashMap<>(); + private Map<IConfigurationElement, GenericContentTypeRelatedExtension<IContentAssistProcessor>> extensions = new HashMap<>(); private boolean outOfSync = true; /** @@ -185,13 +152,11 @@ public class ContentAssistProcessorRegistry { if (this.outOfSync) { sync(); } - List<IContentAssistProcessor> res = new ArrayList<>(); - for (ContentAssistProcessorExtension ext : this.extensions.values()) { - if (contentTypes.contains(ext.targetContentType)) { - res.add(ext.createDelegate()); - } - } - return res; + return this.extensions.values().stream() + .filter(ext -> contentTypes.contains(ext.targetContentType)) + .sorted(new ContentTypeSpecializationComparator<IContentAssistProcessor>()) + .map(GenericContentTypeRelatedExtension<IContentAssistProcessor>::createDelegate) + .collect(Collectors.toList()); } private void sync() { @@ -200,7 +165,7 @@ public class ContentAssistProcessorRegistry { toRemoveExtensions.remove(extension); if (!this.extensions.containsKey(extension)) { try { - this.extensions.put(extension, new ContentAssistProcessorExtension(extension)); + this.extensions.put(extension, new GenericContentTypeRelatedExtension<IContentAssistProcessor>(extension)); } catch (Exception ex) { GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, ex.getMessage(), ex)); } diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentTypeSpecializationComparator.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentTypeSpecializationComparator.java new file mode 100644 index 00000000000..2a2d329434c --- /dev/null +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentTypeSpecializationComparator.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2017 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * - Mickael Istria (Red Hat Inc.) + *******************************************************************************/ +package org.eclipse.ui.internal.genericeditor; + +import java.util.Comparator; + +import org.eclipse.core.runtime.content.IContentType; + +/** + * Compares extension so that the ones with the most "specialized" content-types are returned first. + * + * @param <T> + */ +public class ContentTypeSpecializationComparator<T> implements Comparator<GenericContentTypeRelatedExtension<T>> { + + @Override + public int compare(GenericContentTypeRelatedExtension<T> o1, GenericContentTypeRelatedExtension<T> o2) { + return depth(o2.targetContentType) - depth(o1.targetContentType); + } + + private static int depth(IContentType targetContentType) { + int res = 0; + IContentType current = targetContentType; + while (current != null) { + res++; + current = current.getBaseType(); + } + return res; + } + +} diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericContentTypeRelatedExtension.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericContentTypeRelatedExtension.java new file mode 100644 index 00000000000..da7dc2be16c --- /dev/null +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericContentTypeRelatedExtension.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2017 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * - Mickael Istria (Red Hat Inc.) + *******************************************************************************/ +package org.eclipse.ui.internal.genericeditor; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.content.IContentType; + +/** + * This class wraps and proxies an instance of T provided through extensions + * and loads it lazily when it can contribute to the editor, then delegates all operations to + * actual instance. + * + * @param <T> the actual type to proxy, typically the one defined on the extension point. + */ +public class GenericContentTypeRelatedExtension<T> { + private static final String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$ + private static final String CONTENT_TYPE_ATTRIBUTE = "contentType"; //$NON-NLS-1$ + + public final IConfigurationElement extension; + public final IContentType targetContentType; + + public GenericContentTypeRelatedExtension(IConfigurationElement element) throws Exception { + this.extension = element; + this.targetContentType = Platform.getContentTypeManager().getContentType(element.getAttribute(CONTENT_TYPE_ATTRIBUTE)); + } + + public T createDelegate() { + try { + return (T) extension.createExecutableExtension(CLASS_ATTRIBUTE); + } catch (CoreException e) { + GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, e.getMessage(), e)); + } + return null; + } +} diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/PresentationReconcilerRegistry.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/PresentationReconcilerRegistry.java index b1692332f9b..6826e4ead20 100644 --- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/PresentationReconcilerRegistry.java +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/PresentationReconcilerRegistry.java @@ -10,14 +10,13 @@ *******************************************************************************/ package org.eclipse.ui.internal.genericeditor; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IRegistryChangeEvent; import org.eclipse.core.runtime.IRegistryChangeListener; @@ -38,33 +37,7 @@ public class PresentationReconcilerRegistry { private static final String EXTENSION_POINT_ID = GenericEditorPlugin.BUNDLE_ID + ".presentationReconcilers"; //$NON-NLS-1$ - /** - * This class wraps and proxies an {@link IPresentationReconcilier} provided through extensions - * and loads it lazily when it can contribute to the editor, then delegates all operations to - * actual reconcilier. - */ - private static class PresentationReconcilerExtension { - private static final String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$ - private static final String CONTENT_TYPE_ATTRIBUTE = "contentType"; //$NON-NLS-1$ - - private IConfigurationElement extension; - private IContentType targetContentType; - - private PresentationReconcilerExtension(IConfigurationElement element) throws Exception { - this.extension = element; - this.targetContentType = Platform.getContentTypeManager().getContentType(element.getAttribute(CONTENT_TYPE_ATTRIBUTE)); - } - - public IPresentationReconciler createDelegate() { - try { - return (IPresentationReconciler) extension.createExecutableExtension(CLASS_ATTRIBUTE); - } catch (CoreException e) { - GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, e.getMessage(), e)); - } - return null; - } - } - private Map<IConfigurationElement, PresentationReconcilerExtension> extensions = new HashMap<>(); + private Map<IConfigurationElement, GenericContentTypeRelatedExtension<IPresentationReconciler>> extensions = new HashMap<>(); private boolean outOfSync = true; /** @@ -90,13 +63,11 @@ public class PresentationReconcilerRegistry { if (this.outOfSync) { sync(); } - List<IPresentationReconciler> res = new ArrayList<>(); - for (PresentationReconcilerExtension ext : this.extensions.values()) { - if (contentTypes.contains(ext.targetContentType)) { - res.add(ext.createDelegate()); - } - } - return res; + return this.extensions.values().stream() + .filter(ext -> contentTypes.contains(ext.targetContentType)) + .sorted(new ContentTypeSpecializationComparator<IPresentationReconciler>()) + .map(GenericContentTypeRelatedExtension<IPresentationReconciler>::createDelegate) + .collect(Collectors.toList()); } private void sync() { @@ -105,7 +76,7 @@ public class PresentationReconcilerRegistry { toRemoveExtensions.remove(extension); if (!this.extensions.containsKey(extension)) { try { - this.extensions.put(extension, new PresentationReconcilerExtension(extension)); + this.extensions.put(extension, new GenericContentTypeRelatedExtension<IPresentationReconciler>(extension)); } catch (Exception ex) { GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, ex.getMessage(), ex)); } diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ReconcilerRegistry.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ReconcilerRegistry.java index c942335a0dc..28d1f39f751 100644 --- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ReconcilerRegistry.java +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ReconcilerRegistry.java @@ -10,14 +10,13 @@ *******************************************************************************/ package org.eclipse.ui.internal.genericeditor; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IRegistryChangeEvent; import org.eclipse.core.runtime.IRegistryChangeListener; @@ -38,34 +37,7 @@ public class ReconcilerRegistry { private static final String EXTENSION_POINT_ID = GenericEditorPlugin.BUNDLE_ID + ".reconcilers"; //$NON-NLS-1$ - /** - * This class wraps and proxies an {@link IReconciler} provided through extensions - * and loads it lazily when it can contribute to the editor, then delegates all operations to - * actual reconcilier. - */ - private static class ReconcilerExtension { - private static final String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$ - private static final String CONTENT_TYPE_ATTRIBUTE = "contentType"; //$NON-NLS-1$ - - private IConfigurationElement extension; - private IContentType targetContentType; - - private ReconcilerExtension(IConfigurationElement element) throws Exception { - this.extension = element; - this.targetContentType = Platform.getContentTypeManager().getContentType(element.getAttribute(CONTENT_TYPE_ATTRIBUTE)); - } - - public IReconciler createDelegate() { - try { - return (IReconciler) extension.createExecutableExtension(CLASS_ATTRIBUTE); - } catch (CoreException e) { - GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, e.getMessage(), e)); - } - return null; - } - - } - private Map<IConfigurationElement, ReconcilerExtension> extensions = new HashMap<>(); + private Map<IConfigurationElement, GenericContentTypeRelatedExtension<IReconciler>> extensions = new HashMap<>(); private boolean outOfSync = true; /** @@ -91,13 +63,11 @@ public class ReconcilerRegistry { if (this.outOfSync) { sync(); } - List<IReconciler> res = new ArrayList<>(); - for (ReconcilerExtension ext : this.extensions.values()) { - if (contentTypes.contains(ext.targetContentType)) { - res.add(ext.createDelegate()); - } - } - return res; + return this.extensions.values().stream() + .filter(ext -> contentTypes.contains(ext.targetContentType)) + .sorted(new ContentTypeSpecializationComparator<IReconciler>()) + .map(GenericContentTypeRelatedExtension<IReconciler>::createDelegate) + .collect(Collectors.toList()); } private void sync() { @@ -106,7 +76,7 @@ public class ReconcilerRegistry { toRemoveExtensions.remove(extension); if (!this.extensions.containsKey(extension)) { try { - this.extensions.put(extension, new ReconcilerExtension(extension)); + this.extensions.put(extension, new GenericContentTypeRelatedExtension<IReconciler>(extension)); } catch (Exception ex) { GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, ex.getMessage(), ex)); } diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/TextHoverRegistry.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/TextHoverRegistry.java index 0e572876762..374c066eccc 100644 --- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/TextHoverRegistry.java +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/TextHoverRegistry.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Red Hat Inc. and others. + * Copyright (c) 2016-2017 Red Hat Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,7 +10,6 @@ *******************************************************************************/ package org.eclipse.ui.internal.genericeditor; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -21,7 +20,6 @@ import java.util.TreeSet; import java.util.function.Function; import java.util.stream.Collectors; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IRegistryChangeEvent; import org.eclipse.core.runtime.IRegistryChangeListener; @@ -47,36 +45,22 @@ public final class TextHoverRegistry { private SortedSet<TextHoverExtension> extensions; private boolean outOfSync = true; - static class TextHoverExtension { - private static final String CONTENT_TYPE_ATTRIBUTE = "contentType"; //$NON-NLS-1$ - private static final String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$ + static class TextHoverExtension extends GenericContentTypeRelatedExtension<ITextHover> { private static final String ID_ATTRIBUTE = "id"; //$NON-NLS-1$ private static final String IS_BEFORE_ATTRIBUTE = "isBefore"; //$NON-NLS-1$ private static final String IS_AFTER_ATTRIBUTE = "isAfter"; //$NON-NLS-1$ - private IConfigurationElement extension; - private IContentType targetContentType; private String id; private String isBefore; private String isAfter; public TextHoverExtension(IConfigurationElement extension) throws Exception { - this.extension = extension; - this.targetContentType = Platform.getContentTypeManager().getContentType(extension.getAttribute(CONTENT_TYPE_ATTRIBUTE)); + super(extension); this.id = extension.getAttribute(ID_ATTRIBUTE); this.isBefore = extension.getAttribute(IS_BEFORE_ATTRIBUTE); this.isAfter = extension.getAttribute(IS_AFTER_ATTRIBUTE); } - public ITextHover createDelegate() { - try { - return (ITextHover) extension.createExecutableExtension(CLASS_ATTRIBUTE); - } catch (CoreException e) { - GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, e.getMessage(), e)); - } - return null; - } - public String getId() { if (this.id != null) { return this.id; @@ -110,14 +94,13 @@ public final class TextHoverRegistry { if (this.outOfSync) { sync(); } - List<TextHoverExtension> hoversToConsider = new ArrayList<>(); - for (TextHoverExtension ext : this.extensions) { - if (contentTypes.contains(ext.targetContentType)) { - hoversToConsider.add(ext); - } - } + List<ITextHover> hoversToConsider = this.extensions.stream() + .filter(ext -> contentTypes.contains(ext.targetContentType)) + // don't sort in the stream as the initial structure is already sorted by isAfter/isBefore + .map(GenericContentTypeRelatedExtension<ITextHover>::createDelegate) + .collect(Collectors.toList()); if (!hoversToConsider.isEmpty()) { - return new CompositeTextHover(hoversToConsider.stream().map(TextHoverExtension::createDelegate).collect(Collectors.toList())); + return new CompositeTextHover(hoversToConsider); } return null; } |