[565338] Enable text hovers from the generic editor
diff --git a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/StructuredTextViewerConfiguration.java b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/StructuredTextViewerConfiguration.java
index 4d88757..4e8effe 100644
--- a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/StructuredTextViewerConfiguration.java
+++ b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/StructuredTextViewerConfiguration.java
@@ -524,7 +524,7 @@
 	 * @param partitionType
 	 *            the partition type for which the lineStyleProviders are
 	 *            applicable
-	 * @return LineStyleProvders or null if should not be supported
+	 * @return LineStyleProvders or <code>null</code> if should not be supported
 	 */
 	public LineStyleProvider[] getLineStyleProviders(ISourceViewer sourceViewer, String partitionType) {
 		return null;
@@ -736,7 +736,7 @@
 	}
 	
 	/**
-	 * @return the associated content assistnat
+	 * @return the associated content assistant
 	 */
 	protected StructuredContentAssistant getContentAssistant() {
 		return this.fContentAssistant;
diff --git a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/PreferenceInitializer.java b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/PreferenceInitializer.java
index 187583e..f89e5f4 100644
--- a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/PreferenceInitializer.java
+++ b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/PreferenceInitializer.java
@@ -52,7 +52,7 @@
 		store.setDefault(EditorPreferenceNames.READ_ONLY_FOREGROUND_SCALE, 30);
 		
 		store.setDefault(EditorPreferenceNames.CODEASSIST_AUTOACTIVATION_DELAY, 500);
-		
+
 		initAppearanceAndHoverPreferences(store, registry);
 	}
 
@@ -85,5 +85,7 @@
 		 * SWT.MOD2 is currently SWT.COMMAND on Mac; SWT.CONTROL elsewhere
 		 */
 		store.setDefault(AppearancePreferenceNames.EDITOR_TEXT_HOVER_MODIFIERS, "combinationHover|true|0;problemHover|false|0;documentationHover|false|0;annotationHover|true|" + mod2Name); //$NON-NLS-1$
+
+		store.setDefault(EditorPreferenceNames.PREFER_GENERIC_HOVER, true);
 	}
 }
\ No newline at end of file
diff --git a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/SSEUIMessages.java b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/SSEUIMessages.java
index d581e5b..c765af1 100644
--- a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/SSEUIMessages.java
+++ b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/SSEUIMessages.java
@@ -1,5 +1,5 @@
 /**********************************************************************
- * Copyright (c) 2005, 2015 IBM Corporation and others. All rights reserved.   This
+ * Copyright (c) 2005, 2020 IBM Corporation and others. All rights reserved.   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 https://www.eclipse.org/legal/epl-2.0/
@@ -256,6 +256,7 @@
 	public static String TextHoverPreferenceTab_hoverPreferences;
 	public static String TextHoverPreferenceTab_keyModifier;
 	public static String TextHoverPreferenceTab_description;
+	public static String TextHoverPreferenceTab_generic;
 	public static String TextHoverPreferenceTab_modifierIsNotValid;
 	public static String TextHoverPreferenceTab_modifierIsNotValidForHover;
 	public static String TextHoverPreferenceTab_duplicateModifier;
diff --git a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/SSEUIPluginResources.properties b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/SSEUIPluginResources.properties
index 0bfd5d2..6afd12c 100644
--- a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/SSEUIPluginResources.properties
+++ b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/SSEUIPluginResources.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2001, 2015 IBM Corporation and others.
+# Copyright (c) 2001, 2020 IBM Corporation and others.
 # All rights reserved. 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
@@ -232,6 +232,7 @@
 TextHoverPreferenceTab_hoverPreferences=Text &Hover key modifier preferences:
 TextHoverPreferenceTab_keyModifier=Pressed key &modifier while hovering:
 TextHoverPreferenceTab_description=Description:
+TextHoverPreferenceTab_generic=Prefer Generic Editor hovers when available
 TextHoverPreferenceTab_modifierIsNotValid=Modifier ''{0}'' is not valid.
 TextHoverPreferenceTab_modifierIsNotValidForHover=Modifier ''{0}'' for ''{1}'' hover is not valid.
 TextHoverPreferenceTab_duplicateModifier=''{0}'' hover uses the same modifier as ''{1}'' hover.
diff --git a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/preferences/EditorPreferenceNames.java b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/preferences/EditorPreferenceNames.java
index 71752e8..18bedbd 100644
--- a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/preferences/EditorPreferenceNames.java
+++ b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/preferences/EditorPreferenceNames.java
@@ -44,4 +44,9 @@
 	 * </p>
 	 */
 	public final static String CODEASSIST_AUTOACTIVATION_DELAY = "content_assist_autoactivation_delay"; //$NON-NLS-1$
