diff --git a/org.eclipse.ui.genericeditor/META-INF/MANIFEST.MF b/org.eclipse.ui.genericeditor/META-INF/MANIFEST.MF
index aeaf84dd6..3d7c32cc3 100644
--- a/org.eclipse.ui.genericeditor/META-INF/MANIFEST.MF
+++ b/org.eclipse.ui.genericeditor/META-INF/MANIFEST.MF
@@ -16,11 +16,14 @@ Require-Bundle: org.eclipse.ui.workbench.texteditor;bundle-version="3.10.0",
org.eclipse.core.resources;bundle-version="3.11.0",
org.eclipse.core.expressions;bundle-version="3.6.0",
org.eclipse.compare;resolution:=optional
-Export-Package: org.eclipse.ui.internal.genericeditor;x-internal:=true,
+Export-Package: org.eclipse.core.resources.proposed,
+ org.eclipse.jface.text.proposed,
+ org.eclipse.ui.internal.genericeditor;x-internal:=true,
+ org.eclipse.ui.internal.genericeditor.compare;x-internal:=true,
org.eclipse.ui.internal.genericeditor.hover;x-internal:=true,
org.eclipse.ui.internal.genericeditor.markers;x-internal:=true,
org.eclipse.ui.internal.genericeditor.preferences;x-internal:=true,
- org.eclipse.ui.internal.genericeditor.compare;x-internal:=true
+ org.eclipse.ui.texteditor.proposed
Bundle-Activator: org.eclipse.ui.internal.genericeditor.GenericEditorPlugin
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
diff --git a/org.eclipse.ui.genericeditor/plugin.xml b/org.eclipse.ui.genericeditor/plugin.xml
index 9a8755e5f..fac1f2291 100644
--- a/org.eclipse.ui.genericeditor/plugin.xml
+++ b/org.eclipse.ui.genericeditor/plugin.xml
@@ -26,6 +26,7 @@
+
+
+
+
+
+
+
+
+ This extension point is used to contribute reconcilers for controlling the presentation on a file with a given content type.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a fully qualified identifier of the target extension point
+
+
+
+
+
+
+ an optional identifier of the extension instance
+
+
+
+
+
+
+ an optional name of the extension instance
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The fully qualified class name implementing the interface <code>org.eclipse.jface.text.reconciler.IReconciler</code>
+
+
+
+
+
+
+
+
+
+ The target content-type for this extension. Content-types are defined as extension to the org.eclipse.core.contenttype.contentTypes extension point.
+
+
+
+
+
+
+
+
+
+
+
+
+ A core Expression that controls the enabled of the given reconciler. The viewer, editor, and editor input are registered in the evaluation context as variable:
+
+ * <with variable="viewer"/> : use it if your expression requires the viewer.
+ * <with variable="document"/> : use it if your expression requires the document.
+ * <with variable="editor"/> : use it if your expression requires the editor (deprecated, not always set).
+ * <with variable="editorInput"/> : use it if your expression requires the editor input (deprecated, not always set).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1.1
+
+
+
+
+
+
+
+
+ Below is an example of how to use the Reconciler extension point:
+
+<pre>
+<extension point="org.eclipse.ui.genericeditor.reconcilers">
+ <reconciler
+ class="org.eclipse.ui.genericeditor.examples.TargetDefinitionReconciler"
+ contentType="org.eclipse.pde.targetFile">
+ <enabledWhen>
+ <with variable="editor">
+ <test property="org.eclipse.ui.genericeditor.examples.TargetDefinitionPropertyTester">
+ </test>
+ </with>
+ </enabledWhen>
+ </reconciler>
+</extension>
+</pre>
+
+
+
+
+
+
+
+
+
+
+ Copyright (c) 2017 Red Hat Inc. and others
+
+This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-v20.html</a>/
+
+SPDX-License-Identifier: EPL-2.0
+
+
+
+
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/core/resources/proposed/IPreferenceStoreProvider.java b/org.eclipse.ui.genericeditor/src/org/eclipse/core/resources/proposed/IPreferenceStoreProvider.java
new file mode 100644
index 000000000..a09acc1f6
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/core/resources/proposed/IPreferenceStoreProvider.java
@@ -0,0 +1,9 @@
+package org.eclipse.core.resources.proposed;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+public interface IPreferenceStoreProvider {
+
+ IPreferenceStore getPreferenceStore(IResource resource);
+}
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/core/resources/proposed/PreferenceStoreMapping.java b/org.eclipse.ui.genericeditor/src/org/eclipse/core/resources/proposed/PreferenceStoreMapping.java
new file mode 100644
index 000000000..a307b7ea0
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/core/resources/proposed/PreferenceStoreMapping.java
@@ -0,0 +1,206 @@
+package org.eclipse.core.resources.proposed;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+
+public class PreferenceStoreMapping implements IPreferenceStore {
+
+ private final IPreferenceStore delegate;
+
+ private final Map mappings;
+ private final Map mappings2;
+
+ public PreferenceStoreMapping(IPreferenceStore delegate) {
+ this.delegate = delegate;
+ this.mappings = new HashMap<>();
+ this.mappings2 = new HashMap<>();
+ }
+
+ public PreferenceStoreMapping addMapping(String name1, String name2) {
+ mappings.put(name1, name2);
+ mappings2.put(name2, name1);
+ return this;
+ }
+
+ private String getProperName(String name) {
+ if (mappings.containsKey(name)) {
+ return mappings.get(name);
+ }
+ return name;
+ }
+
+ @Override
+ public void addPropertyChangeListener(IPropertyChangeListener listener) {
+ delegate.addPropertyChangeListener(listener);
+ }
+
+ @Override
+ public boolean contains(String name) {
+ if (mappings.containsKey(name) || mappings2.containsKey(name)) {
+ return true;
+ }
+ return delegate.contains(getProperName(name));
+ }
+
+ @Override
+ public void firePropertyChangeEvent(String name, Object oldValue, Object newValue) {
+ delegate.firePropertyChangeEvent(name, oldValue, newValue);
+ }
+
+ @Override
+ public boolean getBoolean(String name) {
+ if (mappings2.containsKey(name)) {
+ name = mappings2.get(name);
+ }
+ return delegate.getBoolean(name);
+ }
+
+ @Override
+ public boolean getDefaultBoolean(String name) {
+ return delegate.getDefaultBoolean(name);
+ }
+
+ @Override
+ public double getDefaultDouble(String name) {
+ return delegate.getDefaultDouble(getProperName(name));
+ }
+
+ @Override
+ public float getDefaultFloat(String name) {
+ return delegate.getDefaultFloat(getProperName(name));
+ }
+
+ @Override
+ public int getDefaultInt(String name) {
+ return delegate.getDefaultInt(getProperName(name));
+ }
+
+ @Override
+ public long getDefaultLong(String name) {
+ return delegate.getDefaultLong(getProperName(name));
+ }
+
+ @Override
+ public String getDefaultString(String name) {
+ return delegate.getDefaultString(getProperName(name));
+ }
+
+ @Override
+ public double getDouble(String name) {
+ return delegate.getDouble(getProperName(name));
+ }
+
+ @Override
+ public float getFloat(String name) {
+ return delegate.getFloat(getProperName(name));
+ }
+
+ @Override
+ public int getInt(String name) {
+ return delegate.getInt(getProperName(name));
+ }
+
+ @Override
+ public long getLong(String name) {
+ return delegate.getLong(getProperName(name));
+ }
+
+ @Override
+ public String getString(String name) {
+ return delegate.getString(getProperName(name));
+ }
+
+ @Override
+ public boolean isDefault(String name) {
+ return delegate.isDefault(getProperName(name));
+ }
+
+ @Override
+ public boolean needsSaving() {
+ return delegate.needsSaving();
+ }
+
+ @Override
+ public void putValue(String name, String value) {
+ delegate.putValue(name, value);
+ }
+
+ @Override
+ public void removePropertyChangeListener(IPropertyChangeListener listener) {
+ delegate.removePropertyChangeListener(listener);
+ }
+
+ @Override
+ public void setDefault(String name, double value) {
+ delegate.setDefault(name, value);
+ }
+
+ @Override
+ public void setDefault(String name, float value) {
+ delegate.setDefault(name, value);
+ }
+
+ @Override
+ public void setDefault(String name, int value) {
+ delegate.setDefault(name, value);
+ }
+
+ @Override
+ public void setDefault(String name, long value) {
+ delegate.setDefault(name, value);
+ }
+
+ @Override
+ public void setDefault(String name, String defaultObject) {
+ delegate.setDefault(name, defaultObject);
+ }
+
+ @Override
+ public void setDefault(String name, boolean value) {
+ delegate.setDefault(name, value);
+ }
+
+ @Override
+ public void setToDefault(String name) {
+ delegate.setToDefault(getProperName(name));
+ }
+
+ @Override
+ public void setValue(String name, double value) {
+ delegate.setValue(name, value);
+ }
+
+ @Override
+ public void setValue(String name, float value) {
+ delegate.setValue(name, value);
+ }
+
+ @Override
+ public void setValue(String name, int value) {
+ delegate.setValue(name, value);
+ }
+
+ @Override
+ public void setValue(String name, long value) {
+ delegate.setValue(name, value);
+ }
+
+ @Override
+ public void setValue(String name, String value) {
+ delegate.setValue(getProperName(name), value);
+ }
+
+ @Override
+ public void setValue(String name, boolean value) {
+ boolean oldValue = delegate.getBoolean(name);
+ delegate.setValue(name, value);
+ String mapedName = getProperName(name);
+ if (oldValue != value && !mapedName.equals(name)) {
+ firePropertyChangeEvent(mapedName, oldValue, value);
+ }
+ }
+
+}
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/core/resources/proposed/PreferenceStoreProviderRegistry.java b/org.eclipse.ui.genericeditor/src/org/eclipse/core/resources/proposed/PreferenceStoreProviderRegistry.java
new file mode 100644
index 000000000..b2bd7e0b1
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/core/resources/proposed/PreferenceStoreProviderRegistry.java
@@ -0,0 +1,86 @@
+package org.eclipse.core.resources.proposed;
+
+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.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;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.ui.internal.genericeditor.ContentTypeSpecializationComparator;
+import org.eclipse.ui.internal.genericeditor.GenericContentTypeRelatedExtension;
+import org.eclipse.ui.internal.genericeditor.GenericEditorPlugin;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+/**
+ * A registry of {@link IPreferenceStore} provider provided by extension
+ * org.eclipse.ui.genericeditor.preferenceStoreProviders
. Those
+ * extensions are specific to a given {@link IContentType}.
+ *
+ * @since 1.0
+ */
+public class PreferenceStoreProviderRegistry {
+
+ private static final String EXTENSION_POINT_ID = GenericEditorPlugin.BUNDLE_ID + ".preferenceStoreProviders"; //$NON-NLS-1$
+
+ private Map> extensions = new HashMap<>();
+ private boolean outOfSync = true;
+
+ /**
+ * Creates the registry and binds it to the extension point.
+ */
+ public PreferenceStoreProviderRegistry() {
+ Platform.getExtensionRegistry().addRegistryChangeListener(event -> outOfSync = true, EXTENSION_POINT_ID);
+ }
+
+ /**
+ * Get the contributed {@link IPresentationReconciliers}s that are relevant to
+ * hook on source viewer according to document content types.
+ *
+ * @param sourceViewer the source viewer we're hooking completion to.
+ * @param editor the text editor
+ * @param contentTypes the content types of the document we're editing.
+ * @return the list of {@link IPreferenceStore} contributed for at least one of
+ * the content types.
+ */
+ public List getPreferenceStoreProviders(ISourceViewer sourceViewer, ITextEditor editor,
+ Set contentTypes) {
+ if (this.outOfSync) {
+ sync();
+ }
+ return this.extensions.values().stream().filter(ext -> contentTypes.contains(ext.targetContentType))
+ .filter(ext -> ext.matches(sourceViewer, editor))
+ .sorted(new ContentTypeSpecializationComparator())
+ .map(GenericContentTypeRelatedExtension::createDelegate)
+ .collect(Collectors.toList());
+ }
+
+ private void sync() {
+ Set toRemoveExtensions = new HashSet<>(this.extensions.keySet());
+ for (IConfigurationElement extension : Platform.getExtensionRegistry()
+ .getConfigurationElementsFor(EXTENSION_POINT_ID)) {
+ toRemoveExtensions.remove(extension);
+ if (!this.extensions.containsKey(extension)) {
+ try {
+ this.extensions.put(extension,
+ new GenericContentTypeRelatedExtension(extension));
+ } catch (Exception ex) {
+ GenericEditorPlugin.getDefault().getLog()
+ .log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, ex.getMessage(), ex));
+ }
+ }
+ }
+ for (IConfigurationElement toRemove : toRemoveExtensions) {
+ this.extensions.remove(toRemove);
+ }
+ this.outOfSync = false;
+ }
+
+}
\ No newline at end of file
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/jface/text/proposed/ITextViewerLifecycle.java b/org.eclipse.ui.genericeditor/src/org/eclipse/jface/text/proposed/ITextViewerLifecycle.java
new file mode 100644
index 000000000..634a19c6d
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/jface/text/proposed/ITextViewerLifecycle.java
@@ -0,0 +1,10 @@
+package org.eclipse.jface.text.proposed;
+
+import org.eclipse.jface.text.ITextViewer;
+
+public interface ITextViewerLifecycle {
+
+ void install(ITextViewer viewer);
+
+ void uninstall();
+}
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextEditor.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextEditor.java
index 5cea4e45a..903fe6ffd 100644
--- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextEditor.java
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextEditor.java
@@ -16,14 +16,27 @@
*******************************************************************************/
package org.eclipse.ui.internal.genericeditor;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+import org.eclipse.core.filebuffers.FileBuffers;
+import org.eclipse.core.filebuffers.ITextFileBuffer;
+import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+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;
import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.Region;
@@ -39,10 +52,10 @@
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.editors.text.EditorsUI;
+import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.internal.genericeditor.preferences.GenericEditorPreferenceConstants;
-import org.eclipse.ui.texteditor.ChainedPreferenceStore;
+import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
/**
@@ -64,6 +77,8 @@ public class ExtensionBasedTextEditor extends TextEditor {
private ExtensionBasedTextViewerConfiguration configuration;
private Image contentTypeImage;
private ImageDescriptor contentTypeImageDescripter;
+ private Set resolvedContentTypes;
+ private PreferenceStoreWrapper preferenceStoreWrapper;
/**
*
@@ -165,7 +180,9 @@ else if (stateMask == -1 && activeHyperlinkStateMask != fHyperlinkStateMask)
public void createPartControl(Composite parent) {
super.createPartControl(parent);
ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
-
+ if (preferenceStoreWrapper != null) {
+ preferenceStoreWrapper.install(viewer);
+ }
new ProjectionSupport(viewer, getAnnotationAccess(), getSharedColors()).install();
viewer.doOperation(ProjectionViewer.TOGGLE);
computeImage();
@@ -174,8 +191,8 @@ public void createPartControl(Composite parent) {
@Override
protected void initializeEditor() {
super.initializeEditor();
- setPreferenceStore(new ChainedPreferenceStore(new IPreferenceStore[] {
- GenericEditorPreferenceConstants.getPreferenceStore(), EditorsUI.getPreferenceStore() }));
+ preferenceStoreWrapper = new PreferenceStoreWrapper(this);
+ setPreferenceStore(preferenceStoreWrapper);
}
/**
@@ -188,7 +205,7 @@ protected void initializeEditor() {
*/
private void configureCharacterPairMatcher(ISourceViewer viewer, SourceViewerDecorationSupport support) {
List matchers = GenericEditorPlugin.getDefault().getCharacterPairMatcherRegistry()
- .getCharacterPairMatchers(viewer, this, configuration.getContentTypes(viewer.getDocument()));
+ .getCharacterPairMatchers(viewer, this, getContentTypes(viewer.getDocument()));
if (!matchers.isEmpty()) {
ICharacterPairMatcher matcher = matchers.get(0);
support.setCharacterPairMatcher(matcher);
@@ -204,18 +221,86 @@ public Image getTitleImage() {
private void computeImage() {
contentTypeImageDescripter = GenericEditorPlugin.getDefault().getContentTypeImagesRegistry()
- .getImageDescriptor(getContentTypes());
+ .getImageDescriptor(getContentTypes().toArray(new IContentType[getContentTypes().size()]));
if (contentTypeImageDescripter != null) {
this.contentTypeImage = contentTypeImageDescripter.createImage();
}
}
- private IContentType[] getContentTypes() {
+ Set getContentTypes() {
ISourceViewer sourceViewer = getSourceViewer();
if (sourceViewer != null) {
- return configuration.getContentTypes(sourceViewer.getDocument()).toArray(new IContentType[] {});
+ return getContentTypes(sourceViewer.getDocument());
+ }
+ return Collections.emptySet();
+ }
+
+ public Set getContentTypes(IDocument document) {
+ if (this.resolvedContentTypes != null) {
+ return this.resolvedContentTypes;
+ }
+ return this.resolvedContentTypes = collectContentTypes(document, this);
+ }
+
+ public static Set collectContentTypes(IDocument document, ITextEditor editor) {
+ Set collectedContentTypes = new LinkedHashSet<>();
+ ITextFileBuffer buffer = getCurrentBuffer(document);
+ if (buffer != null) {
+ try {
+ IContentType contentType = buffer.getContentType();
+ if (contentType != null) {
+ collectedContentTypes.add(contentType);
+ }
+ } catch (CoreException ex) {
+ GenericEditorPlugin.getDefault().getLog()
+ .log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, ex.getMessage(), ex));
+ }
}
- return new IContentType[] {};
+ String fileName = getCurrentFileName(editor, buffer);
+ if (fileName != null) {
+ Queue types = new LinkedList<>(
+ Arrays.asList(Platform.getContentTypeManager().findContentTypesFor(fileName)));
+ while (!types.isEmpty()) {
+ IContentType type = types.poll();
+ collectedContentTypes.add(type);
+ IContentType parent = type.getBaseType();
+ if (parent != null) {
+ types.add(parent);
+ }
+ }
+ }
+ return collectedContentTypes;
+ }
+
+ private static ITextFileBuffer getCurrentBuffer(IDocument document) {
+ if (document != null) {
+ return FileBuffers.getTextFileBufferManager().getTextFileBuffer(document);
+ }
+ return null;
+ }
+
+ private static String getCurrentFileName(ITextEditor editor, ITextFileBuffer buffer) {
+ String fileName = editor != null ? editor.getEditorInput().getName() : null;
+ if (fileName == null) {
+ if (buffer != null) {
+ IPath path = buffer.getLocation();
+ if (path != null) {
+ fileName = path.lastSegment();
+ }
+ }
+ }
+ return fileName;
+ }
+
+ ISourceViewer getViewer() {
+ return getSourceViewer();
+ }
+
+ IResource getResource() {
+ if (getEditorInput() instanceof IFileEditorInput) {
+ return (((IFileEditorInput) getEditorInput()).getFile());
+ }
+ return null;
}
@Override
@@ -224,6 +309,10 @@ public void dispose() {
this.contentTypeImage.dispose();
this.contentTypeImage = null;
}
+ if (this.preferenceStoreWrapper != null) {
+ this.preferenceStoreWrapper.uninstall();
+ this.preferenceStoreWrapper = null;
+ }
super.dispose();
}
}
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextViewerConfiguration.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextViewerConfiguration.java
index 2c14aa78c..0d10f185f 100644
--- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextViewerConfiguration.java
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextViewerConfiguration.java
@@ -19,25 +19,15 @@
package org.eclipse.ui.internal.genericeditor;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Queue;
import java.util.Set;
import java.util.stream.Collectors;
-import org.eclipse.core.filebuffers.FileBuffers;
-import org.eclipse.core.filebuffers.ITextFileBuffer;
-import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
-import org.eclipse.core.runtime.IPath;
-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;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.AbstractReusableInformationControlCreator;
@@ -73,7 +63,6 @@
import org.eclipse.ui.internal.genericeditor.hover.CompositeInformationControlCreator;
import org.eclipse.ui.internal.genericeditor.hover.CompositeTextHover;
import org.eclipse.ui.internal.genericeditor.markers.MarkerResoltionQuickAssistProcessor;
-import org.eclipse.ui.texteditor.ITextEditor;
/**
* The configuration of the {@link ExtensionBasedTextEditor}. It registers the
@@ -86,8 +75,7 @@
public final class ExtensionBasedTextViewerConfiguration extends TextSourceViewerConfiguration
implements IDocumentPartitioningListener {
- private ITextEditor editor;
- private Set resolvedContentTypes;
+ private ExtensionBasedTextEditor editor;
private Set fallbackContentTypes = Set.of();
private IDocument document;
@@ -98,66 +86,15 @@ public final class ExtensionBasedTextViewerConfiguration extends TextSourceViewe
* @param editor the editor we're creating.
* @param preferenceStore the preference store.
*/
- public ExtensionBasedTextViewerConfiguration(ITextEditor editor, IPreferenceStore preferenceStore) {
+ public ExtensionBasedTextViewerConfiguration(ExtensionBasedTextEditor editor, IPreferenceStore preferenceStore) {
super(preferenceStore);
this.editor = editor;
}
- public Set getContentTypes(IDocument document) {
- if (this.resolvedContentTypes != null) {
- return this.resolvedContentTypes;
- }
- this.resolvedContentTypes = new LinkedHashSet<>();
- ITextFileBuffer buffer = getCurrentBuffer(document);
- if (buffer != null) {
- try {
- IContentType contentType = buffer.getContentType();
- if (contentType != null) {
- this.resolvedContentTypes.add(contentType);
- }
- } catch (CoreException ex) {
- GenericEditorPlugin.getDefault().getLog()
- .log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, ex.getMessage(), ex));
- }
- }
- String fileName = getCurrentFileName(document);
- if (fileName != null) {
- Queue types = new LinkedList<>(
- Arrays.asList(Platform.getContentTypeManager().findContentTypesFor(fileName)));
- while (!types.isEmpty()) {
- IContentType type = types.poll();
- this.resolvedContentTypes.add(type);
- IContentType parent = type.getBaseType();
- if (parent != null) {
- types.add(parent);
- }
- }
- }
- return this.resolvedContentTypes.isEmpty() ? fallbackContentTypes : resolvedContentTypes;
- }
-
- private static ITextFileBuffer getCurrentBuffer(IDocument document) {
- if (document != null) {
- return FileBuffers.getTextFileBufferManager().getTextFileBuffer(document);
- }
- return null;
- }
-
- private String getCurrentFileName(IDocument document) {
- String fileName = null;
- if (this.editor != null) {
- fileName = editor.getEditorInput().getName();
- }
- if (fileName == null) {
- ITextFileBuffer buffer = getCurrentBuffer(document);
- if (buffer != null) {
- IPath path = buffer.getLocation();
- if (path != null) {
- fileName = path.lastSegment();
- }
- }
- }
- return fileName;
+ private Set getContentTypes(IDocument document) {
+ Set resolvedContentTypes = editor != null ? editor.getContentTypes(document)
+ : Collections.emptySet();
+ return resolvedContentTypes.isEmpty() ? fallbackContentTypes : resolvedContentTypes;
}
@Override
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorContentAssistant.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorContentAssistant.java
index fcd3797a3..9d597b8b0 100644
--- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorContentAssistant.java
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorContentAssistant.java
@@ -74,7 +74,7 @@ public GenericEditorContentAssistant(
setAutoActivationDelay(0);
enableColoredLabels(true);
enableAutoActivation(true);
- enableAutoActivateCompletionOnType(true);
+ // enableAutoActivateCompletionOnType(true);
setInformationControlCreator(new AbstractReusableInformationControlCreator() {
@Override
protected IInformationControl doCreateInformationControl(Shell parent) {
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java
index a3130c721..65d24c11a 100644
--- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java
@@ -14,6 +14,7 @@
*******************************************************************************/
package org.eclipse.ui.internal.genericeditor;
+import org.eclipse.core.resources.proposed.PreferenceStoreProviderRegistry;
import org.eclipse.jface.text.IAutoEditStrategy;
import org.eclipse.jface.text.ITextHover;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
@@ -49,6 +50,7 @@ public class GenericEditorPlugin extends AbstractUIPlugin {
private AutoEditStrategyRegistry autoEditStrategyRegistry;
private CharacterPairMatcherRegistry characterPairMatcherRegistry;
private IconsRegistry editorImagesRegistry;
+ private PreferenceStoreProviderRegistry preferenceStoreRegistry;
private IPropertyChangeListener themeListener;
@@ -172,4 +174,11 @@ public synchronized IconsRegistry getContentTypeImagesRegistry() {
}
return this.editorImagesRegistry;
}
+
+ public synchronized PreferenceStoreProviderRegistry getPreferenceStoreRegistry() {
+ if (this.preferenceStoreRegistry == null) {
+ this.preferenceStoreRegistry = new PreferenceStoreProviderRegistry();
+ }
+ return preferenceStoreRegistry;
+ }
}
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/IconsRegistry.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/IconsRegistry.java
index d5909b9a6..59e2e60ad 100644
--- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/IconsRegistry.java
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/IconsRegistry.java
@@ -43,14 +43,18 @@ public ImageDescriptor getImageDescriptor(IContentType[] contentTypes) {
if (this.outOfSync) {
sync();
}
- return Arrays.stream(contentTypes).sorted(Collections.reverseOrder(Comparator.comparingInt(ContentTypeSpecializationComparator::depth))).map(extensions::get).filter(Objects::nonNull).findFirst().orElse(null);
+ return Arrays.stream(contentTypes)
+ .sorted(Collections.reverseOrder(Comparator.comparingInt(ContentTypeSpecializationComparator::depth)))
+ .map(extensions::get).filter(Objects::nonNull).findFirst().orElse(null);
}
private void sync() {
Set toRemoveContentTypes = new HashSet<>(this.extensions.keySet());
- for (IConfigurationElement extension : Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID)) {
+ for (IConfigurationElement extension : Platform.getExtensionRegistry()
+ .getConfigurationElementsFor(EXTENSION_POINT_ID)) {
try {
- final String contentTypeId = extension.getAttribute(GenericContentTypeRelatedExtension.CONTENT_TYPE_ATTRIBUTE);
+ final String contentTypeId = extension
+ .getAttribute(GenericContentTypeRelatedExtension.CONTENT_TYPE_ATTRIBUTE);
if (contentTypeId == null || contentTypeId.isEmpty()) {
continue;
}
@@ -65,10 +69,12 @@ private void sync() {
if (icon == null || icon.isEmpty()) {
continue;
}
- ResourceLocator.imageDescriptorFromBundle(extension.getNamespaceIdentifier(), icon).ifPresent(imageDescriptor -> this.extensions.put(contentType, imageDescriptor));
+ ResourceLocator.imageDescriptorFromBundle(extension.getNamespaceIdentifier(), icon)
+ .ifPresent(imageDescriptor -> this.extensions.put(contentType, imageDescriptor));
}
} catch (Exception ex) {
- GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, ex.getMessage(), 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/PreferenceStoreWrapper.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/PreferenceStoreWrapper.java
new file mode 100644
index 000000000..52259febd
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/PreferenceStoreWrapper.java
@@ -0,0 +1,302 @@
+package org.eclipse.ui.internal.genericeditor;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.proposed.IPreferenceStoreProvider;
+import org.eclipse.core.resources.proposed.PreferenceStoreProviderRegistry;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.proposed.ITextViewerLifecycle;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.ui.editors.text.EditorsUI;
+import org.eclipse.ui.internal.genericeditor.preferences.GenericEditorPreferenceConstants;
+import org.eclipse.ui.texteditor.ChainedPreferenceStore;
+import org.eclipse.ui.texteditor.proposed.ITextEditorAware;
+
+public class PreferenceStoreWrapper implements IPreferenceStore, ITextViewerLifecycle {
+
+ private IPreferenceStore delegate;
+ private boolean computed;
+
+ private ExtensionBasedTextEditor editor;
+ private Set listeners = new HashSet<>();
+ private ITextViewer viewer;
+ private List customPreferenceStore;
+
+ public PreferenceStoreWrapper(ExtensionBasedTextEditor editor) {
+ this.editor = editor;
+ this.delegate = createPreferenceStore(null, null);
+ }
+
+ public static IPreferenceStore createPreferenceStore(Set contentTypes,
+ ExtensionBasedTextEditor editor) {
+ List customStores = collectCustomPreferenceStore(contentTypes, editor);
+ return createPreferenceStore(customStores);
+ }
+
+ private static IPreferenceStore createPreferenceStore(List customStores) {
+ List stores = new ArrayList<>();
+ if (customStores != null) {
+ stores.addAll(customStores);
+ }
+ stores.add(GenericEditorPreferenceConstants.getPreferenceStore());
+ stores.add(EditorsUI.getPreferenceStore());
+ return new ChainedPreferenceStore(stores.toArray(new IPreferenceStore[stores.size()]));
+ }
+
+ public static List collectCustomPreferenceStore(Set contentTypes,
+ ExtensionBasedTextEditor editor) {
+ if (contentTypes != null && editor != null) {
+ PreferenceStoreProviderRegistry registry = GenericEditorPlugin.getDefault().getPreferenceStoreRegistry();
+ List providers = registry.getPreferenceStoreProviders(editor.getViewer(), editor,
+ contentTypes);
+ List stores = new ArrayList<>();
+ for (IPreferenceStoreProvider provider : providers) {
+ IPreferenceStore editorStore = provider.getPreferenceStore(editor.getResource());
+ if (editorStore != null) {
+ if (editorStore instanceof ITextEditorAware) {
+ ((ITextEditorAware) editorStore).setEditor(editor);
+ }
+ stores.add(editorStore);
+ }
+ }
+ return stores;
+ }
+ return null;
+ }
+
+ @Override
+ public void addPropertyChangeListener(IPropertyChangeListener arg0) {
+ listeners.add(arg0);
+ if (delegate != null) {
+ getDelegate().addPropertyChangeListener(arg0);
+ }
+ }
+
+ @Override
+ public boolean contains(String arg0) {
+ return getDelegate().contains(arg0);
+ }
+
+ @Override
+ public void firePropertyChangeEvent(String arg0, Object arg1, Object arg2) {
+ getDelegate().firePropertyChangeEvent(arg0, arg1, arg2);
+ }
+
+ @Override
+ public boolean getBoolean(String arg0) {
+ return getDelegate().getBoolean(arg0);
+ }
+
+ @Override
+ public boolean getDefaultBoolean(String arg0) {
+ return getDelegate().getDefaultBoolean(arg0);
+ }
+
+ @Override
+ public double getDefaultDouble(String arg0) {
+ return getDelegate().getDefaultDouble(arg0);
+ }
+
+ @Override
+ public float getDefaultFloat(String arg0) {
+ return getDelegate().getDefaultFloat(arg0);
+ }
+
+ @Override
+ public int getDefaultInt(String arg0) {
+ return getDelegate().getDefaultInt(arg0);
+ }
+
+ @Override
+ public long getDefaultLong(String arg0) {
+ return getDelegate().getDefaultLong(arg0);
+ }
+
+ @Override
+ public String getDefaultString(String arg0) {
+ return getDelegate().getDefaultString(arg0);
+ }
+
+ @Override
+ public double getDouble(String arg0) {
+ return getDelegate().getDouble(arg0);
+ }
+
+ @Override
+ public float getFloat(String arg0) {
+ return getDelegate().getFloat(arg0);
+ }
+
+ @Override
+ public int getInt(String arg0) {
+ return getDelegate().getInt(arg0);
+ }
+
+ @Override
+ public long getLong(String arg0) {
+ return getDelegate().getLong(arg0);
+ }
+
+ @Override
+ public String getString(String arg0) {
+ return getDelegate().getString(arg0);
+ }
+
+ @Override
+ public boolean isDefault(String arg0) {
+ return getDelegate().isDefault(arg0);
+ }
+
+ @Override
+ public boolean needsSaving() {
+ return getDelegate().needsSaving();
+ }
+
+ @Override
+ public void putValue(String arg0, String arg1) {
+ getDelegate().putValue(arg0, arg1);
+ }
+
+ @Override
+ public void removePropertyChangeListener(IPropertyChangeListener arg0) {
+ listeners.remove(arg0);
+ getDelegate().removePropertyChangeListener(arg0);
+ }
+
+ @Override
+ public void setDefault(String arg0, boolean arg1) {
+ getDelegate().setDefault(arg0, arg1);
+ }
+
+ @Override
+ public void setDefault(String arg0, double arg1) {
+ getDelegate().setDefault(arg0, arg1);
+ }
+
+ @Override
+ public void setDefault(String arg0, float arg1) {
+ getDelegate().setDefault(arg0, arg1);
+ }
+
+ @Override
+ public void setDefault(String arg0, int arg1) {
+ getDelegate().setDefault(arg0, arg1);
+ }
+
+ @Override
+ public void setDefault(String arg0, long arg1) {
+ getDelegate().setDefault(arg0, arg1);
+ }
+
+ @Override
+ public void setDefault(String arg0, String arg1) {
+ getDelegate().setDefault(arg0, arg1);
+ }
+
+ @Override
+ public void setToDefault(String arg0) {
+ getDelegate().setToDefault(arg0);
+ }
+
+ @Override
+ public void setValue(String arg0, boolean arg1) {
+ getDelegate().setValue(arg0, arg1);
+ }
+
+ @Override
+ public void setValue(String arg0, double arg1) {
+ getDelegate().setValue(arg0, arg1);
+ }
+
+ @Override
+ public void setValue(String arg0, float arg1) {
+ getDelegate().setValue(arg0, arg1);
+ }
+
+ @Override
+ public void setValue(String arg0, int arg1) {
+ getDelegate().setValue(arg0, arg1);
+ }
+
+ @Override
+ public void setValue(String arg0, long arg1) {
+ getDelegate().setValue(arg0, arg1);
+ }
+
+ @Override
+ public void setValue(String arg0, String arg1) {
+ getDelegate().setValue(arg0, arg1);
+ }
+
+ private IPreferenceStore getDelegate() {
+ if (!computed) {
+ delegate = getPreferenceStore();
+ }
+ return delegate;
+ }
+
+ private synchronized IPreferenceStore getPreferenceStore() {
+ if (computed) {
+ return delegate;
+ }
+ IPreferenceStore store = createCustomPreferenceStore();
+ if (store != null) {
+ for (IPropertyChangeListener listener : listeners) {
+ store.addPropertyChangeListener(listener);
+ }
+ for (IPropertyChangeListener listener : listeners) {
+ delegate.removePropertyChangeListener(listener);
+ }
+ delegate = store;
+ computed = true;
+ }
+ return delegate;
+ }
+
+ IPreferenceStore createCustomPreferenceStore() {
+ Set contentTypes = editor.getContentTypes();
+ if (contentTypes == null || contentTypes.isEmpty()) {
+ return null;
+ }
+ customPreferenceStore = collectCustomPreferenceStore(contentTypes, editor);
+ if (customPreferenceStore != null) {
+ installIfNeeded();
+ return createPreferenceStore(customPreferenceStore);
+ }
+ return null;
+ }
+
+ private void installIfNeeded() {
+ if (viewer != null) {
+ for (IPreferenceStore store : customPreferenceStore) {
+ if (store instanceof ITextViewerLifecycle) {
+ ((ITextViewerLifecycle) store).install(viewer);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void install(ITextViewer viewer) {
+ this.viewer = viewer;
+ installIfNeeded();
+ }
+
+ @Override
+ public void uninstall() {
+ if (viewer != null && customPreferenceStore != null) {
+ for (IPreferenceStore store : customPreferenceStore) {
+ if (store instanceof ITextViewerLifecycle) {
+ ((ITextViewerLifecycle) store).uninstall();
+ }
+ }
+ this.customPreferenceStore = null;
+ }
+ this.viewer = null;
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/compare/GenericEditorMergeViewer.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/compare/GenericEditorMergeViewer.java
index c6a384552..7850a380f 100644
--- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/compare/GenericEditorMergeViewer.java
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/compare/GenericEditorMergeViewer.java
@@ -19,17 +19,15 @@
import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.contentmergeviewer.TextMergeViewer;
import org.eclipse.core.runtime.content.IContentType;
-import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextInputListener;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.swt.widgets.Composite;
-import org.eclipse.ui.editors.text.EditorsUI;
+import org.eclipse.ui.internal.genericeditor.ExtensionBasedTextEditor;
import org.eclipse.ui.internal.genericeditor.ExtensionBasedTextViewerConfiguration;
-import org.eclipse.ui.internal.genericeditor.GenericEditorPlugin;
-import org.eclipse.ui.texteditor.ChainedPreferenceStore;
+import org.eclipse.ui.internal.genericeditor.PreferenceStoreWrapper;
public class GenericEditorMergeViewer extends TextMergeViewer {
@@ -45,8 +43,7 @@ protected SourceViewer createSourceViewer(Composite parent, int textOrientation)
res.addTextInputListener(new ITextInputListener() {
@Override
public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
- fallbackContentTypes
- .addAll(new ExtensionBasedTextViewerConfiguration(null, null).getContentTypes(newInput));
+ fallbackContentTypes.addAll(ExtensionBasedTextEditor.collectContentTypes(newInput, null));
configureTextViewer(res);
}
@@ -62,8 +59,8 @@ public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput
protected void configureTextViewer(TextViewer textViewer) {
if (textViewer.getDocument() != null && textViewer instanceof ISourceViewer) {
ExtensionBasedTextViewerConfiguration configuration = new ExtensionBasedTextViewerConfiguration(null,
- new ChainedPreferenceStore(new IPreferenceStore[] { EditorsUI.getPreferenceStore(),
- GenericEditorPlugin.getDefault().getPreferenceStore() }));
+ PreferenceStoreWrapper.createPreferenceStore(
+ ExtensionBasedTextEditor.collectContentTypes(textViewer.getDocument(), null), null));
configuration.setFallbackContentTypes(fallbackContentTypes);
((ISourceViewer) textViewer).configure(configuration);
}
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/texteditor/proposed/ITextEditorAware.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/texteditor/proposed/ITextEditorAware.java
new file mode 100644
index 000000000..f03cebaa2
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/texteditor/proposed/ITextEditorAware.java
@@ -0,0 +1,8 @@
+package org.eclipse.ui.texteditor.proposed;
+
+import org.eclipse.ui.texteditor.ITextEditor;
+
+public interface ITextEditorAware {
+
+ void setEditor(ITextEditor editor);
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java
index 878a579a5..765375329 100644
--- a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java
@@ -6175,6 +6175,10 @@ public T getAdapter(Class required) {
if (ITextViewer.class.equals(required))
return (fSourceViewer == null ? null : (T) fSourceViewer);
+ if (IPreferenceStore.class.equals(required)) {
+ return (T) getPreferenceStore();
+ }
+
return super.getAdapter(required);
}