Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSopot Cela2016-09-26 10:16:25 +0000
committerDani Megert2016-09-26 10:30:36 +0000
commit5bcb7ac5045743f9ec17895a9a12318dd90ea4cb (patch)
treeea2d98cee208a040d2ee43fef458d3775a5dc90d /org.eclipse.ui.genericeditor
parent8871738e5b595e7715499161b04980d9f16df820 (diff)
downloadeclipse.platform.text-5bcb7ac5045743f9ec17895a9a12318dd90ea4cb.tar.gz
eclipse.platform.text-5bcb7ac5045743f9ec17895a9a12318dd90ea4cb.tar.xz
eclipse.platform.text-5bcb7ac5045743f9ec17895a9a12318dd90ea4cb.zip
Bug 497871 - Generic and extensible text editor
This change creates a new extensible text editor, with extension points for: * contentAssist * hover * syntax highlighting Some unit tests show examples of extensions. You can load an IDE with the suggested change (including org.eclipse.ui.editors.tests) and get a syntax highlighter, a hover support and some content assist on the plain text editor. Bug: 497871 Bug: 496117 Bug: 496115 Bug: 496300 Signed-off-by: Mickael Istria <mistria@redhat.com> Signed-off-by: Sopot Cela <scela@redhat.com> Change-Id: I2eec71e4620364aa11c500ec07e54c693863cf44
Diffstat (limited to 'org.eclipse.ui.genericeditor')
-rw-r--r--org.eclipse.ui.genericeditor/.classpath7
-rw-r--r--org.eclipse.ui.genericeditor/.project28
-rw-r--r--org.eclipse.ui.genericeditor/.settings/org.eclipse.jdt.core.prefs7
-rw-r--r--org.eclipse.ui.genericeditor/META-INF/MANIFEST.MF17
-rw-r--r--org.eclipse.ui.genericeditor/build.properties7
-rw-r--r--org.eclipse.ui.genericeditor/icons/full/obj16/geneditor.pngbin0 -> 613 bytes
-rw-r--r--org.eclipse.ui.genericeditor/plugin.properties10
-rw-r--r--org.eclipse.ui.genericeditor/plugin.xml64
-rw-r--r--org.eclipse.ui.genericeditor/pom.xml23
-rw-r--r--org.eclipse.ui.genericeditor/schema/contentAssistProcessors.exsd116
-rw-r--r--org.eclipse.ui.genericeditor/schema/hoverProviders.exsd145
-rw-r--r--org.eclipse.ui.genericeditor/schema/presentationReconcilers.exsd116
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/CompositeContentAssistProcessor.java93
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentAssistProcessorRegistry.java195
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextEditor.java37
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextViewerConfiguration.java98
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java82
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/PresentationReconcilerRegistry.java149
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/TextHoverRegistry.java111
19 files changed, 1305 insertions, 0 deletions
diff --git a/org.eclipse.ui.genericeditor/.classpath b/org.eclipse.ui.genericeditor/.classpath
new file mode 100644
index 00000000000..eca7bdba8f0
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.ui.genericeditor/.project b/org.eclipse.ui.genericeditor/.project
new file mode 100644
index 00000000000..e1f2994e5af
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.ui.genericeditor</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.ui.genericeditor/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.ui.genericeditor/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..0c68a61dca8
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/org.eclipse.ui.genericeditor/META-INF/MANIFEST.MF b/org.eclipse.ui.genericeditor/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..ca7ab11688a
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/META-INF/MANIFEST.MF
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Generic and Extensible Text Editor
+Bundle-SymbolicName: org.eclipse.ui.genericeditor;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.ui.workbench.texteditor;bundle-version="3.10.0",
+ org.eclipse.ui.editors;bundle-version="3.10.0",
+ org.eclipse.ui;bundle-version="3.108.0",
+ org.eclipse.text;bundle-version="3.6.0",
+ org.eclipse.jface.text;bundle-version="3.11.0",
+ org.eclipse.core.runtime;bundle-version="3.12.0"
+Export-Package: org.eclipse.ui.internal.genericeditor;x-internal:=true
+Bundle-Activator: org.eclipse.ui.internal.genericeditor.GenericEditorPlugin
+Bundle-Localization: plugin
+Bundle-ActivationPolicy: lazy
diff --git a/org.eclipse.ui.genericeditor/build.properties b/org.eclipse.ui.genericeditor/build.properties
new file mode 100644
index 00000000000..bef8e620327
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/build.properties
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ plugin.properties,\
+ icons/
diff --git a/org.eclipse.ui.genericeditor/icons/full/obj16/geneditor.png b/org.eclipse.ui.genericeditor/icons/full/obj16/geneditor.png
new file mode 100644
index 00000000000..25b7217874f
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/icons/full/obj16/geneditor.png
Binary files differ
diff --git a/org.eclipse.ui.genericeditor/plugin.properties b/org.eclipse.ui.genericeditor/plugin.properties
new file mode 100644
index 00000000000..b6a2e26f60c
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/plugin.properties
@@ -0,0 +1,10 @@
+genericEditor_name=Generic Text Editor
+ExtPoint.presentationReconciliers=Presentation Reconciliers
+ExtPoint.hoverProvider= Hover Providers
+ExtPoint.contentAssistProcessors=Content Assist Providers
+openDeclarationCommand_name=Open Declaration
+openDeclarationCommand_name=Open Declaration for selected element
+context_name=in Generic Code Editor
+context_description=When editing in the Generic Code Editor
+findReferencesCommand_name=Find References
+findReferencesCommand_description=Find other code items referencing the current selected item. \ No newline at end of file
diff --git a/org.eclipse.ui.genericeditor/plugin.xml b/org.eclipse.ui.genericeditor/plugin.xml
new file mode 100644
index 00000000000..dba3b9ab914
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/plugin.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension-point id="presentationReconcilers" name="%ExtPoint.presentationReconciliers" schema="schema/presentationReconcilers.exsd"/>
+ <extension-point id="contentAssistProcessors" name="%ExtPoint.contentAssistProcessors" schema="schema/contentAssistProcessors.exsd"/>
+ <extension-point id="hoverProviders" name="%ExtPoint.hoverProviders" schema="schema/hoverProviders.exsd"/>
+ <extension
+ point="org.eclipse.ui.editors">
+ <editor
+ class="org.eclipse.ui.internal.genericeditor.ExtensionBasedTextEditor"
+ default="false"
+ icon="icons/full/obj16/geneditor.png"
+ id="org.eclipse.ui.genericeditor.GenericEditor"
+ name="%genericEditor_name">
+ <contentTypeBinding
+ contentTypeId="org.eclipse.core.runtime.text">
+ </contentTypeBinding>
+ </editor>
+ </extension>
+ <extension
+ point="org.eclipse.ui.commands">
+ <command
+ description="%findReferencesCommand_description"
+ id="org.eclipse.ui.genericeditor.findReferences"
+ name="%findReferencesCommand_name">
+ </command>
+ </extension>
+ <extension
+ point="org.eclipse.ui.contexts">
+ <context
+ description="%context_description"
+ id="org.eclipse.ui.genericeditor.genericEditorContext"
+ name="%context_name"
+ parentId="org.eclipse.ui.textEditorScope">
+ </context>
+ </extension>
+ <extension
+ point="org.eclipse.ui.bindings">
+ <key
+ commandId="org.eclipse.ui.edit.text.open.hyperlink"
+ contextId="org.eclipse.ui.genericeditor.genericEditorContext"
+ schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
+ sequence="F3">
+ </key>
+ <key
+ commandId="org.eclipse.ui.genericeditor.findReferences"
+ contextId="org.eclipse.ui.genericeditor.genericEditorContext"
+ schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
+ sequence="M1+M2+G">
+ </key>
+ </extension>
+ <extension
+ point="org.eclipse.ui.menus">
+ <menuContribution
+ allPopups="true"
+ locationURI="popup:#TextEditorContext?after=additions">
+ <command
+ commandId="org.eclipse.ui.genericeditor.findReferences"
+ style="push">
+ </command>
+ </menuContribution>
+ </extension>
+
+</plugin>
diff --git a/org.eclipse.ui.genericeditor/pom.xml b/org.eclipse.ui.genericeditor/pom.xml
new file mode 100644
index 00000000000..df83a530d13
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/pom.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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 Distribution License v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/org/documents/edl-v10.php
+
+ Contributors:
+ Mickael Istria (Red Hat Inc.) - initial implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>eclipse.platform.text</artifactId>
+ <groupId>eclipse.platform.text</groupId>
+ <version>4.7.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.eclipse.ui</groupId>
+ <artifactId>org.eclipse.ui.genericeditor</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+</project>
diff --git a/org.eclipse.ui.genericeditor/schema/contentAssistProcessors.exsd b/org.eclipse.ui.genericeditor/schema/contentAssistProcessors.exsd
new file mode 100644
index 00000000000..441b85ab13f
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/schema/contentAssistProcessors.exsd
@@ -0,0 +1,116 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.ui.genericeditor" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.ui.genericeditor" id="contentAssistProcessors" name="Content assist processors"/>
+ </appinfo>
+ <documentation>
+ This extension point is used to contribute content assist processors for adding content assist support to a given content type.
+ </documentation>
+ </annotation>
+
+ <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence minOccurs="1" maxOccurs="unbounded">
+ <element ref="contentAssistProcessor"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+ a fully qualified identifier of the target extension point
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+ an optional identifier of the extension instance
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+ an optional name of the extension instance
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="contentAssistProcessor">
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ The fully qualified class name implementing the interface &lt;code&gt;org.eclipse.jface.text.contentassist.IContentAssistProcessor&lt;/code&gt;
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.jface.text.contentassist.IContentAssistProcessor"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="contentType" type="string" use="required">
+ <annotation>
+ <documentation>
+ The target content-type for this extension. Content-types are defined as extension to the org.eclipse.core.contenttype.contentTypes extension point.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.core.contenttype.contentTypes/content-type/@id"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 1.0
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ This is an example of a processor being registered for a target definition file type:
+
+&lt;pre&gt;
+&lt;extension point=&quot;org.eclipse.ui.genericeditor.contentAssistProcessors&quot;&gt;
+ &lt;contentAssistProcessor
+ class=&quot;org.eclipse.ui.genericeditor.examples.TargedDefinitionContentAssist&quot;
+ contentType=&quot;org.eclipse.pde.targetFile&quot;&gt;
+ &lt;/contentAssistProcessor&gt;
+&lt;/extension&gt;
+&lt;/pre&gt;
+ </documentation>
+ </annotation>
+
+
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ 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 &lt;a href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/org.eclipse.ui.genericeditor/schema/hoverProviders.exsd b/org.eclipse.ui.genericeditor/schema/hoverProviders.exsd
new file mode 100644
index 00000000000..ac475e82af3
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/schema/hoverProviders.exsd
@@ -0,0 +1,145 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.ui.genericeditor" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.ui.genericeditor" id="hoverProviders" name="Hover providers"/>
+ </appinfo>
+ <documentation>
+ This extension point is used to contribute hover providers for showing text hovers in a file with a given content type.
+ </documentation>
+ </annotation>
+
+ <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="hoverProvider" minOccurs="1" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+ a fully qualified identifier of the target extension point
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+ an optional identifier of the extension instance
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+ an optional name of the extension instance
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="hoverProvider">
+ <complexType>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+ A string uniquely identifying this reference provider.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ The fully qualified class name implementing the interface &lt;code&gt;org.eclipse.jface.text.ITextHover&lt;/code&gt;
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.jface.text.ITextHover"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="contentType" type="string" use="required">
+ <annotation>
+ <documentation>
+ The target content-type for this extension. Content-types are defined as extension to the org.eclipse.core.contenttype.contentTypes extension point.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.core.contenttype.contentTypes/content-type/@id"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="before" type="string">
+ <annotation>
+ <documentation>
+ The id of a hoverProvider before which to place this contribution.
+Plan is to have contributions are sorted according to that value and to have only the first one shown (or the the first &quot;compoundable&quot; ones)
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.ui.genericeditor.hoverProviders/hoverProvider/@id"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="after" type="string">
+ <annotation>
+ <documentation>
+ The id of a hoverProvider after which to place this contribution.
+Plan is to have contributions are sorted according to that value and to have only the first one shown (or the the first &quot;compoundable&quot; ones)
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.ui.genericeditor.hoverProviders/hoverProvider/@id"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 1.0
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ Below is an example using the hover provider extension point:
+
+&lt;pre&gt;
+&lt;extension point=&quot;org.eclipse.ui.genericeditor.hoverProviders&quot;&gt;
+ &lt;hoverProvider
+ class=&quot;org.eclipse.ui.genericeditor.tests.contributions.MagicHoverProvider&quot;
+ contentType=&quot;org.eclipse.core.runtime.text&quot;&gt;
+ &lt;/hoverProvider&gt;
+&lt;/extension&gt;
+&lt;/pre&gt;
+ </documentation>
+ </annotation>
+
+
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ 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 &lt;a href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/org.eclipse.ui.genericeditor/schema/presentationReconcilers.exsd b/org.eclipse.ui.genericeditor/schema/presentationReconcilers.exsd
new file mode 100644
index 00000000000..17aca3a3506
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/schema/presentationReconcilers.exsd
@@ -0,0 +1,116 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.ui.genericeditor" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.ui.genericeditor" id="presentationReconcilers" name="Presentation reconcilers"/>
+ </appinfo>
+ <documentation>
+ This extension point is used to contribute presentation reconcilers for controlling the presentation on a file with a given content type.
+ </documentation>
+ </annotation>
+
+ <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence minOccurs="1" maxOccurs="unbounded">
+ <element ref="presentationReconciler"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+ a fully qualified identifier of the target extension point
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+ an optional identifier of the extension instance
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+ an optional name of the extension instance
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="presentationReconciler">
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ The fully qualified class name implementing the interface &lt;code&gt;org.eclipse.jface.text.presentation.IPresentationReconciler&lt;/code&gt;
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.jface.text.presentation.IPresentationReconciler"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="contentType" type="string" use="required">
+ <annotation>
+ <documentation>
+ The target content-type for this extension. Content-types are defined as extension to the org.eclipse.core.contenttype.contentTypes extension point.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.core.contenttype.contentTypes/content-type/@id"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 1.0
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ Below is an example of how to use the Presentation Reconciler extension point:
+
+&lt;pre&gt;
+&lt;extension point=&quot;org.eclipse.ui.genericeditor.presentationReconcilers&quot;&gt;
+ &lt;presentationReconciler
+ class=&quot;org.eclipse.ui.genericeditor.examples.TPPresentationReconciler&quot;
+ contentType=&quot;org.eclipse.pde.targetFile&quot;&gt;
+ &lt;/presentationReconciler&gt;
+&lt;/extension&gt;
+&lt;/pre&gt;
+ </documentation>
+ </annotation>
+
+
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ 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 &lt;a href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/CompositeContentAssistProcessor.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/CompositeContentAssistProcessor.java
new file mode 100644
index 00000000000..d4d64acee51
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/CompositeContentAssistProcessor.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * 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:
+ * - Mickael Istria (Red Hat Inc.)
+ *******************************************************************************/
+package org.eclipse.ui.internal.genericeditor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.jface.text.contentassist.IContextInformationValidator;
+
+/**
+ * A content assist processor that delegates all content assist
+ * operations to children provided in constructor and aggregates
+ * the results.
+ *
+ * @since 1.0
+ */
+public class CompositeContentAssistProcessor implements IContentAssistProcessor {
+
+ private List<IContentAssistProcessor> fContentAssistProcessors;
+
+ /**
+ * Constructor
+ * @param contentAssistProcessors the children that will actually populate the output
+ * of this content assist processor.
+ */
+ public CompositeContentAssistProcessor(List<IContentAssistProcessor> contentAssistProcessors) {
+ fContentAssistProcessors= contentAssistProcessors;
+ }
+
+ @Override
+ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
+ List<ICompletionProposal> res = new ArrayList<>();
+ for (IContentAssistProcessor processor : this.fContentAssistProcessors) {
+ res.addAll(Arrays.asList(processor.computeCompletionProposals(viewer, offset)));
+ }
+ return res.toArray(new ICompletionProposal[res.size()]);
+ }
+
+ @Override
+ public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
+ List<IContextInformation> res = new ArrayList<>();
+ for (IContentAssistProcessor processor : this.fContentAssistProcessors) {
+ res.addAll(Arrays.asList(processor.computeContextInformation(viewer, offset)));
+ }
+ return res.toArray(new IContextInformation[res.size()]);
+ }
+
+ @Override
+ public char[] getCompletionProposalAutoActivationCharacters() {
+ return null;
+ }
+
+ @Override
+ public char[] getContextInformationAutoActivationCharacters() {
+ return null;
+ }
+
+ @Override
+ public String getErrorMessage() {
+ StringBuilder res = new StringBuilder();
+ for (IContentAssistProcessor processor : this.fContentAssistProcessors) {
+ String errorMessage = processor.getErrorMessage();
+ if (errorMessage != null) {
+ res.append(errorMessage);
+ res.append('\n');
+ }
+ }
+ if (res.length() == 0) {
+ return null;
+ } else {
+ return res.toString();
+ }
+ }
+
+ @Override
+ public IContextInformationValidator getContextInformationValidator() {
+ return null;
+ }
+
+} \ No newline at end of file
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
new file mode 100644
index 00000000000..a81cecbf8f0
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ContentAssistProcessorRegistry.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * 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:
+ * - Mickael Istria (Red Hat Inc.)
+ *******************************************************************************/
+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 org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.IRegistryChangeListener;
+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.core.runtime.content.IContentTypeManager;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.jface.text.contentassist.IContextInformationValidator;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * A registry of content assist processors provided by extension <code>org.eclipse.ui.genericeditor.contentAssistProcessors</code>.
+ * Those extensions are specific to a given {@link IContentType}.
+ *
+ * @since 1.0
+ */
+public class ContentAssistProcessorRegistry {
+
+ private static final String EXTENSION_POINT_ID = GenericEditorPlugin.BUNDLE_ID + ".contentAssistProcessors"; //$NON-NLS-1$
+
+ /**
+ * 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 implements IContentAssistProcessor {
+ 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 IContentAssistProcessor delegate;
+
+ private ContentAssistProcessorExtension(IConfigurationElement element) throws Exception {
+ this.extension = element;
+ this.targetContentType = Platform.getContentTypeManager().getContentType(element.getAttribute(CONTENT_TYPE_ATTRIBUTE));
+ }
+
+ private IContentAssistProcessor getDelegate() {
+ if (this.delegate == null) {
+ try {
+ this.delegate = (IContentAssistProcessor) extension.createExecutableExtension(CLASS_ATTRIBUTE);
+ } catch (CoreException e) {
+ e.printStackTrace();
+ }
+ }
+ return delegate;
+ }
+
+ /**
+ * @return whether the referenced contribution should contribute to the current editor.
+ */
+ public boolean isActive() {
+ IEditorInput input = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor().getEditorInput();
+ IContentTypeManager contentTypeManager= Platform.getContentTypeManager();
+ for (IContentType currentContentType : contentTypeManager.findContentTypesFor(input.getName())) {
+ if (currentContentType.isKindOf(targetContentType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
+ if (isActive()) {
+ return getDelegate().computeCompletionProposals(viewer, offset);
+ }
+ return new ICompletionProposal[0];
+ }
+
+ @Override
+ public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
+ if (isActive()) {
+ return getDelegate().computeContextInformation(viewer, offset);
+ }
+ return new IContextInformation[0];
+ }
+
+ @Override
+ public char[] getCompletionProposalAutoActivationCharacters() {
+ if (isActive()) {
+ return getDelegate().getCompletionProposalAutoActivationCharacters();
+ }
+ return null;
+ }
+
+ @Override
+ public char[] getContextInformationAutoActivationCharacters() {
+ if (isActive()) {
+ return getDelegate().getContextInformationAutoActivationCharacters();
+ }
+ return null;
+ }
+
+ @Override
+ public String getErrorMessage() {
+ if (isActive()) {
+ return getDelegate().getErrorMessage();
+ }
+ return null;
+ }
+
+ @Override
+ public IContextInformationValidator getContextInformationValidator() {
+ if (isActive()) {
+ return getDelegate().getContextInformationValidator();
+ }
+ return null;
+ }
+ }
+
+ private Map<IConfigurationElement, ContentAssistProcessorExtension> extensions = new HashMap<>();
+ private boolean outOfSync = true;
+
+ /**
+ * Creates the registry and binds it to the extension point.
+ */
+ public ContentAssistProcessorRegistry() {
+ Platform.getExtensionRegistry().addRegistryChangeListener(new IRegistryChangeListener() {
+ @Override
+ public void registryChanged(IRegistryChangeEvent event) {
+ outOfSync = true;
+ }
+ }, EXTENSION_POINT_ID);
+ }
+
+ /**
+ * Get the contributed {@link IContentAssistProcessor}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 contentTypes the content types of the document we're editing.
+ * @return the list of {@link IContentAssistProcessor} contributed for at least one of the content types.
+ */
+ public List<IContentAssistProcessor> getContentAssistProcessors(ISourceViewer sourceViewer, Set<IContentType> contentTypes) {
+ if (this.outOfSync) {
+ sync();
+ }
+ List<IContentAssistProcessor> res = new ArrayList<>();
+ for (ContentAssistProcessorExtension ext : this.extensions.values()) {
+ if (contentTypes.contains(ext.targetContentType)) {
+ res.add(ext);
+ }
+ }
+ return res;
+ }
+
+ private void sync() {
+ Set<IConfigurationElement> 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 ContentAssistProcessorExtension(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;
+ }
+}
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
new file mode 100644
index 00000000000..467be5318d4
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextEditor.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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, Mickael Istria (Red Hat Inc.) - initial implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.genericeditor;
+
+import org.eclipse.ui.editors.text.TextEditor;
+
+/**
+ * A generic code editor that is aimed at being extended by contributions. Behavior
+ * is supposed to be added via extensions, not by inheritance.
+ *
+ * @since 1.0
+ */
+public class ExtensionBasedTextEditor extends TextEditor {
+
+ private static final String CONTEXT_ID = "org.eclipse.ui.genericeditor.genericEditorContext"; //$NON-NLS-1$
+
+ /**
+ *
+ */
+ public ExtensionBasedTextEditor() {
+ setSourceViewerConfiguration(new ExtensionBasedTextViewerConfiguration(this, getPreferenceStore()));
+ }
+
+ @Override
+ protected void setKeyBindingScopes(String[] scopes) {
+ super.setKeyBindingScopes(new String[] { CONTEXT_ID });
+ }
+
+}
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
new file mode 100644
index 00000000000..d8d2b21c423
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextViewerConfiguration.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * 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, Mickael Istria (Red Hat Inc.) - initial implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.genericeditor;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.AbstractReusableInformationControlCreator;
+import org.eclipse.jface.text.DefaultInformationControl;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IInformationControl;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.contentassist.ContentAssistant;
+import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
+import org.eclipse.jface.text.contentassist.IContentAssistant;
+import org.eclipse.jface.text.presentation.IPresentationReconciler;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
+
+/**
+ * The configuration of the {@link ExtensionBasedTextEditor}. It registers the proxy composite
+ * for hover, completion, syntax highlighting, and then those proxy take care of resolving to
+ * the right extensions on-demand.
+ *
+ * @since 1.0
+ */
+public final class ExtensionBasedTextViewerConfiguration extends TextSourceViewerConfiguration {
+
+ private IEditorPart editor;
+ private Set<IContentType> contentTypes;
+
+ /**
+ *
+ * @param editor the editor we're creating.
+ * @param preferenceStore the preference store.
+ */
+ public ExtensionBasedTextViewerConfiguration(IEditorPart editor, IPreferenceStore preferenceStore) {
+ super(preferenceStore);
+ this.editor = editor;
+ }
+
+ private Set<IContentType> getContentTypes() {
+ if (this.contentTypes == null) {
+ this.contentTypes = new HashSet<>(Arrays.asList(Platform.getContentTypeManager().findContentTypesFor(editor.getEditorInput().getName())));
+ }
+ return this.contentTypes;
+ }
+
+ @Override
+ public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) {
+ TextHoverRegistry registry= GenericEditorPlugin.getDefault().getHoverRegistry();
+ return registry.getAvailableHover(sourceViewer, getContentTypes());
+ }
+
+ @Override
+ public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
+ ContentAssistProcessorRegistry registry= GenericEditorPlugin.getDefault().getContentAssistProcessorRegistry();
+ IContentAssistProcessor processor = new CompositeContentAssistProcessor(registry.getContentAssistProcessors(sourceViewer, getContentTypes()));
+ ContentAssistant res= new ContentAssistant();
+ res.setContextInformationPopupOrientation(ContentAssistant.CONTEXT_INFO_BELOW);
+ res.setProposalPopupOrientation(ContentAssistant.PROPOSAL_REMOVE);
+ res.enableColoredLabels(true);
+ res.setContentAssistProcessor(processor, IDocument.DEFAULT_CONTENT_TYPE);
+ res.setInformationControlCreator(new AbstractReusableInformationControlCreator() {
+ @Override
+ protected IInformationControl doCreateInformationControl(Shell parent) {
+ return new DefaultInformationControl(parent);
+ }
+ });
+ return res;
+ }
+
+ @Override
+ public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {
+ PresentationReconcilerRegistry registry = GenericEditorPlugin.getDefault().getPresentationReconcilerRegistry();
+ List<IPresentationReconciler> reconciliers = registry.getPresentationReconcilers(sourceViewer, getContentTypes());
+ if (!reconciliers.isEmpty()) {
+ return reconciliers.get(0);
+ }
+ return null;
+ }
+
+}
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
new file mode 100644
index 00000000000..e5f33d470cc
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * 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, Mickael Istria (Red Hat Inc.) - initial implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.genericeditor;
+
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
+import org.eclipse.jface.text.presentation.IPresentationReconciler;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Generic editor plugin activator and singletons.
+ *
+ * @since 1.0
+ */
+public class GenericEditorPlugin extends AbstractUIPlugin {
+
+ public static final String BUNDLE_ID = "org.eclipse.ui.genericeditor"; //$NON-NLS-1$
+
+ private static GenericEditorPlugin INSTANCE;
+
+ private TextHoverRegistry textHoversRegistry;
+ private ContentAssistProcessorRegistry contentAssistProcessorsRegistry;
+ private PresentationReconcilerRegistry presentationReconcilierRegistry;
+
+ @Override
+ public void start(BundleContext context) throws Exception{
+ INSTANCE = this;
+ super.start(context);
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+ INSTANCE = null;
+ }
+
+ public static GenericEditorPlugin getDefault() {
+ return INSTANCE;
+ }
+
+ /**
+ * @return the registry allowing to access contributed {@link ITextHover}s.
+ * @since 1.0
+ */
+ public synchronized TextHoverRegistry getHoverRegistry() {
+ if (this.textHoversRegistry == null) {
+ this.textHoversRegistry = new TextHoverRegistry(getPreferenceStore());
+ }
+ return this.textHoversRegistry;
+ }
+
+ /**
+ * @return the registry allowing to access contributed {@link IContentAssistProcessor}s.
+ * @since 1.0
+ */
+ public synchronized ContentAssistProcessorRegistry getContentAssistProcessorRegistry() {
+ if (this.contentAssistProcessorsRegistry == null) {
+ this.contentAssistProcessorsRegistry = new ContentAssistProcessorRegistry();
+ }
+ return this.contentAssistProcessorsRegistry;
+ }
+
+ /**
+ * @return the registry allowing to access contributed {@link IPresentationReconciler}s.
+ * @since 1.0
+ */
+ public synchronized PresentationReconcilerRegistry getPresentationReconcilerRegistry() {
+ if (this.presentationReconcilierRegistry == null) {
+ this.presentationReconcilierRegistry = new PresentationReconcilerRegistry();
+ }
+ return this.presentationReconcilierRegistry;
+ }
+}
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
new file mode 100644
index 00000000000..b973b816cf2
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/PresentationReconcilerRegistry.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * 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, Mickael Istria (Red Hat Inc.) - initial implementation
+ *******************************************************************************/
+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 org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.IRegistryChangeListener;
+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.text.ITextViewer;
+import org.eclipse.jface.text.presentation.IPresentationDamager;
+import org.eclipse.jface.text.presentation.IPresentationReconciler;
+import org.eclipse.jface.text.presentation.IPresentationRepairer;
+import org.eclipse.jface.text.source.ISourceViewer;
+
+/**
+ * A registry of presentation reconciliers provided by extension <code>org.eclipse.ui.genericeditor.presentationReconcilers</code>.
+ * Those extensions are specific to a given {@link IContentType}.
+ *
+ * @since 1.0
+ */
+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 implements IPresentationReconciler {
+ 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 IPresentationReconciler delegate;
+
+ private PresentationReconcilerExtension(IConfigurationElement element) throws Exception {
+ this.extension = element;
+ this.targetContentType = Platform.getContentTypeManager().getContentType(element.getAttribute(CONTENT_TYPE_ATTRIBUTE));
+ }
+
+ private IPresentationReconciler getDelegate() {
+ if (this.delegate == null) {
+ try {
+ this.delegate = (IPresentationReconciler) extension.createExecutableExtension(CLASS_ATTRIBUTE);
+ } catch (CoreException e) {
+ e.printStackTrace();
+ }
+ }
+ return delegate;
+ }
+
+ @Override
+ public void install(ITextViewer viewer) {
+ getDelegate().install(viewer);
+ }
+
+ @Override
+ public void uninstall() {
+ getDelegate().uninstall();
+ }
+
+ @Override
+ public IPresentationDamager getDamager(String contentType) {
+ return getDelegate().getDamager(contentType);
+
+ }
+
+ @Override
+ public IPresentationRepairer getRepairer(String contentType) {
+ return getDelegate().getRepairer(contentType);
+ }
+
+ }
+ private Map<IConfigurationElement, PresentationReconcilerExtension> extensions = new HashMap<>();
+ private boolean outOfSync = true;
+
+ /**
+ * Creates the registry and binds it to the extension point.
+ */
+ public PresentationReconcilerRegistry() {
+ Platform.getExtensionRegistry().addRegistryChangeListener(new IRegistryChangeListener() {
+ @Override
+ public void registryChanged(IRegistryChangeEvent 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 contentTypes the content types of the document we're editing.
+ * @return the list of {@link IPresentationReconciler} contributed for at least one of the content types.
+ */
+ public List<IPresentationReconciler> getPresentationReconcilers(ISourceViewer sourceViewer, Set<IContentType> contentTypes) {
+ if (this.outOfSync) {
+ sync();
+ }
+ List<IPresentationReconciler> res = new ArrayList<>();
+ for (PresentationReconcilerExtension ext : this.extensions.values()) {
+ if (contentTypes.contains(ext.targetContentType)) {
+ res.add(ext);
+ }
+ }
+ return res;
+ }
+
+ private void sync() {
+ Set<IConfigurationElement> 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 PresentationReconcilerExtension(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;
+ }
+
+}
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
new file mode 100644
index 00000000000..88e4825f66c
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/TextHoverRegistry.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * 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:
+ * - Mickael Istria (Red Hat Inc.)
+ *******************************************************************************/
+package org.eclipse.ui.internal.genericeditor;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.IRegistryChangeListener;
+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.ITextHover;
+import org.eclipse.jface.text.source.ISourceViewer;
+
+/**
+ * Text hover registry that manages the detectors
+ * contributed by the <code>org.eclipse.ui.workbench.texteditor.hoverProvider</code> extension point for
+ * targets contributed by the <code>org.eclipse.ui.workbench.texteditor.hyperlinkDetectorTargets</code> extension point.
+ *
+ * @since 1.0
+ */
+public final class TextHoverRegistry {
+
+ private static final String EXTENSION_POINT_ID = GenericEditorPlugin.BUNDLE_ID + ".hoverProviders"; //$NON-NLS-1$
+
+ private Map<IConfigurationElement, TextHoverExtension> extensions = new HashMap<>();
+ private boolean outOfSync = true;
+
+ private static class TextHoverExtension {
+ 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 ITextHover delegate;
+
+ public TextHoverExtension(IConfigurationElement extension) throws Exception {
+ this.extension = extension;
+ this.targetContentType = Platform.getContentTypeManager().getContentType(extension.getAttribute(CONTENT_TYPE_ATTRIBUTE));
+ }
+
+ private ITextHover getDelegate() {
+ if (this.delegate == null) {
+ try {
+ this.delegate = (ITextHover) extension.createExecutableExtension(CLASS_ATTRIBUTE);
+ } catch (CoreException e) {
+ e.printStackTrace();
+ }
+ }
+ return delegate;
+ }
+
+ }
+
+ public TextHoverRegistry(IPreferenceStore preferenceStore) {
+ Platform.getExtensionRegistry().addRegistryChangeListener(new IRegistryChangeListener() {
+ @Override
+ public void registryChanged(IRegistryChangeEvent event) {
+ outOfSync = true;
+ }
+ }, EXTENSION_POINT_ID);
+ }
+
+ public ITextHover getAvailableHover(ISourceViewer sourceViewer, Set<IContentType> contentTypes) {
+ if (this.outOfSync) {
+ sync();
+ }
+ // TODO rather that returning the 1st active hover, consider
+ // supporting compound/aggregated hovers.
+ for (TextHoverExtension ext : this.extensions.values()) {
+ if (contentTypes.contains(ext.targetContentType)) {
+ return ext.getDelegate();
+ }
+ }
+ return null;
+ }
+
+ private void sync() {
+ Set<IConfigurationElement> 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 TextHoverExtension(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;
+ }
+
+}

Back to the top