+
+	/**
+	 * Preference name for boolean value controlling whether to defer to Generic Editor hovers
+	 */
+	public final static String PREFER_GENERIC_HOVER = "prefer_generic_hover"; //$NON-NLS-1$
 }
diff --git a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/preferences/ui/TextHoverPreferenceTab.java b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/preferences/ui/TextHoverPreferenceTab.java
index 6bb5c74..57fce1c 100644
--- a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/preferences/ui/TextHoverPreferenceTab.java
+++ b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/preferences/ui/TextHoverPreferenceTab.java
@@ -16,12 +16,14 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
+import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jface.action.Action;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.preference.PreferencePage;
-import org.eclipse.jface.text.Assert;
 import org.eclipse.jface.viewers.ArrayContentProvider;
 import org.eclipse.jface.viewers.CheckStateChangedEvent;
 import org.eclipse.jface.viewers.CheckboxTableViewer;
@@ -56,6 +58,7 @@
 import org.eclipse.wst.sse.ui.internal.SSEUIMessages;
 import org.eclipse.wst.sse.ui.internal.SSEUIPlugin;
 import org.eclipse.wst.sse.ui.internal.editor.IHelpContextIds;
+import org.eclipse.wst.sse.ui.internal.preferences.EditorPreferenceNames;
 import org.eclipse.wst.sse.ui.internal.preferences.OverlayPreferenceStore;
 import org.eclipse.wst.sse.ui.internal.taginfo.TextHoverManager;
 import org.eclipse.wst.sse.ui.internal.taginfo.TextHoverManager.TextHoverDescriptor;
@@ -286,6 +289,10 @@
 		gd.horizontalSpan = 2;
 		fDescription.setLayoutData(gd);
 
+		new Label(hoverComposite, SWT.NONE).setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1));
+
+		addCheckBox(hoverComposite, SSEUIMessages.TextHoverPreferenceTab_generic, EditorPreferenceNames.PREFER_GENERIC_HOVER, 0);
+
 		initialize();
 
 		Dialog.applyDialogFont(hoverComposite);
@@ -295,9 +302,10 @@
 	}
 
 	private OverlayPreferenceStore.OverlayKey[] createOverlayStoreKeys() {
-		ArrayList overlayKeys = new ArrayList();
+		List<OverlayPreferenceStore.OverlayKey> overlayKeys = new ArrayList<>();
 
 		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, AppearancePreferenceNames.EDITOR_TEXT_HOVER_MODIFIERS));
+		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, EditorPreferenceNames.PREFER_GENERIC_HOVER));
 
 		OverlayPreferenceStore.OverlayKey[] keys = new OverlayPreferenceStore.OverlayKey[overlayKeys.size()];
 		overlayKeys.toArray(keys);
@@ -383,8 +391,9 @@
 
 		fModifierEditor.setEnabled(false);
 		// initialize checkboxes in hover table
-		for (int i = 0; i < fTextHovers.length; i++)
+		for (int i = 0; i < fTextHovers.length; i++) {
 			fHoverTable.getItem(i).setChecked(fTextHovers[i].isEnabled());
+		}
 		fHoverTableViewer.refresh();
 	}
 
