Bug 470203: [content assist] color/style substring code completion
proposals

Change-Id: Ifc8eb3ec5229955b37287592feab1d969c54d00e
Signed-off-by: Noopur Gupta <noopur_gupta@in.ibm.com>
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/util/Strings.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/util/Strings.java
index 602adc1..5028d31 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/util/Strings.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/util/Strings.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation 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
@@ -16,6 +16,7 @@
 
 import org.eclipse.jface.action.LegacyActionTools;
 import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.jface.viewers.StyledString.Styler;
 
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.DefaultLineTracker;
@@ -49,6 +50,35 @@
 
 	private static final String JAVA_ELEMENT_DELIMITERS= TextProcessor.getDefaultDelimiters() + "<>(),?{} "; //$NON-NLS-1$
 
+	/**
+	 * Sets the given <code>styler</code> to use for <code>matchingRegions</code> (obtained from
+	 * {@link org.eclipse.jdt.core.search.SearchPattern#getMatchingRegions}) in the
+	 * <code>styledString</code> starting from the given <code>index</code>.
+	 * 
+	 * @param styledString the styled string to mark
+	 * @param index the index from which to start marking
+	 * @param matchingRegions the regions to mark
+	 * @param styler the styler to use for marking
+	 */
+	public static void markMatchingRegions(StyledString styledString, int index, int[] matchingRegions, Styler styler) {
+		if (matchingRegions != null) {
+			int offset= -1;
+			int length= 0;
+			for (int i= 0; i + 1 < matchingRegions.length; i= i + 2) {
+				if (offset == -1)
+					offset= index + matchingRegions[i];
+
+				// Concatenate adjacent regions
+				if (i + 2 < matchingRegions.length && matchingRegions[i] + matchingRegions[i + 1] == matchingRegions[i + 2]) {
+					length= length + matchingRegions[i + 1];
+				} else {
+					styledString.setStyle(offset, length + matchingRegions[i + 1], styler);
+					offset= -1;
+					length= 0;
+				}
+			}
+		}
+	}
 	
 	/**
 	 * Adds special marks so that that the given styled string is readable in a BiDi environment.
diff --git a/org.eclipse.jdt.ui/plugin.xml b/org.eclipse.jdt.ui/plugin.xml
index f4b51ed..a77f206 100644
--- a/org.eclipse.jdt.ui/plugin.xml
+++ b/org.eclipse.jdt.ui/plugin.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?eclipse version="3.0"?>
 <!-- ====================================================================== -->
-<!-- Copyright (c) 2000, 2015 IBM Corporation and others.                   -->
+<!-- Copyright (c) 2000, 2016 IBM Corporation 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               -->
@@ -300,7 +300,8 @@
 		id="JavaAllCompletionProposalComputer">
 		<javaCompletionProposalComputer 
 			class="org.eclipse.jdt.internal.ui.text.java.JavaAllCompletionProposalComputer"
-			categoryId="org.eclipse.jdt.ui.javaAllProposalCategory">
+			categoryId="org.eclipse.jdt.ui.javaAllProposalCategory"
+			needsSortingAfterFiltering="true">
 			<partition type="__dftl_partition_content_type"/>
 			<partition type="__java_string"/>
 		</javaCompletionProposalComputer>
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/dialogs/FilteredTypesSelectionDialog.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/dialogs/FilteredTypesSelectionDialog.java
index ae491e1..9140c73 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/dialogs/FilteredTypesSelectionDialog.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/dialogs/FilteredTypesSelectionDialog.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation 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
@@ -21,9 +21,6 @@
 import java.util.List;
 import java.util.Map;
 
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Font;
-import org.eclipse.swt.graphics.FontData;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.TextStyle;
 import org.eclipse.swt.layout.GridData;
@@ -65,6 +62,7 @@
 import org.eclipse.jface.viewers.StyledString.Styler;
 
 import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.contentassist.BoldStylerProvider;
 
 import org.eclipse.ui.IMemento;
 import org.eclipse.ui.IWorkbenchWindow;
@@ -699,16 +697,12 @@
 		private boolean fContainerInfo;
 		private LocalResourceManager fImageManager;
 
-		private Font fBoldFont;
-
-		private Styler fBoldStyler;
+		private BoldStylerProvider fBoldStylerProvider;
 
 		private Styler fBoldQualifierStyler;
 
 		public TypeItemLabelProvider() {
 			fImageManager= new LocalResourceManager(JFaceResources.getResources());
-			fBoldStyler= createBoldStyler();
-			fBoldQualifierStyler= createBoldQualifierStyler();
 		}
 
 		/*
@@ -718,9 +712,9 @@
 		public void dispose() {
 			super.dispose();
 			fImageManager.dispose();
-			if (fBoldFont != null) {
-				fBoldFont.dispose();
-				fBoldFont= null;
+			if (fBoldStylerProvider != null) {
+				fBoldStylerProvider.dispose();
+				fBoldStylerProvider= null;
 			}
 		}
 
@@ -788,7 +782,7 @@
 			if (namePattern != null && !"*".equals(namePattern)) { //$NON-NLS-1$
 				String typeName= index == -1 ? text : text.substring(0, index);
 				int[] matchingRegions= SearchPattern.getMatchingRegions(namePattern, typeName, fFilter.getMatchRule());
-				markMatchingRegions(string, 0, matchingRegions, fBoldStyler);
+				Strings.markMatchingRegions(string, 0, matchingRegions, getBoldStylerProvider().getBoldStyler());
 			}
 
 			if (index != -1) {
@@ -803,69 +797,31 @@
 					else
 						packageName= text.substring(index, endIndex);
 					int[] matchingRegions= SearchPattern.getMatchingRegions(packagePattern, packageName, fFilter.getPackageFlags());
-					markMatchingRegions(string, index, matchingRegions, fBoldQualifierStyler);
+					Strings.markMatchingRegions(string, index, matchingRegions, getBoldQualifierStyler());
 				}
 			}
 			return string;
 		}
 
-		private void markMatchingRegions(StyledString string, int index, int[] matchingRegions, Styler styler) {
-			if (matchingRegions != null) {
-				int offset= -1;
-				int length= 0;
-				for (int i= 0; i + 1 < matchingRegions.length; i= i + 2) {
-					if (offset == -1)
-						offset= index + matchingRegions[i];
-					
-					// Concatenate adjacent regions
-					if (i + 2 < matchingRegions.length && matchingRegions[i] + matchingRegions[i + 1] == matchingRegions[i + 2]) {
-						length= length + matchingRegions[i + 1];
-					} else {
-						string.setStyle(offset, length + matchingRegions[i + 1], styler);
-						offset= -1;
-						length= 0;
+		private BoldStylerProvider getBoldStylerProvider() {
+			if (fBoldStylerProvider == null) {
+				fBoldStylerProvider= new BoldStylerProvider(getDialogArea().getFont());
+			}
+			return fBoldStylerProvider;
+		}
+
+		private Styler getBoldQualifierStyler() {
+			if (fBoldQualifierStyler == null) {
+				fBoldQualifierStyler= new Styler() {
+					@Override
+					public void applyStyles(TextStyle textStyle) {
+						StyledString.QUALIFIER_STYLER.applyStyles(textStyle);
+						getBoldStylerProvider().getBoldStyler().applyStyles(textStyle);
 					}
-				}
+				};
 			}
+			return fBoldQualifierStyler;
 		}
-
-		/**
-		 * Create the bold variant of the currently used font.
-		 * 
-		 * @return the bold font
-		 * @since 3.5
-		 */
-		private Font getBoldFont() {
-			if (fBoldFont == null) {
-				Font font= getDialogArea().getFont();
-				FontData[] data= font.getFontData();
-				for (int i= 0; i < data.length; i++) {
-					data[i].setStyle(SWT.BOLD);
-				}
-				fBoldFont= new Font(font.getDevice(), data);
-			}
-			return fBoldFont;
-		}
-
-		private Styler createBoldStyler() {
-			return new Styler() {
-				@Override
-				public void applyStyles(TextStyle textStyle) {
-					textStyle.font= getBoldFont();
-				}
-			};
-		}
-
-		private Styler createBoldQualifierStyler() {
-			return new Styler() {
-				@Override
-				public void applyStyles(TextStyle textStyle) {
-					StyledString.QUALIFIER_STYLER.applyStyles(textStyle);
-					textStyle.font= getBoldFont();
-				}
-			};
-		}
-
 	}
 
 	/**
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/CodeAssistConfigurationBlock.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/CodeAssistConfigurationBlock.java
index 324e6d6..ea102cc 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/CodeAssistConfigurationBlock.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/CodeAssistConfigurationBlock.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation 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
@@ -77,7 +77,7 @@
 	private static final Key PREF_CODEASSIST_PREFIX_COMPLETION= getJDTUIKey(PreferenceConstants.CODEASSIST_PREFIX_COMPLETION);
 	private static final Key PREF_CODEASSIST_DEPRECATION_CHECK= getJDTCoreKey(JavaCore.CODEASSIST_DEPRECATION_CHECK);
 	private static final Key PREF_CODEASSIST_CAMEL_CASE_MATCH= getJDTCoreKey(JavaCore.CODEASSIST_CAMEL_CASE_MATCH);
-//	private static final Key PREF_CODEASSIST_SUBSTRING_MATCH= getJDTCoreKey(JavaCore.CODEASSIST_SUBSTRING_MATCH);
+	private static final Key PREF_CODEASSIST_SUBSTRING_MATCH= getJDTCoreKey(JavaCore.CODEASSIST_SUBSTRING_MATCH);
 
 	private static Key[] getAllKeys() {
 		return new Key[] {
@@ -97,7 +97,7 @@
 				PREF_CODEASSIST_PREFIX_COMPLETION,
 				PREF_CODEASSIST_DEPRECATION_CHECK,
 				PREF_CODEASSIST_CAMEL_CASE_MATCH,
-//				PREF_CODEASSIST_SUBSTRING_MATCH
+				PREF_CODEASSIST_SUBSTRING_MATCH
 		};
 	}
 
@@ -276,8 +276,8 @@
 		label= PreferencesMessages.CodeAssistConfigurationBlock_matchCamelCase_label;
 		addCheckBox(composite, label, PREF_CODEASSIST_CAMEL_CASE_MATCH, enabledDisabled, 0);
 		
-		/*label= PreferencesMessages.CodeAssistConfigurationBlock_matchSubstring_label;
-		addCheckBox(composite, label, PREF_CODEASSIST_SUBSTRING_MATCH, enabledDisabled, 0);*/
+		label= PreferencesMessages.CodeAssistConfigurationBlock_matchSubstring_label;
+		addCheckBox(composite, label, PREF_CODEASSIST_SUBSTRING_MATCH, enabledDisabled, 0);
 		
 		label= PreferencesMessages.JavaEditorPreferencePage_showOnlyProposalsVisibleInTheInvocationContext;
 		addCheckBox(composite, label, PREF_CODEASSIST_SHOW_VISIBLE_PROPOSALS, trueFalse, 0);
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/AbstractJavaCompletionProposal.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/AbstractJavaCompletionProposal.java
index a231df1..44b2bdf 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/AbstractJavaCompletionProposal.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/AbstractJavaCompletionProposal.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2015 IBM Corporation and others.
+ * Copyright (c) 2005, 2016 IBM Corporation 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
@@ -61,11 +61,13 @@
 import org.eclipse.jface.text.ITextViewerExtension5;
 import org.eclipse.jface.text.Position;
 import org.eclipse.jface.text.TextPresentation;