@@ -414,9 +423,10 @@
 	public void performOk() {
 		String textHoverString = generateTextHoverString();
 		getOverlayStore().setValue(AppearancePreferenceNames.EDITOR_TEXT_HOVER_MODIFIERS, textHoverString);
-		getTextHoverManager().resetTextHovers(); // notify text hover manager
-		// it should reset to get
-		// latest preferences
+		/*
+		 * notify text hover manager it should reset to get latest preferences
+		 */
+		getTextHoverManager().resetTextHovers();
 	}
 
 	/**
@@ -435,7 +445,7 @@
 			status = new StatusInfo(IStatus.ERROR, NLS.bind(SSEUIMessages.TextHoverPreferenceTab_modifierIsNotValid, new String[]{hoverConfig.getModifierString()}));
 
 		int i = 0;
-		HashMap stateMasks = new HashMap(fTextHovers.length);
+		Map<Integer, String> stateMasks = new HashMap<>(fTextHovers.length);
 		while (status.isOK() && i < fTextHovers.length) {
 			if (fTextHovers[i].isEnabled()) {
 				String label = fTextHovers[i].getLabel();
@@ -443,7 +453,7 @@
 				if (stateMask.intValue() == -1)
 					status = new StatusInfo(IStatus.ERROR, NLS.bind(SSEUIMessages.TextHoverPreferenceTab_modifierIsNotValidForHover, new String[]{fTextHovers[i].getModifierString(), label}));
 				else if (stateMasks.containsKey(stateMask))
-					status = new StatusInfo(IStatus.ERROR, NLS.bind(SSEUIMessages.TextHoverPreferenceTab_duplicateModifier, new String[]{label, (String) stateMasks.get(stateMask)}));
+					status = new StatusInfo(IStatus.ERROR, NLS.bind(SSEUIMessages.TextHoverPreferenceTab_duplicateModifier, new String[]{label, stateMasks.get(stateMask)}));
 				else
 					stateMasks.put(stateMask, label);
 			}
diff --git a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/taginfo/BestMatchHover.java b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/taginfo/BestMatchHover.java
index 3443c22..af578af 100644
--- a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/taginfo/BestMatchHover.java
+++ b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/taginfo/BestMatchHover.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2013 IBM Corporation and others.
+ * Copyright (c) 2005, 2020 IBM Corporation and others.
  * All rights reserved. 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
@@ -15,17 +15,28 @@
 package org.eclipse.wst.sse.ui.internal.taginfo;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
+import org.eclipse.core.filebuffers.FileBuffers;
+import org.eclipse.core.filebuffers.ITextFileBuffer;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.IInformationControlCreator;
 import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.ITextHover;
 import org.eclipse.jface.text.ITextHoverExtension;
 import org.eclipse.jface.text.ITextHoverExtension2;
 import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.ui.internal.genericeditor.GenericEditorPlugin;
 import org.eclipse.wst.sse.ui.internal.ExtendedConfigurationBuilder;
 import org.eclipse.wst.sse.ui.internal.Logger;
+import org.eclipse.wst.sse.ui.internal.SSEUIPlugin;
+import org.eclipse.wst.sse.ui.internal.preferences.EditorPreferenceNames;
 
 /**
  * Provides the best hover help documentation (by using other hover help
@@ -40,7 +51,7 @@
 	 */
 	private ITextHover[] fTagInfoHovers;
 	/** List of text hovers to consider in best match */
-	private List fTextHovers;
+	private List<ITextHover> fTextHovers;
 	/**
 	 * Partition type for which to create text hovers (when deferred for
 	 * performance)
@@ -49,6 +60,8 @@
 
 	private ITextHover controlCreatorProvider;
 
+	private Set<IContentType> fDetectedContentTypes;
+
 	public BestMatchHover(ITextHover infoTagHover) {
 		this(new ITextHover[]{infoTagHover});
 	}
@@ -67,8 +80,8 @@
 	 * 
 	 * @return List of ITextHover - in abstract class this is empty list
 	 */
-	private List createTextHoversList() {
-		List hoverList = new ArrayList();
+	private List<ITextHover> createTextHoversList(ITextViewer textViewer) {
+		List<ITextHover> hoverList = new ArrayList<>();
 		// if currently debugging, then add the debug hover to the list of
 		// best match
 		if (Logger.isTracing(DebugInfoHoverProcessor.TRACEFILTER)) {
@@ -78,8 +91,8 @@
 		hoverList.add(new ProblemAnnotationHoverProcessor());
 		
 		if (fPartitionType != null && fTagInfoHovers == null) {
-			List extendedTextHover = ExtendedConfigurationBuilder.getInstance().getConfigurations(ExtendedConfigurationBuilder.DOCUMENTATIONTEXTHOVER, fPartitionType);
-			fTagInfoHovers = (ITextHover[]) extendedTextHover.toArray(new ITextHover[extendedTextHover.size()]);
+			List<ITextHover> extendedTextHover = ExtendedConfigurationBuilder.getInstance().getConfigurations(ExtendedConfigurationBuilder.DOCUMENTATIONTEXTHOVER, fPartitionType);
+			fTagInfoHovers = extendedTextHover.toArray(new ITextHover[extendedTextHover.size()]);
 		}
 		if (fTagInfoHovers != null) {
 			for (int i = 0; i < fTagInfoHovers.length; i++) {
@@ -87,9 +100,39 @@
 			}
 		}
 		hoverList.add(new AnnotationHoverProcessor());
+
+		if (SSEUIPlugin.getInstance().getPreferenceStore().getBoolean(EditorPreferenceNames.PREFER_GENERIC_HOVER)) {
+			Set<IContentType> detectedContentTypes = detectContentTypes(textViewer);
+			if (textViewer instanceof ISourceViewer && detectedContentTypes != null) {
+				List<ITextHover> genericHovers = GenericEditorPlugin.getDefault().getHoverRegistry().getAvailableHovers((ISourceViewer) textViewer, null, detectedContentTypes);
+				hoverList.addAll(0, genericHovers);
+			}
+		}
 		return hoverList;
 	}
 
+	private Set<IContentType> detectContentTypes(ITextViewer viewer) {
+		if (fDetectedContentTypes == null) {
+			Set<IContentType> types = new HashSet<>();
+			IDocument currentDocument = viewer.getDocument();
+			if (currentDocument != null) {
+				ITextFileBuffer textFileBuffer = FileBuffers.getTextFileBufferManager().getTextFileBuffer(currentDocument);
+				if (textFileBuffer != null) {
+					IContentType[] foundTypes = Platform.getContentTypeManager().findContentTypesFor(textFileBuffer.getLocation().lastSegment());
+					for (int i = 0; i < foundTypes.length; i++) {
+						IContentType type = foundTypes[i];
+						while (type != null) {
+							types.add(type);
+							type = type.getBaseType();
+						}
+					}
+				}
+			}
+			fDetectedContentTypes = types;
+		}
+		return fDetectedContentTypes;
+	}
+
 	public IInformationControlCreator getHoverControlCreator() {
 		IInformationControlCreator creator = null;
 
@@ -118,9 +161,9 @@
 		// either had no best match hover or best match hover returned null
 		if (displayText == null) {
 			// go through list of text hovers and return first display string
-			Iterator i = getTextHovers().iterator();
+			Iterator<ITextHover> i = getTextHovers(viewer).iterator();
 			while ((i.hasNext()) && (displayText == null)) {
-				ITextHover hover = (ITextHover) i.next();
+				ITextHover hover = i.next();
 				displayText = hover.getHoverInfo(viewer, hoverRegion);
 				if (displayText != null) {
 					controlCreatorProvider = hover;
@@ -146,9 +189,9 @@
 		// either had no best match hover or best match hover returned null
 		if (information == null) {
 			// go through list of text hovers and return first display string
-			Iterator i = getTextHovers().iterator();
+			Iterator<ITextHover> i = getTextHovers(textViewer).iterator();
 			while ((i.hasNext()) && (information == null)) {
-				ITextHover hover = (ITextHover) i.next();
+				ITextHover hover = i.next();
 				if (hover == fBestMatchHover)
 					continue;
 				if (hover instanceof ITextHoverExtension2) {
@@ -179,9 +222,9 @@
 
 		// go through list of text hovers and return first hover region
 		ITextHover hover = null;
-		Iterator i = getTextHovers().iterator();
+		Iterator<ITextHover> i = getTextHovers(viewer).iterator();
 		while ((i.hasNext()) && (hoverRegion == null)) {
-			hover = (ITextHover) i.next();
+			hover = i.next();
 			hoverRegion = hover.getHoverRegion(viewer, offset);
 		}
 
@@ -194,9 +237,9 @@
 		return hoverRegion;
 	}
 
-	private List getTextHovers() {
+	private List<ITextHover> getTextHovers(ITextViewer viewer) {
 		if (fTextHovers == null) {
-			fTextHovers = createTextHoversList();
+			fTextHovers = createTextHoversList(viewer);
 		}
 		return fTextHovers;
 	}