+import org.eclipse.jface.text.contentassist.BoldStylerProvider;
 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension;
 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2;
 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension3;
 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension5;
 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension6;
+import org.eclipse.jface.text.contentassist.ICompletionProposalExtension7;
 import org.eclipse.jface.text.contentassist.IContextInformation;
 import org.eclipse.jface.text.link.ILinkedModeListener;
 import org.eclipse.jface.text.link.LinkedModeModel;
@@ -87,8 +89,10 @@
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.search.SearchPattern;
 
 import org.eclipse.jdt.internal.corext.javadoc.JavaDocLocations;
+import org.eclipse.jdt.internal.corext.util.Strings;
 
 import org.eclipse.jdt.ui.PreferenceConstants;
 import org.eclipse.jdt.ui.text.IJavaPartitions;
@@ -106,7 +110,8 @@
  *
  * @since 3.2
  */
-public abstract class AbstractJavaCompletionProposal implements IJavaCompletionProposal, ICompletionProposalExtension, ICompletionProposalExtension2, ICompletionProposalExtension3, ICompletionProposalExtension5, ICompletionProposalExtension6 {
+public abstract class AbstractJavaCompletionProposal implements IJavaCompletionProposal, ICompletionProposalExtension, ICompletionProposalExtension2, ICompletionProposalExtension3,
+		ICompletionProposalExtension5, ICompletionProposalExtension6, ICompletionProposalExtension7 {
 
 
 	/**
@@ -226,6 +231,8 @@
 	private int fRelevance;
 	private boolean fIsInJavadoc;
 
+	private int fPatternMatchRule= -1;
+
 	private StyleRange fRememberedStyleRange;
 
 	private boolean fToggleEating;
@@ -804,21 +811,21 @@
 	}
 
 	/**
-	 * Checks whether <code>prefix</code> is a valid prefix for this proposal. Usually, while code
-	 * completion is in progress, the user types and edits the prefix in the document in order to
-	 * filter the proposal list. From {@link #validate(IDocument, int, DocumentEvent) }, the
-	 * current prefix in the document is extracted and this method is called to find out whether the
+	 * Checks whether <code>pattern</code> is a valid pattern for this proposal. Usually, while code
+	 * completion is in progress, the user types and edits the pattern in the document in order to
+	 * filter the proposal list. From {@link #validate(IDocument, int, DocumentEvent) }, the current
+	 * pattern in the document is extracted and this method is called to find out whether the
 	 * proposal is still valid.
 	 * <p>
-	 * The default implementation checks if <code>prefix</code> is a prefix of the proposal's
+	 * The default implementation checks if <code>pattern</code> matches the proposal's
 	 * {@link #getDisplayString() display string} using the {@link #isPrefix(String, String) }
 	 * method.
 	 * </p>
 	 *
-	 * @param prefix the current prefix in the document
-	 * @return <code>true</code> if <code>prefix</code> is a valid prefix of this proposal
+	 * @param pattern the current pattern in the document
+	 * @return <code>true</code> if <code>pattern</code> is a valid match for this proposal
 	 */
-	protected boolean isValidPrefix(String prefix) {
+	protected boolean isValidPrefix(String pattern) {
 		/*
 		 * See http://dev.eclipse.org/bugs/show_bug.cgi?id=17667
 		 * why we do not use the replacement string.
@@ -828,7 +835,7 @@
 		 * for performance reasons, as computing the
 		 * replacement string can be expensive.
 		 */
-		return isPrefix(prefix, TextProcessor.deprocess(getDisplayString()));
+		return isPrefix(pattern, TextProcessor.deprocess(getDisplayString()));
 	}
 
 	/**
@@ -837,6 +844,9 @@
 	 */
 	@Override
 	public int getRelevance() {
+		if (fPatternMatchRule == SearchPattern.R_SUBSTRING_MATCH) {
+			return fRelevance - 1;
+		}
 		return fRelevance;
 	}
 
@@ -869,22 +879,44 @@
 	}
 
 	/**
-	 * Case insensitive comparison of <code>prefix</code> with the start of <code>string</code>.
+	 * Case insensitive matching of the <code>pattern</code> within the given <code>string</code>.
 	 *
-	 * @param prefix the prefix
-	 * @param string  the string to look for the prefix
-	 * @return <code>true</code> if the string begins with the given prefix and
-	 *			<code>false</code> if <code>prefix</code> is longer than <code>string</code>
-	 *			or the string doesn't start with the given prefix
+	 * @param pattern the pattern
+	 * @param string the string to look for the pattern
+	 * @return <code>true</code> if the given pattern matches the string as a prefix, as a CamelCase
+	 *         match, or as a substring pattern and <code>false</code> if <code>pattern</code> is
+	 *         longer than <code>string</code> or if the pattern doesn't match the string based on
+	 *         any of these rules
 	 * @since 3.2
 	 */
-	protected boolean isPrefix(String prefix, String string) {
-		if (prefix == null || string ==null || prefix.length() > string.length())
+	protected boolean isPrefix(String pattern, String string) {
+		if (pattern == null || string == null || pattern.length() > string.length())
 			return false;
-		String start= string.substring(0, prefix.length());
-		return start.equalsIgnoreCase(prefix) ||
-				isCamelCaseMatching() && CharOperation.camelCaseMatch(prefix.toCharArray(), string.toCharArray())/* ||
-				isSubstringMatching() && CharOperation.substringMatch(prefix.toCharArray(), string.toCharArray())*/;
+		fPatternMatchRule= getPatternMatchRule(pattern, string);
+		return fPatternMatchRule != -1;
+	}
+
+	/**
+	 * Matches the given <code>pattern</code> in <code>string</code> and returns the match rule.
+	 * 
+	 * @param pattern the pattern to match
+	 * @param string the string to look for the pattern
+	 * @return the match rule used to match the given <code>pattern</code> in <code>string</code>,
+	 *         or -1 if the <code>pattern</code> doesn't match the <code>string</code> based on any
+	 *         rule
+	 * @since 3.12
+	 */
+	protected int getPatternMatchRule(String pattern, String string) {
+		String start= string.substring(0, pattern.length());
+		if (start.equalsIgnoreCase(pattern)) {
+			return SearchPattern.R_PREFIX_MATCH;
+		} else if (isCamelCaseMatching() && CharOperation.camelCaseMatch(pattern.toCharArray(), string.toCharArray())) {
+			return SearchPattern.R_CAMELCASE_MATCH;
+		} else if (isSubstringMatching() && CharOperation.substringMatch(pattern.toCharArray(), string.toCharArray())) {
+			return SearchPattern.R_SUBSTRING_MATCH;
+		} else {
+			return -1;
+		}
 	}
 
 	/**
@@ -1199,6 +1231,53 @@
 		fDisplayString= text;
 	}
 
+	@Override
+	public StyledString emphasizeMatch(IDocument document, int offset, BoldStylerProvider boldStylerProvider) {
+		StyledString styledDisplayString= new StyledString();
+		styledDisplayString.append(getStyledDisplayString());
+
+		String pattern= getPatternToEmphasizeMatch(document, offset);
+		if (pattern != null && pattern.length() > 0) {
+			String displayString= styledDisplayString.getString();
+			int index= displayString.indexOf('(');
+			if (index == -1) {
+				index= displayString.indexOf(':');
+				if (index == -1) {
+					index= displayString.indexOf('-');
+				}
+			}
+			if (index != -1) {
+				displayString= displayString.substring(0, index);
+			}
+			int patternMatchRule= getPatternMatchRule(pattern, displayString);
+			int[] matchingRegions= SearchPattern.getMatchingRegions(pattern, displayString, patternMatchRule);
+			Strings.markMatchingRegions(styledDisplayString, 0, matchingRegions, boldStylerProvider.getBoldStyler());
+		}
+		return styledDisplayString;
+	}
+
+	/**
+	 * Computes the token at the given <code>offset</code> in <code>document</code> to emphasize the
+	 * ranges matching this token in proposal's display string.
+	 * 
+	 * @param document the document where content assist is invoked
+	 * @param offset the offset in the document at current caret location
+	 * @return the token at the given <code>offset</code> in <code>document</code> to be used for
+	 *         emphasizing matching ranges in proposal's display string
+	 * @since 3.12
+	 */
+	protected String getPatternToEmphasizeMatch(IDocument document, int offset) {
+		int start= getPrefixCompletionStart(document, offset);
+		int patternLength= offset - start;
+		String pattern= null;
+		try {
+			pattern= document.get(start, patternLength);
+		} catch (BadLocationException e) {
+			// return null
+		}
+		return pattern;
+	}
+
 	/*
 	 * @see java.lang.Object#toString()
 	 */
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/LazyJavaTypeCompletionProposal.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/LazyJavaTypeCompletionProposal.java
index 4c67d1c..9c44673 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/LazyJavaTypeCompletionProposal.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/LazyJavaTypeCompletionProposal.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation 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
@@ -314,6 +314,18 @@
 		return isPrefix;
 	}
 
+	@Override
+	protected String getPatternToEmphasizeMatch(IDocument document, int offset) {
+		String pattern= super.getPatternToEmphasizeMatch(document, offset);
+		if (pattern != null && getPatternMatchRule(pattern, getStyledDisplayString().getString()) == -1) {
+			int lastIndexOfDot= pattern.lastIndexOf('.');
+			if (lastIndexOfDot != -1) {
+				pattern= pattern.substring(lastIndexOfDot + 1);
+			}
+		}
+		return pattern;
+	}
+
 	/*
 	 * @see org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal#getCompletionText()
 	 */
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/template/contentassist/TemplateProposal.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/template/contentassist/TemplateProposal.java
index 649a1dd..2049615 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/template/contentassist/TemplateProposal.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/template/contentassist/TemplateProposal.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation 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
@@ -36,11 +36,13 @@
 import org.eclipse.jface.text.ITextViewerExtension;
 import org.eclipse.jface.text.Position;
 import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.contentassist.BoldStylerProvider;
 import org.eclipse.jface.text.contentassist.ICompletionProposal;
 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2;
 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension3;
 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension4;
 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension6;
+import org.eclipse.jface.text.contentassist.ICompletionProposalExtension7;
 import org.eclipse.jface.text.contentassist.IContextInformation;
 import org.eclipse.jface.text.link.ILinkedModeListener;
 import org.eclipse.jface.text.link.LinkedModeModel;
@@ -62,9 +64,12 @@
 
 import org.eclipse.ui.texteditor.link.EditorLinkedModeUI;
 
+import org.eclipse.jdt.core.search.SearchPattern;
+
 import org.eclipse.jdt.internal.corext.template.java.CompilationUnitContext;
 import org.eclipse.jdt.internal.corext.template.java.JavaDocContext;
 import org.eclipse.jdt.internal.corext.util.Messages;
+import org.eclipse.jdt.internal.corext.util.Strings;
 
 import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
 
@@ -77,7 +82,8 @@
 /**
  * A template proposal.
  */
-public class TemplateProposal implements IJavaCompletionProposal, ICompletionProposalExtension2, ICompletionProposalExtension3, ICompletionProposalExtension4, ICompletionProposalExtension6 {
+public class TemplateProposal
+		implements IJavaCompletionProposal, ICompletionProposalExtension2, ICompletionProposalExtension3, ICompletionProposalExtension4, ICompletionProposalExtension6, ICompletionProposalExtension7 {
 
 	private final Template fTemplate;
 	private final TemplateContext fContext;
@@ -472,6 +478,25 @@
 		fDisplayString= displayString;
 	}
 
+	@Override
+	public StyledString emphasizeMatch(IDocument document, int offset, BoldStylerProvider boldStylerProvider) {
+		StyledString styledDisplayString= new StyledString();
+		styledDisplayString.append(getStyledDisplayString());
+		int start= getPrefixCompletionStart(document, offset);
+		int patternLength= offset - start;
+		try {
+			String pattern= document.get(start, patternLength);
+			if (!pattern.isEmpty()) {
+				String displayString= styledDisplayString.getString();
+				int[] matchingRegions= SearchPattern.getMatchingRegions(pattern, displayString, SearchPattern.R_PREFIX_MATCH);
+				Strings.markMatchingRegions(styledDisplayString, 0, matchingRegions, boldStylerProvider.getBoldStyler());
+			}
+		} catch (BadLocationException e) {
+			// return styledDisplayString
+		}
+		return styledDisplayString;
+	}
+
 	/*
 	 * @see ICompletionProposal#getImage()
 	 */