Bug 528256 - Support async autocompletion

DLTK Core doesn't need UI thread to compute completion proposals.

Change-Id: Id11ae8f5f6e6514aaa66245251b1a1e59f29a757
Signed-off-by: Dawid Pakuła <zulus@w3des.net>
diff --git a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/templates/ScriptTemplateCompletionProcessor.java b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/templates/ScriptTemplateCompletionProcessor.java
index f7f39a8..216e994 100644
--- a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/templates/ScriptTemplateCompletionProcessor.java
+++ b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/templates/ScriptTemplateCompletionProcessor.java
@@ -41,14 +41,13 @@
 import org.eclipse.jface.window.Window;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.part.IWorkbenchPartOrientation;
 
-public abstract class ScriptTemplateCompletionProcessor
-		extends TemplateCompletionProcessor {
+public abstract class ScriptTemplateCompletionProcessor extends TemplateCompletionProcessor {
 
-	private static final class ProposalComparator
-			implements Comparator<TemplateProposal> {
+	private static final class ProposalComparator implements Comparator<TemplateProposal> {
 		@Override
 		public int compare(TemplateProposal o1, TemplateProposal o2) {
 			return o2.getRelevance() - o1.getRelevance();
@@ -59,8 +58,7 @@
 
 	private final ScriptContentAssistInvocationContext context;
 
-	public ScriptTemplateCompletionProcessor(
-			ScriptContentAssistInvocationContext context) {
+	public ScriptTemplateCompletionProcessor(ScriptContentAssistInvocationContext context) {
 		Assert.isNotNull(context);
 		this.context = context;
 	}
@@ -74,12 +72,24 @@
 	private static final String $_WORD_SELECTION = "${" //$NON-NLS-1$
 			+ GlobalTemplateVariables.WordSelection.NAME + "}"; //$NON-NLS-1$
 
-	@Override
-	public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer,
-			int offset) {
+	protected ITextSelection getTextSelection(ITextViewer viewer) {
+		final ITextSelection[] selection = new ITextSelection[1];
+		Runnable getSelection = () -> {
+			selection[0] = (ITextSelection) viewer.getSelectionProvider().getSelection();
+		};
+		if (Display.getCurrent() != null) {
+			getSelection.run();
+		} else {
+			Display.getDefault().syncExec(getSelection);
+		}
 
-		ITextSelection selection = (ITextSelection) viewer
-				.getSelectionProvider().getSelection();
+		return selection[0];
+	}
+
+	@Override
+	public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
+
+		ITextSelection selection = getTextSelection(viewer);
 
 		// adjust offset to end of normalized selection
 		if (selection.getOffset() == offset)
@@ -92,15 +102,13 @@
 			if (!isValidPrefix(prefix)) {
 				return new ICompletionProposal[0];
 			}
-			IRegion region = new Region(offset - prefix.length(),
-					prefix.length());
+			IRegion region = new Region(offset - prefix.length(), prefix.length());
 			TemplateContext context = createContext(viewer, region);
 			if (context == null)
 				return new ICompletionProposal[0];
 			// name of the selection variables {line, word}_selection
 			context.setVariable("selection", selection.getText()); //$NON-NLS-1$
-			Template[] templates = getTemplates(
-					context.getContextType().getId());
+			Template[] templates = getTemplates(context.getContextType().getId());
 			for (int i = 0; i != templates.length; i++) {
 				final Template template = templates[i];
 				try {
@@ -109,22 +117,19 @@
 					continue;
 				}
 				if (isMatchingTemplate(template, prefix, context)) {
-					matches.add((TemplateProposal) createProposal(template,
-							context, region, getRelevance(template, prefix)));
+					matches.add((TemplateProposal) createProposal(template, context, region,
+							getRelevance(template, prefix)));
 				}
 			}
 		} else {
-			IRegion region = new Region(offset - selection.getLength(),
-					selection.getLength());
+			IRegion region = new Region(offset - selection.getLength(), selection.getLength());
 			TemplateContext context = createContext(viewer, region);
 			if (context == null)
 				return new ICompletionProposal[0];
 			// name of the selection variables {line, word}_selection
 			context.setVariable("selection", selection.getText()); //$NON-NLS-1$
-			Template[] templates = getTemplates(
-					context.getContextType().getId());
-			final boolean multipleLinesSelected = areMultipleLinesSelected(
-					viewer);
+			Template[] templates = getTemplates(context.getContextType().getId());
+			final boolean multipleLinesSelected = areMultipleLinesSelected(viewer);
 			for (int i = 0; i != templates.length; i++) {
 				final Template template = templates[i];
 				try {
@@ -132,12 +137,9 @@
 				} catch (TemplateException e) {
 					continue;
 				}
-				if (!multipleLinesSelected
-						&& template.getPattern().indexOf($_WORD_SELECTION) != -1
-						|| (multipleLinesSelected && template.getPattern()
-								.indexOf($_LINE_SELECTION) != -1)) {
-					matches.add((TemplateProposal) createProposal(template,
-							context, region, getRelevance(template)));
+				if (!multipleLinesSelected && template.getPattern().indexOf($_WORD_SELECTION) != -1
+						|| (multipleLinesSelected && template.getPattern().indexOf($_LINE_SELECTION) != -1)) {
+					matches.add((TemplateProposal) createProposal(template, context, region, getRelevance(template)));
 				}
 			}
 		}
@@ -153,12 +155,11 @@
 	}
 
 	/**
-	 * Returns <code>true</code> if one line is completely selected or if
-	 * multiple lines are selected. Being completely selected means that all
-	 * characters except the new line characters are selected.
+	 * Returns <code>true</code> if one line is completely selected or if multiple
+	 * lines are selected. Being completely selected means that all characters
+	 * except the new line characters are selected.
 	 *
-	 * @param viewer
-	 *                   the text viewer
+	 * @param viewer the text viewer
 	 * @return <code>true</code> if one or multiple lines are selected
 	 * @since 2.1
 	 */
@@ -173,8 +174,7 @@
 			int startLine = document.getLineOfOffset(s.x);
 			int endLine = document.getLineOfOffset(s.x + s.y);
 			IRegion line = document.getLineInformation(startLine);
-			return startLine != endLine
-					|| (s.x == line.getOffset() && s.y == line.getLength());
+			return startLine != endLine || (s.x == line.getOffset() && s.y == line.getLength());
 		} catch (BadLocationException x) {
 			return false;
 		}
@@ -184,15 +184,12 @@
 		return prefix.length() != 0;
 	}
 
-	protected boolean isMatchingTemplate(Template template, String prefix,
-			TemplateContext context) {
-		return template.getName().startsWith(prefix)
-				&& template.matches(prefix, context.getContextType().getId());
+	protected boolean isMatchingTemplate(Template template, String prefix, TemplateContext context) {
+		return template.getName().startsWith(prefix) && template.matches(prefix, context.getContextType().getId());
 	}
 
 	@Override
-	protected TemplateContext createContext(ITextViewer viewer,
-			IRegion region) {
+	protected TemplateContext createContext(ITextViewer viewer, IRegion region) {
 		TemplateContextType contextType = getContextType(viewer, region);
 		if (contextType instanceof ScriptTemplateContextType) {
 			IDocument document = viewer.getDocument();
@@ -201,18 +198,17 @@
 			if (sourceModule == null) {
 				return null;
 			}
-			return ((ScriptTemplateContextType) contextType).createContext(
-					document, region.getOffset(), region.getLength(),
-					sourceModule);
+			return ((ScriptTemplateContextType) contextType).createContext(document, region.getOffset(),
+					region.getLength(), sourceModule);
 		}
 		return null;
 	}
 
 	@Override
-	protected ICompletionProposal createProposal(Template template,
-			TemplateContext context, IRegion region, int relevance) {
+	protected ICompletionProposal createProposal(Template template, TemplateContext context, IRegion region,
+			int relevance) {
 		return new ScriptTemplateProposal(template, context, region,
-				getImage(template), relevance);
+				() -> ScriptTemplateCompletionProcessor.this.getImage(template), relevance);
 	}
 
 	protected IInformationControlCreator getInformationControlCreator() {
@@ -223,8 +219,7 @@
 		if (editor instanceof IWorkbenchPartOrientation)
 			orientation = ((IWorkbenchPartOrientation) editor).getOrientation();
 		IDLTKLanguageToolkit toolkit = null;
-		toolkit = DLTKLanguageManager
-				.getLanguageToolkit(getContext().getLanguageNatureID());
+		toolkit = DLTKLanguageManager.getLanguageToolkit(getContext().getLanguageNatureID());
 		if ((toolkit == null) && (editor instanceof ScriptEditor))
 			toolkit = ((ScriptEditor) editor).getLanguageToolkit();
 		return new TemplateInformationControlCreator(orientation, toolkit);
@@ -236,8 +231,7 @@
 
 	@Override
 	protected Template[] getTemplates(String contextTypeId) {
-		return getTemplateAccess().getTemplateStore()
-				.getTemplates(contextTypeId);
+		return getTemplateAccess().getTemplateStore().getTemplates(contextTypeId);
 	}
 
 	protected char[] getIgnore() {
@@ -245,11 +239,9 @@
 	}
 
 	@Override
-	protected TemplateContextType getContextType(ITextViewer viewer,
-			IRegion region) {
+	protected TemplateContextType getContextType(ITextViewer viewer, IRegion region) {
 		if (isValidLocation(viewer, region)) {
-			return getTemplateAccess().getContextTypeRegistry()
-					.getContextType(getContextTypeId());
+			return getTemplateAccess().getContextTypeRegistry().getContextType(getContextTypeId());
 		}
 		return null;
 	}
@@ -285,13 +277,11 @@
 		return DLTKPluginImages.get(DLTKPluginImages.IMG_OBJS_TEMPLATE);
 	}
 
-	protected String getTrigger(ITextViewer viewer, IRegion region)
-			throws BadLocationException {
+	protected String getTrigger(ITextViewer viewer, IRegion region) throws BadLocationException {
 		final IDocument doc = viewer.getDocument();
 		final int regionEnd = region.getOffset() + region.getLength();
 		final IRegion line = doc.getLineInformationOfOffset(regionEnd);
-		final String s = doc.get(line.getOffset(),
-				regionEnd - line.getOffset());
+		final String s = doc.get(line.getOffset(), regionEnd - line.getOffset());
 		final int spaceIndex = s.lastIndexOf(' ');
 		if (spaceIndex != -1) {
 			return s.substring(spaceIndex);
@@ -300,11 +290,9 @@
 	}
 
 	/**
-	 * Returns the relevance of a template. The default implementation returns
-	 * zero.
+	 * Returns the relevance of a template. The default implementation returns zero.
 	 *
-	 * @param template
-	 *                     the template to compute the relevance for
+	 * @param template the template to compute the relevance for
 	 * @return the relevance of <code>template</code>
 	 */
 	protected int getRelevance(Template template) {
diff --git a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/templates/ScriptTemplateProposal.java b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/templates/ScriptTemplateProposal.java
index dc73d0d..e9536ef 100644
--- a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/templates/ScriptTemplateProposal.java
+++ b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/templates/ScriptTemplateProposal.java
@@ -1,5 +1,7 @@
 package org.eclipse.dltk.ui.templates;
 
+import java.util.function.Supplier;
+
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.IRegion;
@@ -13,14 +15,21 @@
 import org.eclipse.jface.text.templates.TemplateProposal;
 import org.eclipse.swt.graphics.Image;
 
-public class ScriptTemplateProposal extends TemplateProposal implements
-		ICompletionProposalExtension4 {
+public class ScriptTemplateProposal extends TemplateProposal implements ICompletionProposalExtension4 {
+	private Supplier<Image> fImageFactory;
+	private Image fComputedImage;
 
-	public ScriptTemplateProposal(Template template, TemplateContext context,
-			IRegion region, Image image, int relevance) {
+	public ScriptTemplateProposal(Template template, TemplateContext context, IRegion region, Image image,
+			int relevance) {
 		super(template, context, region, image, relevance);
 	}
 
+	public ScriptTemplateProposal(Template template, TemplateContext context, IRegion region, Supplier<Image> image,
+			int relevance) {
+		super(template, context, region, null, relevance);
+		fImageFactory = image;
+	}
+
 	private boolean isRelevanceOverriden;
 	private int relevanceOverride;
 
@@ -32,6 +41,14 @@
 		return isRelevanceOverriden ? relevanceOverride : super.getRelevance();
 	}
 
+	public void setImageFactory(Supplier<Image> factory) {
+		fImageFactory = factory;
+	}
+
+	public Supplier<Image> getImageFactory() {
+		return fImageFactory;
+	}
+
 	public void setRelevance(int value) {
 		this.relevanceOverride = value;
 		this.isRelevanceOverriden = true;
@@ -50,10 +67,8 @@
 
 				// restore indenting
 				IDocument document = scriptContext.getDocument();
-				String indenting = ScriptTemplateContext.calculateIndent(
-						document, scriptContext.getStart());
-				String delimeter = TextUtilities
-						.getDefaultLineDelimiter(document);
+				String indenting = ScriptTemplateContext.calculateIndent(document, scriptContext.getStart());
+				String delimeter = TextUtilities.getDefaultLineDelimiter(document);
 
 				String info = templateBuffer.getString();
 				return info.replaceAll(delimeter + indenting, delimeter);
@@ -99,4 +114,17 @@
 		return getDisplayString();
 	}
 
+	@Override
+	public Image getImage() {
+		if (fComputedImage != null) {
+			return fComputedImage;
+		}
+		if (fImageFactory != null) {
+			fComputedImage = fImageFactory.get();
+			return fComputedImage;
+		}
+
+		return super.getImage();
+	}
+
 }
diff --git a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/AbstractScriptCompletionProposal.java b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/AbstractScriptCompletionProposal.java
index 93e0ec6..c781d4b 100644
--- a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/AbstractScriptCompletionProposal.java
+++ b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/AbstractScriptCompletionProposal.java
@@ -12,6 +12,7 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.net.URL;
+import java.util.function.Supplier;
 
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.FileLocator;
@@ -42,6 +43,7 @@
 import org.eclipse.jface.text.IInformationControlCreator;
 import org.eclipse.jface.text.IPositionUpdater;
 import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextSelection;
 import org.eclipse.jface.text.ITextViewer;
 import org.eclipse.jface.text.ITextViewerExtension2;
 import org.eclipse.jface.text.ITextViewerExtension5;
@@ -75,6 +77,7 @@
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.RGB;
 import org.eclipse.swt.graphics.TextStyle;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.IWorkbenchPart;
@@ -83,11 +86,9 @@
 import org.osgi.framework.Bundle;
 
 @SuppressWarnings("restriction")
-public abstract class AbstractScriptCompletionProposal
-		implements IScriptCompletionProposal, ICompletionProposalExtension,
-		ICompletionProposalExtension2, ICompletionProposalExtension3,
-		ICompletionProposalExtension5, ICompletionProposalExtension6,
-		ICompletionProposalExtension7 {
+public abstract class AbstractScriptCompletionProposal implements IScriptCompletionProposal,
+		ICompletionProposalExtension, ICompletionProposalExtension2, ICompletionProposalExtension3,
+		ICompletionProposalExtension5, ICompletionProposalExtension6, ICompletionProposalExtension7 {
 
 	/**
 	 * A class to simplify tracking a reference position in a document.
@@ -97,22 +98,18 @@
 		/** The reference position category name. */
 		private static final String CATEGORY = "reference_position"; //$NON-NLS-1$
 		/** The position updater of the reference position. */
-		private final IPositionUpdater fPositionUpdater = new DefaultPositionUpdater(
-				CATEGORY);
+		private final IPositionUpdater fPositionUpdater = new DefaultPositionUpdater(CATEGORY);
 		/** The reference position. */
 		private final Position fPosition = new Position(0);
 
 		/**
-		 * Called before document changes occur. It must be followed by a call
-		 * to postReplace().
+		 * Called before document changes occur. It must be followed by a call to
+		 * postReplace().
 		 *
-		 * @param document
-		 *                     the document on which to track the reference
-		 *                     position.
+		 * @param document the document on which to track the reference position.
 		 *
 		 */
-		public void preReplace(IDocument document, int offset)
-				throws BadLocationException {
+		public void preReplace(IDocument document, int offset) throws BadLocationException {
 			fPosition.setOffset(offset);
 			try {
 				document.addPositionCategory(CATEGORY);
@@ -126,12 +123,10 @@
 		}
 
 		/**
-		 * Called after the document changed occurred. It must be preceded by a
-		 * call to preReplace().
+		 * Called after the document changed occurred. It must be preceded by a call to
+		 * preReplace().
 		 *
-		 * @param document
-		 *                     the document on which to track the reference
-		 *                     position.
+		 * @param document the document on which to track the reference position.
 		 */
 		public int postReplace(IDocument document) {
 			try {
@@ -158,13 +153,11 @@
 		}
 
 		@Override
-		public ExitFlags doExit(LinkedModeModel environment, VerifyEvent event,
-				int offset, int length) {
+		public ExitFlags doExit(LinkedModeModel environment, VerifyEvent event, int offset, int length) {
 
 			if (event.character == fExitCharacter) {
 				if (environment.anyPositionContains(offset)) {
-					return new ExitFlags(ILinkedModeListener.UPDATE_CARET,
-							false);
+					return new ExitFlags(ILinkedModeListener.UPDATE_CARET, false);
 				}
 				return new ExitFlags(ILinkedModeListener.UPDATE_CARET, true);
 			}
@@ -179,8 +172,7 @@
 				if (offset > 0) {
 					try {
 						if (fDocument.getChar(offset - 1) == '{')
-							return new ExitFlags(ILinkedModeListener.EXIT_ALL,
-									true);
+							return new ExitFlags(ILinkedModeListener.EXIT_ALL, true);
 					} catch (BadLocationException e) {
 					}
 				}
@@ -198,6 +190,7 @@
 	private int fReplacementLength;
 	private int fCursorPosition;
 	private Image fImage;
+	private Supplier<Image> fImageFactory;
 	private IContextInformation fContextInformation;
 	private ICompletionProposalInfo fProposalInfo;
 	private char[] fTriggerCharacters;
@@ -231,9 +224,8 @@
 	/**
 	 * Sets the trigger characters.
 	 *
-	 * @param triggerCharacters
-	 *                              The set of characters which can trigger the
-	 *                              application of this completion proposal
+	 * @param triggerCharacters The set of characters which can trigger the
+	 *                          application of this completion proposal
 	 */
 	public void setTriggerCharacters(char[] triggerCharacters) {
 		fTriggerCharacters = triggerCharacters;
@@ -242,17 +234,15 @@
 	/**
 	 * Sets the proposal info.
 	 *
-	 * @param proposalInfo
-	 *                         The additional information associated with this
-	 *                         proposal or <code>null</code>
+	 * @param proposalInfo The additional information associated with this proposal
+	 *                     or <code>null</code>
 	 */
 	public void setProposalInfo(ICompletionProposalInfo proposalInfo) {
 		fProposalInfo = proposalInfo;
 	}
 
 	/**
-	 * Returns the additional proposal info, or <code>null</code> if none
-	 * exists.
+	 * Returns the additional proposal info, or <code>null</code> if none exists.
 	 *
 	 * @return the additional proposal info, or <code>null</code> if none exists
 	 */
@@ -261,12 +251,10 @@
 	}
 
 	/**
-	 * Sets the cursor position relative to the insertion offset. By default
-	 * this is the length of the completion string (Cursor positioned after the
-	 * completion)
+	 * Sets the cursor position relative to the insertion offset. By default this is
+	 * the length of the completion string (Cursor positioned after the completion)
 	 *
-	 * @param cursorPosition
-	 *                           The cursorPosition to set
+	 * @param cursorPosition The cursorPosition to set
 	 */
 	public void setCursorPosition(int cursorPosition) {
 		Assert.isTrue(cursorPosition >= 0);
@@ -280,16 +268,14 @@
 	@Override
 	public final void apply(IDocument document) {
 		// not used any longer
-		apply(document, (char) 0,
-				getReplacementOffset() + getReplacementLength());
+		apply(document, (char) 0, getReplacementOffset() + getReplacementLength());
 	}
 
 	@Override
 	public void apply(IDocument document, char trigger, int offset) {
 		try {
 			// patch replacement length
-			int delta = offset
-					- (getReplacementOffset() + getReplacementLength());
+			int delta = offset - (getReplacementOffset() + getReplacementLength());
 			if (delta > 0)
 				setReplacementLength(getReplacementLength() + delta);
 
@@ -301,18 +287,15 @@
 			String replacement = getReplacementString();
 
 			// reference position just at the end of the document change.
-			int referenceOffset = getReplacementOffset()
-					+ getReplacementLength();
+			int referenceOffset = getReplacementOffset() + getReplacementLength();
 			final ReferenceTracker referenceTracker = new ReferenceTracker();
 			referenceTracker.preReplace(document, referenceOffset);
 
-			replace(document, getReplacementOffset(), getReplacementLength(),
-					replacement);
+			replace(document, getReplacementOffset(), getReplacementLength(), replacement);
 			postReplace(document);
 
 			referenceOffset = referenceTracker.postReplace(document);
-			setReplacementOffset(referenceOffset
-					- (replacement == null ? 0 : replacement.length()));
+			setReplacementOffset(referenceOffset - (replacement == null ? 0 : replacement.length()));
 
 			// PR 47097
 			if (isSmartTrigger)
@@ -333,8 +316,7 @@
 		String replacement = getReplacementString();
 
 		// fix for PR #5533. Assumes that no eating takes place.
-		if (getCursorPosition() > 0
-				&& getCursorPosition() <= replacement.length()
+		if (getCursorPosition() > 0 && getCursorPosition() <= replacement.length()
 				&& replacement.charAt(getCursorPosition() - 1) != trigger) {
 			StringBuilder buffer = new StringBuilder(replacement);
 			buffer.insert(getCursorPosition(), trigger);
@@ -353,19 +335,18 @@
 	 * @param referenceOffset
 	 * @throws BadLocationException
 	 */
-	protected void handleSmartTrigger(IDocument document, char trigger,
-			int referenceOffset) throws BadLocationException {
+	protected void handleSmartTrigger(IDocument document, char trigger, int referenceOffset)
+			throws BadLocationException {
 	}
 
-	protected final void replace(IDocument document, int offset, int length,
-			String string) throws BadLocationException {
+	protected final void replace(IDocument document, int offset, int length, String string)
+			throws BadLocationException {
 		if (!document.get(offset, length).equals(string))
 			document.replace(offset, length, string);
 	}
 
 	@Override
-	public void apply(ITextViewer viewer, char trigger, int stateMask,
-			int offset) {
+	public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) {
 
 		IDocument document = viewer.getDocument();
 		if (fTextViewer == null)
@@ -400,11 +381,9 @@
 		fToggleEating = false;
 	}
 
-	protected void applyAutoClose(char trigger, IDocument document)
-			throws BadLocationException {
+	protected void applyAutoClose(char trigger, IDocument document) throws BadLocationException {
 		if (trigger == '(' && autocloseBrackets()) {
-			document.replace(getReplacementOffset() + getCursorPosition(), 0,
-					")"); //$NON-NLS-1$
+			document.replace(getReplacementOffset() + getCursorPosition(), 0, ")"); //$NON-NLS-1$
 			setUpLinkedMode(document, ')');
 		}
 	}
@@ -435,8 +414,7 @@
 	/**
 	 * Sets the javadoc attribute.
 	 *
-	 * @param isInDoc
-	 *                    <code>true</code> if the proposal is within javadoc
+	 * @param isInDoc <code>true</code> if the proposal is within javadoc
 	 */
 	protected void setInDoc(boolean isInDoc) {
 		fIsInDoc = isInDoc;
@@ -455,9 +433,8 @@
 	/**
 	 * Sets the context information.
 	 *
-	 * @param contextInformation
-	 *                               The context information associated with
-	 *                               this proposal
+	 * @param contextInformation The context information associated with this
+	 *                           proposal
 	 */
 	public void setContextInformation(IContextInformation contextInformation) {
 		fContextInformation = contextInformation;
@@ -486,32 +463,28 @@
 	}
 
 	@Override
-	public StyledString getStyledDisplayString(IDocument document, int offset,
-			BoldStylerProvider boldStylerProvider) {
+	public StyledString getStyledDisplayString(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();
-			boolean isJavadocTag = isInDoc() && displayString.charAt(0) == '@'
-					&& pattern.charAt(0) == '@';
+			boolean isJavadocTag = isInDoc() && displayString.charAt(0) == '@' && pattern.charAt(0) == '@';
 			if (isJavadocTag) {
 				displayString = displayString.substring(1);
 				pattern = pattern.substring(1);
 			}
 			int patternMatchRule = getPatternMatchRule(pattern, displayString);
-			int[] matchingRegions = SearchPattern.getMatchingRegions(pattern,
-					displayString, patternMatchRule);
+			int[] matchingRegions = SearchPattern.getMatchingRegions(pattern, displayString, patternMatchRule);
 			if (isJavadocTag && matchingRegions != null) {
-				Strings.markMatchingRegions(styledDisplayString, 0,
-						new int[] { 0, 1 }, boldStylerProvider.getBoldStyler());
+				Strings.markMatchingRegions(styledDisplayString, 0, new int[] { 0, 1 },
+						boldStylerProvider.getBoldStyler());
 				for (int i = 0; i < matchingRegions.length; i += 2) {
 					matchingRegions[i]++;
 				}
 			}
-			Strings.markMatchingRegions(styledDisplayString, 0, matchingRegions,
-					boldStylerProvider.getBoldStyler());
+			Strings.markMatchingRegions(styledDisplayString, 0, matchingRegions, boldStylerProvider.getBoldStyler());
 		}
 		return styledDisplayString;
 	}
@@ -523,25 +496,21 @@
 		} catch (StringIndexOutOfBoundsException e) {
 			String message = "Error retrieving proposal text.\nDisplay string:\n" //$NON-NLS-1$
 					+ string + "\nPattern:\n" + pattern; //$NON-NLS-1$
-			DLTKUIPlugin.log(new Status(IStatus.ERROR,
-					DLTKUIPlugin.getPluginId(), IStatus.OK, message, e));
+			DLTKUIPlugin.log(new Status(IStatus.ERROR, DLTKUIPlugin.getPluginId(), IStatus.OK, message, e));
 			return -1;
 		}
 		if (start.equalsIgnoreCase(pattern)) {
 			return SearchPattern.R_PREFIX_MATCH;
-		} else if (isCamelCaseMatching() && CharOperation
-				.camelCaseMatch(pattern.toCharArray(), string.toCharArray())) {
+		} else if (isCamelCaseMatching() && CharOperation.camelCaseMatch(pattern.toCharArray(), string.toCharArray())) {
 			return SearchPattern.R_CAMELCASE_MATCH;
-		} else if (isSubstringMatching() && CharOperation
-				.substringMatch(pattern.toCharArray(), string.toCharArray())) {
+		} else if (isSubstringMatching() && CharOperation.substringMatch(pattern.toCharArray(), string.toCharArray())) {
 			return SearchPattern.R_SUBSTRING_MATCH;
 		} else {
 			return -1;
 		}
 	}
 
-	protected String getPatternToEmphasizeMatch(IDocument document,
-			int offset) {
+	protected String getPatternToEmphasizeMatch(IDocument document, int offset) {
 		int start = getPrefixCompletionStart(document, offset);
 		int patternLength = offset - start;
 		String pattern = null;
@@ -565,8 +534,7 @@
 
 	@Override
 	public String getAdditionalProposalInfo() {
-		final Object info = getAdditionalProposalInfo(
-				new NullProgressMonitor());
+		final Object info = getAdditionalProposalInfo(new NullProgressMonitor());
 		return info != null ? info.toString() : null;
 	}
 
@@ -598,8 +566,7 @@
 			if (url != null) {
 				try {
 					url = FileLocator.toFileURL(url);
-					BufferedReader reader = new BufferedReader(
-							new InputStreamReader(url.openStream()));
+					BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
 					StringBuffer buffer = new StringBuffer(200);
 					String line = reader.readLine();
 					while (line != null) {
@@ -615,8 +582,8 @@
 		}
 		String css = fgCSSStyles;
 		if (css != null) {
-			FontData fontData = JFaceResources.getFontRegistry().getFontData(
-					PreferenceConstants.APPEARANCE_DOCUMENTATION_FONT)[0];
+			FontData fontData = JFaceResources.getFontRegistry()
+					.getFontData(PreferenceConstants.APPEARANCE_DOCUMENTATION_FONT)[0];
 			css = HTMLPrinter.convertTopLevelFont(css, fontData);
 		}
 		return css;
@@ -641,8 +608,7 @@
 	/**
 	 * Sets the replacement offset.
 	 *
-	 * @param replacementOffset
-	 *                              The replacement offset to set
+	 * @param replacementOffset The replacement offset to set
 	 */
 	public void setReplacementOffset(int replacementOffset) {
 		Assert.isTrue(replacementOffset >= 0);
@@ -650,8 +616,7 @@
 	}
 
 	@Override
-	public int getPrefixCompletionStart(IDocument document,
-			int completionOffset) {
+	public int getPrefixCompletionStart(IDocument document, int completionOffset) {
 		return getReplacementOffset();
 	}
 
@@ -667,8 +632,7 @@
 	/**
 	 * Sets the replacement length.
 	 *
-	 * @param replacementLength
-	 *                              The replacementLength to set
+	 * @param replacementLength The replacementLength to set
 	 */
 	public void setReplacementLength(int replacementLength) {
 		Assert.isTrue(replacementLength >= 0);
@@ -687,8 +651,7 @@
 	/**
 	 * Sets the replacement string.
 	 *
-	 * @param replacementString
-	 *                              The replacement string to set
+	 * @param replacementString The replacement string to set
 	 */
 	public void setReplacementString(String replacementString) {
 		Assert.isNotNull(replacementString);
@@ -696,8 +659,7 @@
 	}
 
 	@Override
-	public CharSequence getPrefixCompletionText(IDocument document,
-			int completionOffset) {
+	public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
 		if (!isCamelCaseMatching())
 			return getReplacementString();
 
@@ -707,27 +669,36 @@
 
 	@Override
 	public Image getImage() {
+		if (fImage == null && fImageFactory != null) {
+			setImage(fImageFactory.get());
+		}
 		return fImage;
 	}
 
 	/**
 	 * Sets the image.
 	 *
-	 * @param image
-	 *                  The image to set
+	 * @param image The image to set
 	 */
 	public void setImage(Image image) {
 		fImage = image;
 	}
 
+	public void setImageFactory(Supplier<Image> factory) {
+		fImageFactory = factory;
+	}
+
+	public Supplier<Image> getImageFactory() {
+		return fImageFactory;
+	}
+
 	@Override
 	public boolean isValidFor(IDocument document, int offset) {
 		return validate(document, offset, null);
 	}
 
 	@Override
-	public boolean validate(IDocument document, int offset,
-			DocumentEvent event) {
+	public boolean validate(IDocument document, int offset, DocumentEvent event) {
 
 		if (offset < getReplacementOffset())
 			return false;
@@ -736,8 +707,7 @@
 
 		if (validated && event != null) {
 			// adapt replacement range to document change
-			int delta = (event.fText == null ? 0 : event.fText.length())
-					- event.fLength;
+			int delta = (event.fText == null ? 0 : event.fText.length()) - event.fLength;
 			final int newLength = Math.max(getReplacementLength() + delta, 0);
 			setReplacementLength(newLength);
 		}
@@ -747,26 +717,25 @@
 
 	/**
 	 * 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 proposal is still valid.
+	 * 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
+	 * proposal is still valid.
 	 * <p>
-	 * The default implementation checks if <code>prefix</code> is a prefix of
-	 * the proposal's {@link #getDisplayString() display string} using the
+	 * The default implementation checks if <code>prefix</code> is a prefix of 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 prefix the current prefix in the document
+	 * @return <code>true</code> if <code>prefix</code> is a valid prefix of this
+	 *         proposal
 	 */
 	protected boolean isValidPrefix(String prefix) {
 		/*
-		 * See http://dev.eclipse.org/bugs/show_bug.cgi?id=17667 why we do not
-		 * use the replacement string. String word= fReplacementString;
+		 * See http://dev.eclipse.org/bugs/show_bug.cgi?id=17667 why we do not use the
+		 * replacement string. String word= fReplacementString;
 		 */
 		return isPrefix(prefix, TextProcessor.deprocess(getDisplayString()));
 	}
@@ -787,8 +756,7 @@
 	/**
 	 * Sets the proposal's relevance.
 	 *
-	 * @param relevance
-	 *                      The relevance to set
+	 * @param relevance The relevance to set
 	 */
 	public void setRelevance(int relevance) {
 		fRelevance = relevance;
@@ -820,8 +788,7 @@
 	 *
 	 */
 	protected boolean isPrefix(String prefix, String string) {
-		if (prefix == null || string == null
-				|| prefix.length() > string.length())
+		if (prefix == null || string == null || prefix.length() > string.length())
 			return false;
 		fPatternMatchRule = getPatternMatchRule(prefix, string);
 		return fPatternMatchRule != -1;
@@ -829,23 +796,19 @@
 
 	/**
 	 * Matches <code>prefix</code> against <code>string</code> and replaces the
-	 * matched region by prefix. Case is preserved as much as possible. This
-	 * method returns <code>string</code> if camel case completion is disabled.
-	 * Examples when camel case completion is enabled:
+	 * matched region by prefix. Case is preserved as much as possible. This method
+	 * returns <code>string</code> if camel case completion is disabled. Examples
+	 * when camel case completion is enabled:
 	 * <ul>
 	 * <li>getCamelCompound("NuPo", "NullPointerException") ->
 	 * "NuPointerException"</li>
-	 * <li>getCamelCompound("NuPoE", "NullPointerException") ->
-	 * "NuPoException"</li>
+	 * <li>getCamelCompound("NuPoE", "NullPointerException") -> "NuPoException"</li>
 	 * <li>getCamelCompound("hasCod", "hashCode") -> "hasCode"</li>
 	 * </ul>
 	 *
-	 * @param prefix
-	 *                   the prefix to match against
-	 * @param string
-	 *                   the string to match
-	 * @return a compound of prefix and any postfix taken from
-	 *         <code>string</code>
+	 * @param prefix the prefix to match against
+	 * @param string the string to match
+	 * @return a compound of prefix and any postfix taken from <code>string</code>
 	 *
 	 */
 	protected final String getCamelCaseCompound(String prefix, String string) {
@@ -861,8 +824,7 @@
 		final char[] stringChars = string.toCharArray();
 
 		for (int i = 1; i <= stringChars.length; i++)
-			if (CharOperation.camelCaseMatch(patternChars, 0,
-					patternChars.length, stringChars, 0, i))
+			if (CharOperation.camelCaseMatch(patternChars, 0, patternChars.length, stringChars, 0, i))
 				return prefix + string.substring(i);
 
 		// Not a camel case match at all.
@@ -883,8 +845,7 @@
 	}
 
 	protected boolean insertCompletion() {
-		return getPreferenceStore()
-				.getBoolean(PreferenceConstants.CODEASSIST_INSERT_COMPLETION);
+		return getPreferenceStore().getBoolean(PreferenceConstants.CODEASSIST_INSERT_COMPLETION);
 	}
 
 	protected Color getForegroundColor(StyledText text) {
@@ -922,16 +883,13 @@
 
 					ITextViewerExtension5 extension = (ITextViewerExtension5) viewer;
 					IRegion modelRange = extension.widgetRange2ModelRange(
-							new Region(fRememberedStyleRange.start,
-									fRememberedStyleRange.length));
+							new Region(fRememberedStyleRange.start, fRememberedStyleRange.length));
 					if (modelRange != null)
-						viewer2.invalidateTextPresentation(
-								modelRange.getOffset(), modelRange.getLength());
+						viewer2.invalidateTextPresentation(modelRange.getOffset(), modelRange.getLength());
 
 				} else {
 					viewer2.invalidateTextPresentation(
-							fRememberedStyleRange.start
-									+ viewer.getVisibleRegion().getOffset(),
+							fRememberedStyleRange.start + viewer.getVisibleRegion().getOffset(),
 							fRememberedStyleRange.length);
 				}
 
@@ -963,8 +921,7 @@
 		}
 
 		int offset = widgetCaret;
-		int length = getReplacementOffset() + getReplacementLength()
-				- modelCaret;
+		int length = getReplacementOffset() + getReplacementLength() - modelCaret;
 
 		Color foreground = getForegroundColor(text);
 		Color background = getBackgroundColor(text);
@@ -973,8 +930,7 @@
 		int fontStyle = range != null ? range.fontStyle : SWT.NORMAL;
 
 		repairPresentation(viewer);
-		fRememberedStyleRange = new StyleRange(offset, length, foreground,
-				background, fontStyle);
+		fRememberedStyleRange = new StyleRange(offset, length, foreground, background, fontStyle);
 		if (range != null) {
 			fRememberedStyleRange.strikeout = range.strikeout;
 			fRememberedStyleRange.underline = range.underline;
@@ -1014,8 +970,7 @@
 		if (fCreator == null) {
 			DocumentationHover.PresenterControlCreator presenterControlCreator = new DocumentationHover.PresenterControlCreator(
 					getSite());
-			fCreator = new DocumentationHover.HoverControlCreator(
-					presenterControlCreator, true);
+			fCreator = new DocumentationHover.HoverControlCreator(presenterControlCreator, true);
 		}
 		return fCreator;
 	}
@@ -1048,13 +1003,11 @@
 
 	/**
 	 * Sets up a simple linked mode at {@link #getCursorPosition()} and an exit
-	 * policy that will exit the mode when <code>closingCharacter</code> is
-	 * typed and an exit position at <code>getCursorPosition() + 1</code>.
+	 * policy that will exit the mode when <code>closingCharacter</code> is typed
+	 * and an exit position at <code>getCursorPosition() + 1</code>.
 	 *
-	 * @param document
-	 *                             the document
-	 * @param closingCharacter
-	 *                             the exit character
+	 * @param document         the document
+	 * @param closingCharacter the exit character
 	 */
 	protected void setUpLinkedMode(IDocument document, char closingCharacter) {
 		if (getTextViewer() != null && autocloseBrackets()) {
@@ -1062,15 +1015,13 @@
 			int exit = getReplacementOffset() + getReplacementString().length();
 			try {
 				LinkedPositionGroup group = new LinkedPositionGroup();
-				group.addPosition(new LinkedPosition(document, offset, 0,
-						LinkedPositionGroup.NO_STOP));
+				group.addPosition(new LinkedPosition(document, offset, 0, LinkedPositionGroup.NO_STOP));
 
 				LinkedModeModel model = new LinkedModeModel();
 				model.addGroup(group);
 				model.forceInstall();
 
-				LinkedModeUI ui = new EditorLinkedModeUI(model,
-						getTextViewer());
+				LinkedModeUI ui = new EditorLinkedModeUI(model, getTextViewer());
 				ui.setSimpleMode(true);
 				ui.setExitPolicy(new ExitPolicy(closingCharacter, document));
 				ui.setExitPosition(getTextViewer(), exit, 0, Integer.MAX_VALUE);
@@ -1083,8 +1034,7 @@
 	}
 
 	protected boolean autocloseBrackets() {
-		return getPreferenceStore()
-				.getBoolean(PreferenceConstants.EDITOR_CLOSE_BRACKETS);
+		return getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_CLOSE_BRACKETS);
 	}
 
 	protected void setDisplayString(String string) {
@@ -1118,8 +1068,7 @@
 	/**
 	 * Returns a deep copy of the given styles string.
 	 */
-	public static StyledString copyStyledString(
-			final StyledString displayString) {
+	public static StyledString copyStyledString(final StyledString displayString) {
 		final StyledString copy = new StyledString(displayString.getString());
 		for (final StyleRange range : displayString.getStyleRanges()) {
 			copy.setStyle(range.start, range.length, new Styler() {
@@ -1136,4 +1085,18 @@
 		}
 		return copy;
 	}
+
+	protected ITextSelection getTextSelection(ITextViewer viewer) {
+		final ITextSelection[] selection = new ITextSelection[1];
+		Runnable getSelection = () -> {
+			selection[0] = (ITextSelection) viewer.getSelectionProvider().getSelection();
+		};
+		if (Display.getCurrent() != null) {
+			getSelection.run();
+		} else {
+			Display.getDefault().syncExec(getSelection);
+		}
+
+		return selection[0];
+	}
 }
diff --git a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/CompletionProposalComputerRegistry.java b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/CompletionProposalComputerRegistry.java
index d5434e1..7827a31 100644
--- a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/CompletionProposalComputerRegistry.java
+++ b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/CompletionProposalComputerRegistry.java
@@ -39,6 +39,7 @@
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Link;
 import org.eclipse.ui.dialogs.PreferencesUtil;
 
@@ -66,21 +67,19 @@
 	}
 
 	/**
-	 * The sets of descriptors, grouped by partition type (key type:
-	 * {@link String}, value type: {@linkplain List
+	 * The sets of descriptors, grouped by partition type (key type: {@link String},
+	 * value type: {@linkplain List
 	 * List&lt;CompletionProposalComputerDescriptor&gt;}).
 	 */
 	private final Map<String, List<CompletionProposalComputerDescriptor>> fDescriptorsByPartition = new HashMap<>();
 	/**
 	 * Unmodifiable versions of the sets stored in
-	 * <code>fDescriptorsByPartition</code> (key type: {@link String}, value
-	 * type: {@linkplain List List&lt;CompletionProposalComputerDescriptor&gt;}
-	 * ).
+	 * <code>fDescriptorsByPartition</code> (key type: {@link String}, value type:
+	 * {@linkplain List List&lt;CompletionProposalComputerDescriptor&gt;} ).
 	 */
 	private final Map<String, List<CompletionProposalComputerDescriptor>> fPublicDescriptorsByPartition = new HashMap<>();
 	/**
-	 * All descriptors (element type:
-	 * {@link CompletionProposalComputerDescriptor}).
+	 * All descriptors (element type: {@link CompletionProposalComputerDescriptor}).
 	 */
 	private final List<CompletionProposalComputerDescriptor> fDescriptors = new ArrayList<>();
 	/**
@@ -90,8 +89,7 @@
 			.unmodifiableList(fDescriptors);
 
 	private final List<CompletionProposalCategory> fCategories = new ArrayList<>();
-	private final List<CompletionProposalCategory> fPublicCategories = Collections
-			.unmodifiableList(fCategories);
+	private final List<CompletionProposalCategory> fPublicCategories = Collections.unmodifiableList(fCategories);
 	/**
 	 * <code>true</code> if this registry has been loaded.
 	 */
@@ -104,62 +102,54 @@
 	}
 
 	/**
-	 * Returns the list of {@link CompletionProposalComputerDescriptor}s
-	 * describing all extensions to the
-	 * <code>javaCompletionProposalComputer</code> extension point for the given
-	 * partition type.
+	 * Returns the list of {@link CompletionProposalComputerDescriptor}s describing
+	 * all extensions to the <code>javaCompletionProposalComputer</code> extension
+	 * point for the given partition type.
 	 * <p>
 	 * A valid partition is either one of the constants defined in
 	 * {@link org.eclipse.dltk.ui.text.IJavaPartitions} or
-	 * {@link org.eclipse.jface.text.IDocument#DEFAULT_CONTENT_TYPE}. An empty
-	 * list is returned if there are no extensions for the given partition.
+	 * {@link org.eclipse.jface.text.IDocument#DEFAULT_CONTENT_TYPE}. An empty list
+	 * is returned if there are no extensions for the given partition.
 	 * </p>
 	 * <p>
-	 * The returned list is read-only and is sorted in the order that the
-	 * extensions were read in. There are no duplicate elements in the returned
-	 * list. The returned list may change if plug-ins are loaded or unloaded
-	 * while the application is running or if an extension violates the API
-	 * contract of
-	 * {@link org.eclipse.dltk.ui.text.java.IScriptCompletionProposalComputer}.
-	 * When computing proposals, it is therefore imperative to copy the returned
-	 * list before iterating over it.
+	 * The returned list is read-only and is sorted in the order that the extensions
+	 * were read in. There are no duplicate elements in the returned list. The
+	 * returned list may change if plug-ins are loaded or unloaded while the
+	 * application is running or if an extension violates the API contract of
+	 * {@link org.eclipse.dltk.ui.text.java.IScriptCompletionProposalComputer}. When
+	 * computing proposals, it is therefore imperative to copy the returned list
+	 * before iterating over it.
 	 * </p>
 	 *
-	 * @param partition
-	 *            the partition type for which to retrieve the computer
-	 *            descriptors
+	 * @param partition the partition type for which to retrieve the computer
+	 *                  descriptors
 	 * @return the list of extensions to the
-	 *         <code>javaCompletionProposalComputer</code> extension point
-	 *         (element type: {@link CompletionProposalComputerDescriptor})
+	 *         <code>javaCompletionProposalComputer</code> extension point (element
+	 *         type: {@link CompletionProposalComputerDescriptor})
 	 */
-	List<CompletionProposalComputerDescriptor> getProposalComputerDescriptors(
-			String partition) {
+	List<CompletionProposalComputerDescriptor> getProposalComputerDescriptors(String partition) {
 		ensureExtensionPointRead();
-		List<CompletionProposalComputerDescriptor> result = fPublicDescriptorsByPartition
-				.get(partition);
-		return result != null ? result
-				: Collections
-						.<CompletionProposalComputerDescriptor> emptyList();
+		List<CompletionProposalComputerDescriptor> result = fPublicDescriptorsByPartition.get(partition);
+		return result != null ? result : Collections.<CompletionProposalComputerDescriptor>emptyList();
 	}
 
 	/**
-	 * Returns the list of {@link CompletionProposalComputerDescriptor}s
-	 * describing all extensions to the
-	 * <code>javaCompletionProposalComputer</code> extension point.
+	 * Returns the list of {@link CompletionProposalComputerDescriptor}s describing
+	 * all extensions to the <code>javaCompletionProposalComputer</code> extension
+	 * point.
 	 * <p>
-	 * The returned list is read-only and is sorted in the order that the
-	 * extensions were read in. There are no duplicate elements in the returned
-	 * list. The returned list may change if plug-ins are loaded or unloaded
-	 * while the application is running or if an extension violates the API
-	 * contract of
-	 * {@link org.eclipse.dltk.ui.text.java.IScriptCompletionProposalComputer}.
-	 * When computing proposals, it is therefore imperative to copy the returned
-	 * list before iterating over it.
+	 * The returned list is read-only and is sorted in the order that the extensions
+	 * were read in. There are no duplicate elements in the returned list. The
+	 * returned list may change if plug-ins are loaded or unloaded while the
+	 * application is running or if an extension violates the API contract of
+	 * {@link org.eclipse.dltk.ui.text.java.IScriptCompletionProposalComputer}. When
+	 * computing proposals, it is therefore imperative to copy the returned list
+	 * before iterating over it.
 	 * </p>
 	 *
 	 * @return the list of extensions to the
-	 *         <code>javaCompletionProposalComputer</code> extension point
-	 *         (element type: {@link CompletionProposalComputerDescriptor})
+	 *         <code>javaCompletionProposalComputer</code> extension point (element
+	 *         type: {@link CompletionProposalComputerDescriptor})
 	 */
 	List<CompletionProposalComputerDescriptor> getProposalComputerDescriptors() {
 		ensureExtensionPointRead();
@@ -171,15 +161,15 @@
 	 * <code>javaCompletionProposalComputer</code> extension point.
 	 * <p>
 	 * <p>
-	 * The returned list is read-only and is sorted in the order that the
-	 * extensions were read in. There are no duplicate elements in the returned
-	 * list. The returned list may change if plug-ins are loaded or unloaded
-	 * while the application is running.
+	 * The returned list is read-only and is sorted in the order that the extensions
+	 * were read in. There are no duplicate elements in the returned list. The
+	 * returned list may change if plug-ins are loaded or unloaded while the
+	 * application is running.
 	 * </p>
 	 *
 	 * @return list of proposal categories contributed to the
-	 *         <code>javaCompletionProposalComputer</code> extension point
-	 *         (element type: {@link CompletionProposalCategory})
+	 *         <code>javaCompletionProposalComputer</code> extension point (element
+	 *         type: {@link CompletionProposalCategory})
 	 */
 	public List<CompletionProposalCategory> getProposalCategories() {
 		ensureExtensionPointRead();
@@ -203,30 +193,27 @@
 	/**
 	 * Reloads the extensions to the extension point.
 	 * <p>
-	 * This method can be called more than once in order to reload from a
-	 * changed extension registry.
+	 * This method can be called more than once in order to reload from a changed
+	 * extension registry.
 	 * </p>
 	 */
 	public void reload() {
 		IExtensionRegistry registry = Platform.getExtensionRegistry();
 		List<IConfigurationElement> elements = new ArrayList<>(
-				Arrays.asList(registry.getConfigurationElementsFor(
-						DLTKUIPlugin.getPluginId(), EXTENSION_POINT)));
+				Arrays.asList(registry.getConfigurationElementsFor(DLTKUIPlugin.getPluginId(), EXTENSION_POINT)));
 
 		Map<String, List<CompletionProposalComputerDescriptor>> map = new HashMap<>();
 		List<CompletionProposalComputerDescriptor> all = new ArrayList<>();
 
 		List<CompletionProposalCategory> categories = getCategories(elements);
-		for (Iterator<IConfigurationElement> iter = elements.iterator(); iter
-				.hasNext();) {
+		for (Iterator<IConfigurationElement> iter = elements.iterator(); iter.hasNext();) {
 			IConfigurationElement element = iter.next();
 			try {
-				CompletionProposalComputerDescriptor desc = new CompletionProposalComputerDescriptor(
-						element, this, categories);
+				CompletionProposalComputerDescriptor desc = new CompletionProposalComputerDescriptor(element, this,
+						categories);
 				final Set<String> partitions = desc.getPartitions();
 				for (String partition : partitions) {
-					List<CompletionProposalComputerDescriptor> list = map
-							.get(partition);
+					List<CompletionProposalComputerDescriptor> list = map.get(partition);
 					if (list == null) {
 						list = new ArrayList<>();
 						map.put(partition, list);
@@ -237,16 +224,14 @@
 
 			} catch (InvalidRegistryObjectException x) {
 				/*
-				 * Element is not valid any longer as the contributing plug-in
-				 * was unloaded or for some other reason. Do not include the
-				 * extension in the list and inform the user about it.
+				 * Element is not valid any longer as the contributing plug-in was unloaded or
+				 * for some other reason. Do not include the extension in the list and inform
+				 * the user about it.
 				 */
 				Object[] args = { element.toString() };
-				String message = Messages.format(
-						ScriptTextMessages.CompletionProposalComputerRegistry_invalid_message,
+				String message = Messages.format(ScriptTextMessages.CompletionProposalComputerRegistry_invalid_message,
 						args);
-				IStatus status = new Status(IStatus.WARNING,
-						DLTKUIPlugin.getPluginId(), IStatus.OK, message, x);
+				IStatus status = new Status(IStatus.WARNING, DLTKUIPlugin.getPluginId(), IStatus.OK, message, x);
 				informUser(status);
 			}
 		}
@@ -260,17 +245,14 @@
 			fPublicDescriptorsByPartition.keySet().retainAll(partitions);
 			for (Iterator<String> it = partitions.iterator(); it.hasNext();) {
 				String partition = it.next();
-				List<CompletionProposalComputerDescriptor> old = fDescriptorsByPartition
-						.get(partition);
-				List<CompletionProposalComputerDescriptor> current = map
-						.get(partition);
+				List<CompletionProposalComputerDescriptor> old = fDescriptorsByPartition.get(partition);
+				List<CompletionProposalComputerDescriptor> current = map.get(partition);
 				if (old != null) {
 					old.clear();
 					old.addAll(current);
 				} else {
 					fDescriptorsByPartition.put(partition, current);
-					fPublicDescriptorsByPartition.put(partition,
-							Collections.unmodifiableList(current));
+					fPublicDescriptorsByPartition.put(partition, Collections.unmodifiableList(current));
 				}
 			}
 
@@ -279,18 +261,15 @@
 		}
 	}
 
-	private List<CompletionProposalCategory> getCategories(
-			List<IConfigurationElement> elements) {
+	private List<CompletionProposalCategory> getCategories(List<IConfigurationElement> elements) {
 		IPreferenceStore store = DLTKUIPlugin.getDefault().getPreferenceStore();
-		String preference = store
-				.getString(PreferenceConstants.CODEASSIST_EXCLUDED_CATEGORIES);
+		String preference = store.getString(PreferenceConstants.CODEASSIST_EXCLUDED_CATEGORIES);
 		Set<String> disabled = new HashSet<>();
 		StringTokenizer tok = new StringTokenizer(preference, "\0"); //$NON-NLS-1$
 		while (tok.hasMoreTokens())
 			disabled.add(tok.nextToken());
 		Map<String, Integer> ordered = new HashMap<>();
-		preference = store
-				.getString(PreferenceConstants.CODEASSIST_CATEGORY_ORDER);
+		preference = store.getString(PreferenceConstants.CODEASSIST_CATEGORY_ORDER);
 		tok = new StringTokenizer(preference, "\0"); //$NON-NLS-1$
 		while (tok.hasMoreTokens()) {
 			StringTokenizer inner = new StringTokenizer(tok.nextToken(), ":"); //$NON-NLS-1$
@@ -300,15 +279,13 @@
 		}
 
 		List<CompletionProposalCategory> categories = new ArrayList<>();
-		for (Iterator<IConfigurationElement> iter = elements.iterator(); iter
-				.hasNext();) {
+		for (Iterator<IConfigurationElement> iter = elements.iterator(); iter.hasNext();) {
 			IConfigurationElement element = iter.next();
 			try {
 				if (element.getName().equals("proposalCategory")) { //$NON-NLS-1$
 					iter.remove(); // remove from list to leave only computers
 
-					CompletionProposalCategory category = new CompletionProposalCategory(
-							element, this);
+					CompletionProposalCategory category = new CompletionProposalCategory(element, this);
 					categories.add(category);
 					category.setIncluded(!disabled.contains(category.getId()));
 					Integer rank = ordered.get(category.getId());
@@ -321,16 +298,14 @@
 				}
 			} catch (InvalidRegistryObjectException x) {
 				/*
-				 * Element is not valid any longer as the contributing plug-in
-				 * was unloaded or for some other reason. Do not include the
-				 * extension in the list and inform the user about it.
+				 * Element is not valid any longer as the contributing plug-in was unloaded or
+				 * for some other reason. Do not include the extension in the list and inform
+				 * the user about it.
 				 */
 				Object[] args = { element.toString() };
-				String message = Messages.format(
-						ScriptTextMessages.CompletionProposalComputerRegistry_invalid_message,
+				String message = Messages.format(ScriptTextMessages.CompletionProposalComputerRegistry_invalid_message,
 						args);
-				IStatus status = new Status(IStatus.WARNING,
-						DLTKUIPlugin.getPluginId(), IStatus.OK, message, x);
+				IStatus status = new Status(IStatus.WARNING, DLTKUIPlugin.getPluginId(), IStatus.OK, message, x);
 				informUser(status);
 			}
 		}
@@ -340,76 +315,72 @@
 	/**
 	 * Log the status and inform the user about a misbehaving extension.
 	 *
-	 * @param descriptor
-	 *            the descriptor of the misbehaving extension
-	 * @param status
-	 *            a status object that will be logged
+	 * @param descriptor the descriptor of the misbehaving extension
+	 * @param status     a status object that will be logged
 	 */
-	void informUser(CompletionProposalComputerDescriptor descriptor,
-			IStatus status) {
+	void informUser(CompletionProposalComputerDescriptor descriptor, IStatus status) {
 		DLTKUIPlugin.log(status);
 		String title = ScriptTextMessages.CompletionProposalComputerRegistry_error_dialog_title;
 		CompletionProposalCategory category = descriptor.getCategory();
 		IContributor culprit = descriptor.getContributor();
-		Set<String> affectedPlugins = getAffectedContributors(category,
-				culprit);
+		Set<String> affectedPlugins = getAffectedContributors(category, culprit);
 
 		final String avoidHint;
 		final String culpritName = culprit == null ? null : culprit.getName();
 		if (affectedPlugins.isEmpty())
-			avoidHint = Messages.format(
-					ScriptTextMessages.CompletionProposalComputerRegistry_messageAvoidanceHint,
+			avoidHint = Messages.format(ScriptTextMessages.CompletionProposalComputerRegistry_messageAvoidanceHint,
 					new Object[] { culpritName, category.getDisplayName() });
 		else
 			avoidHint = Messages.format(
 					ScriptTextMessages.CompletionProposalComputerRegistry_messageAvoidanceHintWithWarning,
-					new Object[] { culpritName, category.getDisplayName(),
-							toString(affectedPlugins) });
+					new Object[] { culpritName, category.getDisplayName(), toString(affectedPlugins) });
 
 		String message = status.getMessage();
 		// inlined from MessageDialog.openError
-		MessageDialog dialog = new MessageDialog(
-				DLTKUIPlugin.getActiveWorkbenchShell(), title,
-				null /* default image */, message, MessageDialog.ERROR,
-				new String[] { IDialogConstants.OK_LABEL }, 0) {
-			@Override
-			protected Control createCustomArea(Composite parent) {
-				Link link = new Link(parent, SWT.NONE);
-				link.setText(avoidHint);
-				link.addSelectionListener(new SelectionAdapter() {
-					@Override
-					public void widgetSelected(SelectionEvent e) {
-						PreferencesUtil.createPreferenceDialogOn(getShell(),
-								"org.eclipse.dltk.ui.preferences.CodeAssistPreferenceAdvanced", //$NON-NLS-1$
-								null, null).open();
-					}
-				});
-				GridData gridData = new GridData(SWT.FILL, SWT.BEGINNING, true,
-						false);
-				gridData.widthHint = this.getMinimumMessageWidth();
-				link.setLayoutData(gridData);
-				return link;
-			}
+		Runnable openPopup = () -> {
+			MessageDialog dialog = new MessageDialog(DLTKUIPlugin.getActiveWorkbenchShell(), title,
+					null /* default image */, message, MessageDialog.ERROR, new String[] { IDialogConstants.OK_LABEL },
+					0) {
+				@Override
+				protected Control createCustomArea(Composite parent) {
+					Link link = new Link(parent, SWT.NONE);
+					link.setText(avoidHint);
+					link.addSelectionListener(new SelectionAdapter() {
+						@Override
+						public void widgetSelected(SelectionEvent e) {
+							PreferencesUtil.createPreferenceDialogOn(getShell(),
+									"org.eclipse.dltk.ui.preferences.CodeAssistPreferenceAdvanced", //$NON-NLS-1$
+									null, null).open();
+						}
+					});
+					GridData gridData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
+					gridData.widthHint = this.getMinimumMessageWidth();
+					link.setLayoutData(gridData);
+					return link;
+				}
+			};
+			dialog.open();
 		};
-		dialog.open();
+		if (Display.getCurrent() != null) {
+			openPopup.run();
+		} else {
+			Display.getDefault().syncExec(openPopup);
+		}
 	}
 
 	/**
 	 * Returns the names of contributors affected by disabling a category.
 	 *
-	 * @param category
-	 *            the category that would be disabled
-	 * @param culprit
-	 *            the cuprit plug-in, which is not included in the returned list
-	 * @return the names of the contributors other than <code>culprit</code>
-	 *         that contribute to <code>category</code> (element type:
-	 *         {@link String})
+	 * @param category the category that would be disabled
+	 * @param culprit  the cuprit plug-in, which is not included in the returned
+	 *                 list
+	 * @return the names of the contributors other than <code>culprit</code> that
+	 *         contribute to <code>category</code> (element type: {@link String})
 	 */
-	private Set<String> getAffectedContributors(
-			CompletionProposalCategory category, IContributor culprit) {
+	private Set<String> getAffectedContributors(CompletionProposalCategory category, IContributor culprit) {
 		Set<String> affectedPlugins = new HashSet<>();
-		for (Iterator<CompletionProposalComputerDescriptor> it = getProposalComputerDescriptors()
-				.iterator(); it.hasNext();) {
+		for (Iterator<CompletionProposalComputerDescriptor> it = getProposalComputerDescriptors().iterator(); it
+				.hasNext();) {
 			CompletionProposalComputerDescriptor desc = it.next();
 			CompletionProposalCategory cat = desc.getCategory();
 			if (cat.equals(category)) {
@@ -431,7 +402,6 @@
 		DLTKUIPlugin.log(status);
 		String title = ScriptTextMessages.CompletionProposalComputerRegistry_error_dialog_title;
 		String message = status.getMessage();
-		MessageDialog.openError(DLTKUIPlugin.getActiveWorkbenchShell(), title,
-				message);
+		MessageDialog.openError(DLTKUIPlugin.getActiveWorkbenchShell(), title, message);
 	}
 }
diff --git a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ContentAssistProcessor.java b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ContentAssistProcessor.java
index 6252472..921f63d 100644
--- a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ContentAssistProcessor.java
+++ b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ContentAssistProcessor.java
@@ -20,6 +20,7 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.core.runtime.SubProgressMonitor;
 import org.eclipse.dltk.internal.corext.util.Messages;
 import org.eclipse.dltk.internal.ui.DLTKUIMessages;
@@ -54,6 +55,7 @@
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Link;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.PlatformUI;
@@ -264,7 +266,7 @@
 		List<CompletionProposalCategory> providers = getCategories();
 		for (CompletionProposalCategory cat : providers) {
 			List<ICompletionProposal> computed = cat.computeCompletionProposals(context, fPartition,
-					new SubProgressMonitor(monitor, 1));
+					SubMonitor.convert(monitor, 1));
 			proposalSet.addAll(computed);
 			if (fErrorMessage == null) {
 				fErrorMessage = cat.getErrorMessage();
@@ -411,8 +413,18 @@
 		}
 
 		int iteration = fRepetition % fCategoryIteration.size();
-		fAssistant.setStatusMessage(createIterationMessage());
-		fAssistant.setEmptyMessage(createEmptyMessage());
+		String message = createIterationMessage();
+		String emptyMessage = createEmptyMessage();
+		if (Display.getCurrent() != null) {
+			fAssistant.setStatusMessage(message);
+			fAssistant.setEmptyMessage(emptyMessage);
+		} else {
+			Display.getDefault().syncExec(() -> {
+				fAssistant.setStatusMessage(message);
+				fAssistant.setEmptyMessage(emptyMessage);
+			});
+		}
+
 		fRepetition++;
 
 		// fAssistant.setShowMessage(fRepetition % 2 != 0);
diff --git a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ScriptCompletionProposal.java b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ScriptCompletionProposal.java
index eabdbe0..c929dfc 100644
--- a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ScriptCompletionProposal.java
+++ b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ScriptCompletionProposal.java
@@ -9,6 +9,8 @@
 
 package org.eclipse.dltk.ui.text.completion;
 
+import java.util.function.Supplier;
+
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.viewers.StyledString;
@@ -17,87 +19,88 @@
 public class ScriptCompletionProposal extends AbstractScriptCompletionProposal {
 
 	/**
-	 * Creates a new completion proposal. All fields are initialized based on
-	 * the provided information.
+	 * Creates a new completion proposal. All fields are initialized based on the
+	 * provided information.
 	 *
-	 * @param replacementString
-	 *                              the actual string to be inserted into the
-	 *                              document
-	 * @param replacementOffset
-	 *                              the offset of the text to be replaced
-	 * @param replacementLength
-	 *                              the length of the text to be replaced
-	 * @param image
-	 *                              the image to display for this proposal
-	 * @param displayString
-	 *                              the string to be displayed for the proposal
-	 *                              If set to <code>null</code>, the replacement
-	 *                              string will be taken as display string.
+	 * @param replacementString the actual string to be inserted into the document
+	 * @param replacementOffset the offset of the text to be replaced
+	 * @param replacementLength the length of the text to be replaced
+	 * @param image             the image to display for this proposal
+	 * @param displayString     the string to be displayed for the proposal If set
+	 *                          to <code>null</code>, the replacement string will be
+	 *                          taken as display string.
 	 */
-	public ScriptCompletionProposal(String replacementString,
-			int replacementOffset, int replacementLength, Image image,
+	public ScriptCompletionProposal(String replacementString, int replacementOffset, int replacementLength, Image image,
 			String displayString, int relevance) {
-		this(replacementString, replacementOffset, replacementLength, image,
-				displayString, relevance, false);
+		this(replacementString, replacementOffset, replacementLength, image, displayString, relevance, false);
 	}
 
 	/**
-	 * Creates a new completion proposal. All fields are initialized based on
-	 * the provided information.
+	 * Creates a new completion proposal. All fields are initialized based on the
+	 * provided information.
 	 *
-	 * @param replacementString
-	 *                              the actual string to be inserted into the
-	 *                              document
-	 * @param replacementOffset
-	 *                              the offset of the text to be replaced
-	 * @param replacementLength
-	 *                              the length of the text to be replaced
-	 * @param image
-	 *                              the image to display for this proposal
-	 * @param displayString
-	 *                              the string to be displayed for the proposal
-	 *                              If set to <code>null</code>, the replacement
-	 *                              string will be taken as display string.
-	 * @param relevance
-	 *                              the relevance
-	 * @param indoc
-	 *                              <code>true</code> for a javadoc proposal
+	 * @param replacementString the actual string to be inserted into the document
+	 * @param replacementOffset the offset of the text to be replaced
+	 * @param replacementLength the length of the text to be replaced
+	 * @param image             the image to display for this proposal
+	 * @param displayString     the string to be displayed for the proposal If set
+	 *                          to <code>null</code>, the replacement string will be
+	 *                          taken as display string.
+	 * @param relevance         the relevance
+	 * @param indoc             <code>true</code> for a javadoc proposal
 	 *
 	 */
-	public ScriptCompletionProposal(String replacementString,
-			int replacementOffset, int replacementLength, Image image,
+	public ScriptCompletionProposal(String replacementString, int replacementOffset, int replacementLength, Image image,
 			String displayString, int relevance, boolean indoc) {
-		this(replacementString, replacementOffset, replacementLength, image,
-				new StyledString(displayString), relevance, false);
+		this(replacementString, replacementOffset, replacementLength, image, new StyledString(displayString), relevance,
+				false);
 	}
 
 	/**
-	 * Creates a new completion proposal. All fields are initialized based on
-	 * the provided information.
+	 * Creates a new completion proposal. All fields are initialized based on the
+	 * provided information.
 	 *
-	 * @param replacementString
-	 *                              the actual string to be inserted into the
-	 *                              document
-	 * @param replacementOffset
-	 *                              the offset of the text to be replaced
-	 * @param replacementLength
-	 *                              the length of the text to be replaced
-	 * @param image
-	 *                              the image to display for this proposal
-	 * @param displayString
-	 *                              the StyledString to be displayed for the
-	 *                              proposal If set to <code>null</code>, the
-	 *                              replacement string will be taken as display
-	 *                              string.
-	 * @param relevance
-	 *                              the relevance
-	 * @param indoc
-	 *                              <code>true</code> for a javadoc proposal
+	 * @param replacementString the actual string to be inserted into the document
+	 * @param replacementOffset the offset of the text to be replaced
+	 * @param replacementLength the length of the text to be replaced
+	 * @param image             the image to display for this proposal
+	 * @param displayString     the StyledString to be displayed for the proposal If
+	 *                          set to <code>null</code>, the replacement string
+	 *                          will be taken as display string.
+	 * @param relevance         the relevance
+	 * @param indoc             <code>true</code> for a javadoc proposal
 	 * @since 5.2
 	 *
 	 */
-	public ScriptCompletionProposal(String replacementString,
-			int replacementOffset, int replacementLength, Image image,
+	public ScriptCompletionProposal(String replacementString, int replacementOffset, int replacementLength, Image image,
+			StyledString displayString, int relevance, boolean indoc) {
+		this(replacementString, replacementOffset, replacementLength, displayString, relevance, indoc);
+		setImage(image);
+	}
+
+	/**
+	 * Creates a new completion proposal. All fields are initialized based on the
+	 * provided information.
+	 *
+	 * @param replacementString the actual string to be inserted into the document
+	 * @param replacementOffset the offset of the text to be replaced
+	 * @param replacementLength the length of the text to be replaced
+	 * @param image             the image to display for this proposal
+	 * @param displayString     the StyledString to be displayed for the proposal If
+	 *                          set to <code>null</code>, the replacement string
+	 *                          will be taken as display string.
+	 * @param relevance         the relevance
+	 * @param indoc             <code>true</code> for a javadoc proposal
+	 * @since 5.9
+	 *
+	 */
+	public ScriptCompletionProposal(String replacementString, int replacementOffset, int replacementLength,
+			Supplier<Image> image, StyledString displayString, int relevance, boolean indoc) {
+		this(replacementString, replacementOffset, replacementLength, displayString, relevance, indoc);
+		setImageFactory(image);
+	}
+
+	private ScriptCompletionProposal(String replacementString, int replacementOffset, int replacementLength,
 			StyledString displayString, int relevance, boolean indoc) {
 		Assert.isNotNull(replacementString);
 		Assert.isTrue(replacementOffset >= 0);
@@ -106,15 +109,11 @@
 		setReplacementString(replacementString);
 		setReplacementOffset(replacementOffset);
 		setReplacementLength(replacementLength);
-		setImage(image);
-		setStyledDisplayString(
-				displayString == null ? new StyledString(replacementString)
-						: displayString);
+		setStyledDisplayString(displayString == null ? new StyledString(replacementString) : displayString);
 		setRelevance(relevance);
 		setCursorPosition(replacementString.length());
 		setInDoc(indoc);
-		setSortString(displayString == null ? replacementString
-				: displayString.toString());
+		setSortString(displayString == null ? replacementString : displayString.toString());
 	}
 
 	@Override
@@ -135,8 +134,7 @@
 	}
 
 	@Override
-	public CharSequence getPrefixCompletionText(IDocument document,
-			int completionOffset) {
+	public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
 		String string = getReplacementString();
 		int pos = string.indexOf('(');
 		if (pos > 0) {
diff --git a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ScriptCompletionProposalCollector.java b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ScriptCompletionProposalCollector.java
index eb183ef..69500c1 100644
--- a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ScriptCompletionProposalCollector.java
+++ b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ScriptCompletionProposalCollector.java
@@ -14,6 +14,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Supplier;
 
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.CoreException;
@@ -69,16 +70,15 @@
  *
  *
  */
-public abstract class ScriptCompletionProposalCollector
-		extends CompletionRequestor implements ICompletionRequestorExtension {
+public abstract class ScriptCompletionProposalCollector extends CompletionRequestor
+		implements ICompletionRequestorExtension {
 	/**
-	 * Intermediate attribute of {@link CompletionProposal} used to limit the
-	 * number of displayed method parameters.
+	 * Intermediate attribute of {@link CompletionProposal} used to limit the number
+	 * of displayed method parameters.
 	 *
 	 * @since 5.0
 	 */
-	public static final String ATTR_PARAM_LIMIT = DLTKUIPlugin.PLUGIN_ID
-			+ "CompletionProposal#ParameterLimit";
+	public static final String ATTR_PARAM_LIMIT = DLTKUIPlugin.PLUGIN_ID + "CompletionProposal#ParameterLimit";
 
 	/** Tells whether this class is in debug mode. */
 	private static final boolean DEBUG = "true".equalsIgnoreCase(Platform //$NON-NLS-1$
@@ -88,8 +88,7 @@
 	/** Triggers for variables. Do not modify. */
 	private CompletionProposalLabelProvider fLabelProvider;
 
-	private final ImageDescriptorRegistry fRegistry = DLTKUIPlugin
-			.getImageDescriptorRegistry();
+	private final ImageDescriptorRegistry fRegistry = DLTKUIPlugin.getImageDescriptorRegistry();
 
 	private final List<IScriptCompletionProposal> fScriptProposals = new ArrayList<>();
 
@@ -109,6 +108,8 @@
 
 	private IProblem fLastProblem;
 
+	private boolean fAsyncCompletion = false;
+
 	/* performance measurement */
 	private long fStartTime;
 
@@ -121,23 +122,22 @@
 
 	/**
 	 * Creates a new instance ready to collect proposals. If the passed
-	 * <code>ISourceModule</code> is not contained in an {@link IScriptProject},
-	 * no javadoc will be available as
+	 * <code>ISourceModule</code> is not contained in an {@link IScriptProject}, no
+	 * javadoc will be available as
 	 * {@link org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
 	 * additional info} on the created proposals.
 	 *
-	 * @param cu
-	 *            the compilation unit that the result collector will operate on
+	 * @param cu the compilation unit that the result collector will operate on
 	 */
 	public ScriptCompletionProposalCollector(ISourceModule cu) {
 		this(cu.getScriptProject(), cu);
 	}
 
 	/**
-	 * Creates a new instance ready to collect proposals. Note that proposals
-	 * for anonymous types and method declarations are not created when using
-	 * this constructor, as those need to know the compilation unit that they
-	 * are created on. Use
+	 * Creates a new instance ready to collect proposals. Note that proposals for
+	 * anonymous types and method declarations are not created when using this
+	 * constructor, as those need to know the compilation unit that they are created
+	 * on. Use
 	 * {@link ScriptCompletionProposalCollector#CompletionProposalCollector(ISourceModule)}
 	 * instead to get all proposals.
 	 * <p>
@@ -147,50 +147,52 @@
 	 * additional info} on the created (e.g. method and type) proposals.
 	 * </p>
 	 *
-	 * @param project
-	 *            the project that the result collector will operate on, or
-	 *            <code>null</code>
+	 * @param project the project that the result collector will operate on, or
+	 *                <code>null</code>
 	 */
 	public ScriptCompletionProposalCollector(IScriptProject project) {
 		this(project, null);
 	}
 
-	protected ScriptCompletionProposalCollector(IScriptProject project,
-			ISourceModule cu) {
+	protected ScriptCompletionProposalCollector(IScriptProject project, ISourceModule cu) {
 		fScriptProject = project;
 		fSourceModule = cu;
 		fUserReplacementLength = -1;
 	}
 
 	/**
+	 * Enable async mode
+	 */
+	public void setAsyncCompletion(boolean async) {
+		fAsyncCompletion = async;
+	}
+
+	/**
 	 * Sets the invocation context.
 	 * <p>
 	 * Subclasses may extend.
 	 * </p>
 	 *
-	 * @param context
-	 *            the invocation context
+	 * @param context the invocation context
 	 * @see #getInvocationContext()
 	 *
 	 */
-	public void setInvocationContext(
-			ScriptContentAssistInvocationContext context) {
+	public void setInvocationContext(ScriptContentAssistInvocationContext context) {
 		fInvocationContext = context;
 		context.setCollector(this);
 	}
 
 	/**
 	 * Returns the invocation context. If none has been set via
-	 * {@link #setInvocationContext(JavaContentAssistInvocationContext)}, a new
-	 * one is created.
+	 * {@link #setInvocationContext(JavaContentAssistInvocationContext)}, a new one
+	 * is created.
 	 *
 	 * @return invocationContext the invocation context
 	 *
 	 */
 	public final ScriptContentAssistInvocationContext getInvocationContext() {
 		if (fInvocationContext == null) {
-			setInvocationContext(createScriptContentAssistInvocationContext(
-					getSourceModule()));
+			setInvocationContext(createScriptContentAssistInvocationContext(getSourceModule()));
 		}
 
 		return fInvocationContext;
@@ -198,15 +200,14 @@
 
 	protected ScriptContentAssistInvocationContext createScriptContentAssistInvocationContext(
 			ISourceModule sourceModule) {
-		return new ScriptContentAssistInvocationContext(sourceModule,
-				getNatureId());
+		return new ScriptContentAssistInvocationContext(sourceModule, getNatureId());
 	}
 
 	/**
 	 * {@inheritDoc}
 	 * <p>
-	 * Subclasses may replace, but usually should not need to. Consider
-	 * replacing {@linkplain #createScriptCompletionProposal(CompletionProposal)
+	 * Subclasses may replace, but usually should not need to. Consider replacing
+	 * {@linkplain #createScriptCompletionProposal(CompletionProposal)
 	 * createScriptCompletionProposal} instead.
 	 * </p>
 	 */
@@ -260,8 +261,8 @@
 	}
 
 	/**
-	 * Returns an error message about any error that may have occurred during
-	 * code completion, or the empty string if none.
+	 * Returns an error message about any error that may have occurred during code
+	 * completion, or the empty string if none.
 	 * <p>
 	 * Subclasses may replace or extend.
 	 * </p>
@@ -281,8 +282,7 @@
 	 */
 	public final IScriptCompletionProposal[] getScriptCompletionProposals() {
 		processUnprocessedProposals();
-		return fScriptProposals.toArray(
-				new IScriptCompletionProposal[fScriptProposals.size()]);
+		return fScriptProposals.toArray(new IScriptCompletionProposal[fScriptProposals.size()]);
 	}
 
 	private void processUnprocessedProposals() {
@@ -292,8 +292,7 @@
 			final int size = fUnprocessedCompletionProposals.size();
 			if (size == 0)
 				return;
-			copy = fUnprocessedCompletionProposals
-					.toArray(new CompletionProposal[size]);
+			copy = fUnprocessedCompletionProposals.toArray(new CompletionProposal[size]);
 			fUnprocessedCompletionProposals.clear();
 		}
 		for (CompletionProposal proposal : copy) {
@@ -303,8 +302,7 @@
 				// all signature processing method may throw IAEs
 				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=84657
 				// don't abort, but log and show all the valid proposals
-				DLTKUIPlugin.log(new Status(IStatus.ERROR,
-						DLTKUIPlugin.getPluginId(), IStatus.OK,
+				DLTKUIPlugin.log(new Status(IStatus.ERROR, DLTKUIPlugin.getPluginId(), IStatus.OK,
 						"Exception when processing proposal for: " //$NON-NLS-1$
 								+ String.valueOf(proposal.getCompletion()),
 						e));
@@ -318,24 +316,18 @@
 	}
 
 	protected void processUnprocessedProposal(CompletionProposal proposal) {
-		if (proposal
-				.getKind() == CompletionProposal.POTENTIAL_METHOD_DECLARATION) {
+		if (proposal.getKind() == CompletionProposal.POTENTIAL_METHOD_DECLARATION) {
 			acceptPotentialMethodDeclaration(proposal);
 		} else {
-			if (proposal.getKind() == CompletionProposal.METHOD_REF
-					&& !isContextInformationMode()) {
+			if (proposal.getKind() == CompletionProposal.METHOD_REF && !isContextInformationMode()) {
 				final String[] params = proposal.findParameterNames(null);
 				final Integer requiredParamCount = (Integer) proposal
-						.getAttribute(
-								CompletionProposal.ATTR_REQUIRED_PARAM_COUNT);
-				if (params != null && requiredParamCount != null
-						&& params.length > requiredParamCount.intValue()) {
-					for (int i = requiredParamCount
-							.intValue(); i <= params.length; ++i) {
+						.getAttribute(CompletionProposal.ATTR_REQUIRED_PARAM_COUNT);
+				if (params != null && requiredParamCount != null && params.length > requiredParamCount.intValue()) {
+					for (int i = requiredParamCount.intValue(); i <= params.length; ++i) {
 						final CompletionProposal copy = proposal.clone();
 						copy.setAttribute(ATTR_PARAM_LIMIT, i);
-						final IScriptCompletionProposal scriptProposal = createScriptCompletionProposal(
-								copy);
+						final IScriptCompletionProposal scriptProposal = createScriptCompletionProposal(copy);
 						if (scriptProposal != null) {
 							addProposal(scriptProposal, copy);
 						}
@@ -343,16 +335,14 @@
 					return;
 				}
 			}
-			final IScriptCompletionProposal scriptProposal = createScriptCompletionProposal(
-					proposal);
+			final IScriptCompletionProposal scriptProposal = createScriptCompletionProposal(proposal);
 			if (scriptProposal != null) {
 				addProposal(scriptProposal, proposal);
 			}
 		}
 	}
 
-	protected void addProposal(IScriptCompletionProposal scriptProposal,
-			CompletionProposal proposal) {
+	protected void addProposal(IScriptCompletionProposal scriptProposal, CompletionProposal proposal) {
 		fScriptProposals.add(scriptProposal);
 		if (proposal.getKind() == CompletionProposal.KEYWORD)
 			fKeywords.add(scriptProposal);
@@ -365,18 +355,16 @@
 	 */
 	public final IScriptCompletionProposal[] getKeywordCompletionProposals() {
 		processUnprocessedProposals();
-		return fKeywords
-				.toArray(new IScriptCompletionProposal[fKeywords.size()]);
+		return fKeywords.toArray(new IScriptCompletionProposal[fKeywords.size()]);
 	}
 
 	/**
-	 * If the replacement length is set, it overrides the length returned from
-	 * the content assist infrastructure. Use this setting if code assist is
-	 * called with a none empty selection.
+	 * If the replacement length is set, it overrides the length returned from the
+	 * content assist infrastructure. Use this setting if code assist is called with
+	 * a none empty selection.
 	 *
-	 * @param length
-	 *            the new replacement length, relative to the code assist
-	 *            offset. Must be equal to or greater than zero.
+	 * @param length the new replacement length, relative to the code assist offset.
+	 *               Must be equal to or greater than zero.
 	 */
 	public final void setReplacementLength(int length) {
 		fUserReplacementLength = length;
@@ -388,8 +376,7 @@
 	 * Subclasses may replace, but usually should not need to.
 	 * </p>
 	 *
-	 * @param proposal
-	 *            the proposal to compute the relevance for
+	 * @param proposal the proposal to compute the relevance for
 	 * @return the relevance for <code>proposal</code>
 	 */
 	public int computeRelevance(CompletionProposal proposal) {
@@ -423,11 +410,11 @@
 	 * Creates a new script completion proposal from a core proposal. This may
 	 * involve computing the display label and setting up some context.
 	 * <p>
-	 * This method is called for every proposal that will be displayed to the
-	 * user, which may be hundreds. Implementations should therefore defer as
-	 * much work as possible: Labels should be computed lazily to leverage
-	 * virtual table usage, and any information only needed when
-	 * <em>applying</em> a proposal should not be computed yet.
+	 * This method is called for every proposal that will be displayed to the user,
+	 * which may be hundreds. Implementations should therefore defer as much work as
+	 * possible: Labels should be computed lazily to leverage virtual table usage,
+	 * and any information only needed when <em>applying</em> a proposal should not
+	 * be computed yet.
 	 * </p>
 	 * <p>
 	 * Implementations may return <code>null</code> if a proposal should not be
@@ -437,19 +424,16 @@
 	 * Subclasses may extend or replace this method.
 	 * </p>
 	 *
-	 * @param proposal
-	 *            the core completion proposal to create a UI proposal for
-	 * @return the created script completion proposal, or <code>null</code> if
-	 *         no proposal should be displayed
+	 * @param proposal the core completion proposal to create a UI proposal for
+	 * @return the created script completion proposal, or <code>null</code> if no
+	 *         proposal should be displayed
 	 */
-	protected IScriptCompletionProposal createScriptCompletionProposal(
-			CompletionProposal proposal) {
+	protected IScriptCompletionProposal createScriptCompletionProposal(CompletionProposal proposal) {
 		final IScriptCompletionProposalFactory[] factories = ScriptCompletionProposalFactoryRegistry
 				.getFactories(getNatureId());
 		if (factories != null) {
 			for (IScriptCompletionProposalFactory factory : factories) {
-				final IScriptCompletionProposal scriptProposal = factory
-						.create(this, proposal);
+				final IScriptCompletionProposal scriptProposal = factory.create(this, proposal);
 				if (scriptProposal != null) {
 					return scriptProposal;
 				}
@@ -488,33 +472,29 @@
 		// return createJavadocInlineTagProposal(proposal);
 		case CompletionProposal.POTENTIAL_METHOD_DECLARATION:
 		default:
-			return new ScriptCompletionProposal(proposal.getCompletion(),
-					proposal.getReplaceStart(),
-					proposal.getReplaceEnd() - proposal.getReplaceStart(), null,
-					proposal.getName(), proposal.getRelevance());
+			return new ScriptCompletionProposal(proposal.getCompletion(), proposal.getReplaceStart(),
+					proposal.getReplaceEnd() - proposal.getReplaceStart(), null, proposal.getName(),
+					proposal.getRelevance());
 		}
 	}
 
 	/**
-	 * Creates the context information for a given method reference proposal.
-	 * The passed proposal must be of kind {@link CompletionProposal#METHOD_REF}
-	 * .
+	 * Creates the context information for a given method reference proposal. The
+	 * passed proposal must be of kind {@link CompletionProposal#METHOD_REF} .
 	 *
-	 * @param methodProposal
-	 *            the method proposal for which to create context information
+	 * @param methodProposal the method proposal for which to create context
+	 *                       information
 	 * @return the context information for <code>methodProposal</code>
 	 */
-	protected final IContextInformation createMethodContextInformation(
-			CompletionProposal methodProposal) {
-		Assert.isTrue(
-				methodProposal.getKind() == CompletionProposal.METHOD_REF);
+	protected final IContextInformation createMethodContextInformation(CompletionProposal methodProposal) {
+		Assert.isTrue(methodProposal.getKind() == CompletionProposal.METHOD_REF);
 		return new ProposalContextInformation(methodProposal);
 	}
 
 	/**
 	 * Returns the compilation unit that the receiver operates on, or
-	 * <code>null</code> if the <code>IScriptProject</code> constructor was used
-	 * to create the receiver.
+	 * <code>null</code> if the <code>IScriptProject</code> constructor was used to
+	 * create the receiver.
 	 *
 	 * @return the compilation unit that the receiver operates on, or
 	 *         <code>null</code>
@@ -536,9 +516,8 @@
 	/**
 	 * Returns a cached image for the given descriptor.
 	 *
-	 * @param descriptor
-	 *            the image descriptor to get an image for, may be
-	 *            <code>null</code>
+	 * @param descriptor the image descriptor to get an image for, may be
+	 *                   <code>null</code>
 	 * @return the image corresponding to <code>descriptor</code>
 	 */
 	public final Image getImage(ImageDescriptor descriptor) {
@@ -549,11 +528,10 @@
 	 * Returns the replacement length of a given completion proposal. The
 	 * replacement length is usually the difference between the return values of
 	 * <code>proposal.getReplaceEnd</code> and
-	 * <code>proposal.getReplaceStart</code>, but this behavior may be
-	 * overridden by calling {@link #setReplacementLength(int)}.
+	 * <code>proposal.getReplaceStart</code>, but this behavior may be overridden by
+	 * calling {@link #setReplacementLength(int)}.
 	 *
-	 * @param proposal
-	 *            the completion proposal to get the replacement length for
+	 * @param proposal the completion proposal to get the replacement length for
 	 * @return the replacement length for <code>proposal</code>
 	 */
 	protected final int getLength(CompletionProposal proposal) {
@@ -574,8 +552,8 @@
 	}
 
 	/**
-	 * Returns <code>true</code> if <code>proposal</code> is filtered, e.g.
-	 * should not be proposed to the user, <code>false</code> if it is valid.
+	 * Returns <code>true</code> if <code>proposal</code> is filtered, e.g. should
+	 * not be proposed to the user, <code>false</code> if it is valid.
 	 * <p>
 	 * Subclasses may extends this method. The default implementation filters
 	 * proposals set to be ignored via
@@ -583,10 +561,9 @@
 	 * types set to be ignored in the preferences.
 	 * </p>
 	 *
-	 * @param proposal
-	 *            the proposal to filter
-	 * @return <code>true</code> to filter <code>proposal</code>,
-	 *         <code>false</code> to let it pass
+	 * @param proposal the proposal to filter
+	 * @return <code>true</code> to filter <code>proposal</code>, <code>false</code>
+	 *         to let it pass
 	 */
 	protected boolean isFiltered(CompletionProposal proposal) {
 		if (isIgnored(proposal.getKind())) {
@@ -612,8 +589,7 @@
 		// int completionEnd = proposal.getReplaceEnd();
 		// int relevance = computeRelevance(proposal);
 		try {
-			IModelElement element = fSourceModule
-					.getElementAt(proposal.getCompletionLocation());
+			IModelElement element = fSourceModule.getElementAt(proposal.getCompletionLocation());
 			if (element != null) {
 				IType type = (IType) element.getAncestor(IModelElement.TYPE);
 				if (type != null) {
@@ -625,8 +601,7 @@
 					// completionStart, completionEnd - completionStart,
 					// relevance, fSuggestedMethodNames, fJavaProposals);
 					if (DLTKCore.DEBUG) {
-						System.out.println(
-								"TODO: Add method completion proposal support here..."); //$NON-NLS-1$
+						System.out.println("TODO: Add method completion proposal support here..."); //$NON-NLS-1$
 					}
 				}
 			}
@@ -654,36 +629,39 @@
 	 * It is recommended to override only the next method.
 	 */
 	@Deprecated
-	protected ScriptCompletionProposal createScriptCompletionProposal(
-			String completion, int replaceStart, int length, Image image,
-			String displayString, int relevance) {
-		return createScriptCompletionProposal(completion, replaceStart, length,
-				image, displayString, relevance, false);
+	protected ScriptCompletionProposal createScriptCompletionProposal(String completion, int replaceStart, int length,
+			Image image, String displayString, int relevance) {
+		return createScriptCompletionProposal(completion, replaceStart, length, image, displayString, relevance, false);
 	}
 
 	@Deprecated
-	protected ScriptCompletionProposal createScriptCompletionProposal(
-			String completion, int replaceStart, int length, Image image,
-			String displayString, int relevance, boolean isInDoc) {
-		return new ScriptCompletionProposal(completion, replaceStart, length,
-				image, displayString, relevance, isInDoc);
+	protected ScriptCompletionProposal createScriptCompletionProposal(String completion, int replaceStart, int length,
+			Image image, String displayString, int relevance, boolean isInDoc) {
+		return new ScriptCompletionProposal(completion, replaceStart, length, image, displayString, relevance, isInDoc);
 	}
 
 	/**
 	 * @since 5.2
 	 */
-	protected ScriptCompletionProposal createScriptCompletionProposal(
-			String completion, int replaceStart, int length, Image image,
-			StyledString displayString, int relevance, boolean isInDoc) {
-		return new ScriptCompletionProposal(completion, replaceStart, length,
-				image, displayString, relevance, isInDoc);
+	protected ScriptCompletionProposal createScriptCompletionProposal(String completion, int replaceStart, int length,
+			Image image, StyledString displayString, int relevance, boolean isInDoc) {
+		return new ScriptCompletionProposal(completion, replaceStart, length, image, displayString, relevance, isInDoc);
+	}
+
+	/**
+	 * Used when {@link #setAsyncCompletion(true)} is called
+	 *
+	 * @since 5.9
+	 */
+	protected ScriptCompletionProposal createScriptCompletionProposal(String completion, int replaceStart, int length,
+			Supplier<Image> image, StyledString displayString, int relevance, boolean isInDoc) {
+		return new ScriptCompletionProposal(completion, replaceStart, length, image, displayString, relevance, isInDoc);
 	}
 
 	@Deprecated
-	protected ScriptCompletionProposal createOverrideCompletionProposal(
-			IScriptProject scriptProject, ISourceModule compilationUnit,
-			String name, String[] paramTypes, int start, int length,
-			String label, String string) {
+	protected ScriptCompletionProposal createOverrideCompletionProposal(IScriptProject scriptProject,
+			ISourceModule compilationUnit, String name, String[] paramTypes, int start, int length, String label,
+			String string) {
 		// default implementation return null, as this functionality is optional
 		return null;
 	}
@@ -691,16 +669,13 @@
 	/**
 	 * @since 5.5
 	 */
-	protected ScriptCompletionProposal createOverrideCompletionProposal(
-			IScriptProject scriptProject, ISourceModule compilationUnit,
-			String name, String[] paramTypes, int start, int length,
-			StyledString label, String string) {
-		// default implementation return null, as this functionality is optional
+	protected ScriptCompletionProposal createOverrideCompletionProposal(IScriptProject scriptProject,
+			ISourceModule compilationUnit, String name, String[] paramTypes, int start, int length, StyledString label,
+			String string) {
 		return null;
 	}
 
-	protected IScriptCompletionProposal createFieldProposal(
-			CompletionProposal proposal) {
+	protected IScriptCompletionProposal createFieldProposal(CompletionProposal proposal) {
 		String completion = String.valueOf(proposal.getCompletion());
 		int start = proposal.getReplaceStart();
 		int length = getLength(proposal);
@@ -709,31 +684,35 @@
 		ScriptCompletionProposal scriptProposal;
 
 		CompletionProposalLabelProvider labelProvider = getLabelProvider();
-		Image image = getImage(
-				getLabelProvider().createFieldImageDescriptor(proposal));
+		Supplier<Image> image = getImageFactory(getLabelProvider().createFieldImageDescriptor(proposal));
 
 		if (labelProvider instanceof ICompletionProposalLabelProviderExtension) {
-
 			StyledString label = ((ICompletionProposalLabelProviderExtension) getLabelProvider())
 					.createStyledFieldProposalLabel(proposal);
-			scriptProposal = createScriptCompletionProposal(completion, start,
-					length, image, label, relevance, false);
+			if (fAsyncCompletion) {
+				scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance,
+						false);
+			} else {
+				scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label,
+						relevance, false);
+			}
 		} else {
-			String label = getLabelProvider()
-					.createFieldProposalLabel(proposal);
-			scriptProposal = createScriptCompletionProposal(completion, start,
-					length, image, label, relevance, false);
+			String label = getLabelProvider().createFieldProposalLabel(proposal);
+			scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label, relevance,
+					false);
 		}
 
 		if (fScriptProject != null)
-			scriptProposal.setProposalInfo(
-					new FieldProposalInfo(fScriptProject, proposal));
+			scriptProposal.setProposalInfo(new FieldProposalInfo(fScriptProject, proposal));
 		scriptProposal.setTriggerCharacters(getVarTrigger());
 		return scriptProposal;
 	}
 
-	protected IScriptCompletionProposal createKeywordProposal(
-			CompletionProposal proposal) {
+	protected Supplier<Image> getImageFactory(ImageDescriptor imageDescriptor) {
+		return () -> getImage(imageDescriptor);
+	}
+
+	protected IScriptCompletionProposal createKeywordProposal(CompletionProposal proposal) {
 		String completion = String.valueOf(proposal.getCompletion());
 		int start = proposal.getReplaceStart();
 		int length = getLength(proposal);
@@ -742,31 +721,33 @@
 		ScriptCompletionProposal scriptProposal;
 
 		CompletionProposalLabelProvider labelProvider = getLabelProvider();
-		Image image = getImage(
-				getLabelProvider().createImageDescriptor(proposal));
+		Supplier<Image> image = getImageFactory(getLabelProvider().createImageDescriptor(proposal));
 
 		if (labelProvider instanceof ICompletionProposalLabelProviderExtension) {
 
 			StyledString label = ((ICompletionProposalLabelProviderExtension) getLabelProvider())
 					.createStyledKeywordLabel(proposal);
-			scriptProposal = createScriptCompletionProposal(completion, start,
-					length, image, label, relevance, false);
+			if (fAsyncCompletion) {
+				scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance,
+						false);
+			} else {
+				scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label,
+						relevance, false);
+			}
 		} else {
 			String label = getLabelProvider().createKeywordLabel(proposal);
-			scriptProposal = createScriptCompletionProposal(completion, start,
-					length, image, label, relevance, false);
+			scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label, relevance,
+					false);
 		}
 
 		if (fScriptProject != null) {
-			scriptProposal.setProposalInfo(
-					new ProposalInfo(fScriptProject, proposal.getName()));
+			scriptProposal.setProposalInfo(new ProposalInfo(fScriptProject, proposal.getName()));
 		}
 
 		return scriptProposal;
 	}
 
-	protected IScriptCompletionProposal createPackageProposal(
-			CompletionProposal proposal) {
+	protected IScriptCompletionProposal createPackageProposal(CompletionProposal proposal) {
 		String completion = String.valueOf(proposal.getCompletion());
 		int start = proposal.getReplaceStart();
 		int length = getLength(proposal);
@@ -775,26 +756,29 @@
 		ScriptCompletionProposal scriptProposal;
 
 		CompletionProposalLabelProvider labelProvider = getLabelProvider();
-		Image image = getImage(
-				getLabelProvider().createImageDescriptor(proposal));
+		Supplier<Image> image = getImageFactory(getLabelProvider().createImageDescriptor(proposal));
 
 		if (labelProvider instanceof ICompletionProposalLabelProviderExtension) {
 
 			StyledString label = ((ICompletionProposalLabelProviderExtension) getLabelProvider())
 					.createStyledSimpleLabel(proposal);
-			scriptProposal = createScriptCompletionProposal(completion, start,
-					length, image, label, relevance, false);
+			if (fAsyncCompletion) {
+				scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance,
+						false);
+			} else {
+				scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label,
+						relevance, false);
+			}
 		} else {
 			String label = getLabelProvider().createSimpleLabel(proposal);
-			scriptProposal = createScriptCompletionProposal(completion, start,
-					length, image, label, relevance, false);
+			scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label, relevance,
+					false);
 		}
 
 		return scriptProposal;
 	}
 
-	private IScriptCompletionProposal createLabelProposal(
-			CompletionProposal proposal) {
+	private IScriptCompletionProposal createLabelProposal(CompletionProposal proposal) {
 		String completion = String.valueOf(proposal.getCompletion());
 		int start = proposal.getReplaceStart();
 		int length = getLength(proposal);
@@ -803,23 +787,27 @@
 		ScriptCompletionProposal scriptProposal;
 
 		CompletionProposalLabelProvider labelProvider = getLabelProvider();
-
+		Image image = null;
+		Supplier<Image> factory = null;
 		if (labelProvider instanceof ICompletionProposalLabelProviderExtension) {
 
 			StyledString label = ((ICompletionProposalLabelProviderExtension) getLabelProvider())
 					.createStyledSimpleLabel(proposal);
-			scriptProposal = createScriptCompletionProposal(completion, start,
-					length, null, label, relevance, false);
+			if (fAsyncCompletion) {
+				scriptProposal = createScriptCompletionProposal(completion, start, length, factory, label, relevance,
+						false);
+			} else {
+				scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance,
+						false);
+			}
 		} else {
 			String label = getLabelProvider().createSimpleLabel(proposal);
-			scriptProposal = createScriptCompletionProposal(completion, start,
-					length, null, label, relevance, false);
+			scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance, false);
 		}
 		return scriptProposal;
 	}
 
-	private IScriptCompletionProposal createLocalVariableProposal(
-			CompletionProposal proposal) {
+	private IScriptCompletionProposal createLocalVariableProposal(CompletionProposal proposal) {
 		String completion = String.valueOf(proposal.getCompletion());
 		int start = proposal.getReplaceStart();
 		int length = getLength(proposal);
@@ -828,20 +816,23 @@
 		ScriptCompletionProposal scriptProposal;
 
 		CompletionProposalLabelProvider labelProvider = getLabelProvider();
-		Image image = getImage(
-				getLabelProvider().createLocalImageDescriptor(proposal));
+		Supplier<Image> image = getImageFactory(getLabelProvider().createLocalImageDescriptor(proposal));
 
 		if (labelProvider instanceof ICompletionProposalLabelProviderExtension) {
 
 			StyledString label = ((ICompletionProposalLabelProviderExtension) getLabelProvider())
 					.createStyledSimpleLabelWithType(proposal);
-			scriptProposal = createScriptCompletionProposal(completion, start,
-					length, image, label, relevance, false);
+			if (fAsyncCompletion) {
+				scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance,
+						false);
+			} else {
+				scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label,
+						relevance, false);
+			}
 		} else {
-			String label = getLabelProvider()
-					.createSimpleLabelWithType(proposal);
-			scriptProposal = createScriptCompletionProposal(completion, start,
-					length, image, label, relevance, false);
+			String label = getLabelProvider().createSimpleLabelWithType(proposal);
+			scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label, relevance,
+					false);
 		}
 
 		scriptProposal.setTriggerCharacters(getVarTrigger());
@@ -851,15 +842,13 @@
 	/**
 	 * @since 3.0
 	 */
-	protected static final char[] VAR_TRIGGER = new char[] { '\t', ' ', '=',
-			';', '.' };
+	protected static final char[] VAR_TRIGGER = new char[] { '\t', ' ', '=', ';', '.' };
 
 	protected char[] getVarTrigger() {
 		return VAR_TRIGGER;
 	}
 
-	private IScriptCompletionProposal createMethodDeclarationProposal(
-			CompletionProposal proposal) {
+	private IScriptCompletionProposal createMethodDeclarationProposal(CompletionProposal proposal) {
 		if (fSourceModule == null || fScriptProject == null) {
 			return null;
 		}
@@ -875,21 +864,17 @@
 		if (labelProvider instanceof ICompletionProposalLabelProviderExtension2) {
 			StyledString label = ((ICompletionProposalLabelProviderExtension2) labelProvider)
 					.createStyledOverrideMethodProposalLabel(proposal);
-			scriptProposal = createOverrideCompletionProposal(fScriptProject,
-					fSourceModule, name, paramTypes, start, length, label,
-					String.valueOf(proposal.getCompletion()));
+			scriptProposal = createOverrideCompletionProposal(fScriptProject, fSourceModule, name, paramTypes, start,
+					length, label, String.valueOf(proposal.getCompletion()));
 		} else {
-			String label = labelProvider
-					.createOverrideMethodProposalLabel(proposal);
-			scriptProposal = createOverrideCompletionProposal(fScriptProject,
-					fSourceModule, name, paramTypes, start, length, label,
-					String.valueOf(proposal.getCompletion()));
+			String label = labelProvider.createOverrideMethodProposalLabel(proposal);
+			scriptProposal = createOverrideCompletionProposal(fScriptProject, fSourceModule, name, paramTypes, start,
+					length, label, String.valueOf(proposal.getCompletion()));
 		}
 
 		if (scriptProposal == null)
 			return null;
-		scriptProposal.setImage(getImage(
-				getLabelProvider().createMethodImageDescriptor(proposal)));
+		scriptProposal.setImage(getImage(getLabelProvider().createMethodImageDescriptor(proposal)));
 
 		ProposalInfo info = new MethodProposalInfo(fScriptProject, proposal);
 		scriptProposal.setProposalInfo(info);
@@ -899,32 +884,25 @@
 		return scriptProposal;
 	}
 
-	private IScriptCompletionProposal createMethodReferenceProposal0(
-			CompletionProposal methodProposal) {
-		IScriptCompletionProposal proposal = createMethodReferenceProposal(
-				methodProposal);
+	private IScriptCompletionProposal createMethodReferenceProposal0(CompletionProposal methodProposal) {
+		IScriptCompletionProposal proposal = createMethodReferenceProposal(methodProposal);
 		if (proposal instanceof AbstractScriptCompletionProposal) {
-			adaptLength((AbstractScriptCompletionProposal) proposal,
-					methodProposal);
+			adaptLength((AbstractScriptCompletionProposal) proposal, methodProposal);
 		}
 		return proposal;
 	}
 
-	protected IScriptCompletionProposal createMethodReferenceProposal(
-			CompletionProposal methodProposal) {
-		return new ScriptMethodCompletionProposal(methodProposal,
-				getInvocationContext());
+	protected IScriptCompletionProposal createMethodReferenceProposal(CompletionProposal methodProposal) {
+		return new ScriptMethodCompletionProposal(methodProposal, getInvocationContext());
 	}
 
-	private void adaptLength(AbstractScriptCompletionProposal proposal,
-			CompletionProposal coreProposal) {
+	private void adaptLength(AbstractScriptCompletionProposal proposal, CompletionProposal coreProposal) {
 		if (fUserReplacementLength != -1) {
 			proposal.setReplacementLength(getLength(coreProposal));
 		}
 	}
 
-	protected IScriptCompletionProposal createTypeProposal(
-			CompletionProposal proposal) {
+	protected IScriptCompletionProposal createTypeProposal(CompletionProposal proposal) {
 
 		String completion = proposal.getCompletion();
 		int start = proposal.getReplaceStart();
@@ -934,30 +912,32 @@
 		ScriptCompletionProposal scriptProposal;
 
 		CompletionProposalLabelProvider labelProvider = getLabelProvider();
-		Image image = getImage(
-				getLabelProvider().createTypeImageDescriptor(proposal));
+		Supplier<Image> image = getImageFactory(getLabelProvider().createTypeImageDescriptor(proposal));
 
 		if (labelProvider instanceof ICompletionProposalLabelProviderExtension) {
 
 			StyledString label = ((ICompletionProposalLabelProviderExtension) getLabelProvider())
 					.createStyledTypeProposalLabel(proposal);
-			scriptProposal = createScriptCompletionProposal(completion, start,
-					length, image, label, relevance, false);
+			if (fAsyncCompletion) {
+				scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance,
+						false);
+			} else {
+				scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label,
+						relevance, false);
+			}
 		} else {
 			String label = getLabelProvider().createTypeProposalLabel(proposal);
-			scriptProposal = createScriptCompletionProposal(completion, start,
-					length, image, label, relevance, false);
+			scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label, relevance,
+					false);
 		}
-		scriptProposal.setProposalInfo(
-				new TypeProposalInfo(fScriptProject, proposal));
+		scriptProposal.setProposalInfo(new TypeProposalInfo(fScriptProject, proposal));
 
 		return scriptProposal;
 	}
 
 	@Override
 	public boolean isContextInformationMode() {
-		return fInvocationContext != null
-				&& fInvocationContext.isContextInformationMode();
+		return fInvocationContext != null && fInvocationContext.isContextInformationMode();
 	}
 
 	@Override
diff --git a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ScriptCompletionProposalComputer.java b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ScriptCompletionProposalComputer.java
index c8790e0..0f98026 100644
--- a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ScriptCompletionProposalComputer.java
+++ b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/text/completion/ScriptCompletionProposalComputer.java
@@ -29,23 +29,21 @@
 import org.eclipse.jface.text.templates.TemplateCompletionProcessor;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Shell;
 
 /**
  * Computes Script completion proposals and context infos.
  */
-public abstract class ScriptCompletionProposalComputer
-		extends AbstractScriptCompletionProposalComputer
+public abstract class ScriptCompletionProposalComputer extends AbstractScriptCompletionProposalComputer
 		implements IScriptCompletionProposalComputer {
 
-	private static final class ContextInformationWrapper
-			implements IContextInformation, IContextInformationExtension {
+	private static final class ContextInformationWrapper implements IContextInformation, IContextInformationExtension {
 
 		private final IContextInformation fContextInformation;
 		private int fPosition;
 
-		public ContextInformationWrapper(
-				IContextInformation contextInformation) {
+		public ContextInformationWrapper(IContextInformation contextInformation) {
 			fContextInformation = contextInformation;
 		}
 
@@ -76,8 +74,7 @@
 		@Override
 		public boolean equals(Object object) {
 			if (object instanceof ContextInformationWrapper) {
-				return fContextInformation.equals(
-						((ContextInformationWrapper) object).fContextInformation);
+				return fContextInformation.equals(((ContextInformationWrapper) object).fContextInformation);
 			}
 			return fContextInformation.equals(object);
 		}
@@ -85,19 +82,15 @@
 
 	private String fErrorMessage;
 
-	private List<IContextInformation> addContextInformations(
-			ScriptContentAssistInvocationContext context, int offset,
+	private List<IContextInformation> addContextInformations(ScriptContentAssistInvocationContext context, int offset,
 			IProgressMonitor monitor) {
-		List<ICompletionProposal> proposals = computeScriptCompletionProposals(
-				offset, context, monitor);
+		List<ICompletionProposal> proposals = computeScriptCompletionProposals(offset, context, monitor);
 		List<IContextInformation> result = new ArrayList<>(proposals.size());
 
 		for (ICompletionProposal proposal : proposals) {
-			IContextInformation contextInformation = proposal
-					.getContextInformation();
+			IContextInformation contextInformation = proposal.getContextInformation();
 			if (contextInformation != null) {
-				ContextInformationWrapper wrapper = new ContextInformationWrapper(
-						contextInformation);
+				ContextInformationWrapper wrapper = new ContextInformationWrapper(contextInformation);
 				wrapper.setContextInformationPosition(offset);
 				result.add(wrapper);
 			}
@@ -105,40 +98,37 @@
 		return result;
 	}
 
-	private void handleCodeCompletionException(ModelException e,
-			ScriptContentAssistInvocationContext context) {
+	private void handleCodeCompletionException(ModelException e, ScriptContentAssistInvocationContext context) {
 		ISourceModule module = context.getSourceModule();
-		Shell shell = context.getViewer().getTextWidget().getShell();
-		if (e.isDoesNotExist()
-				&& !module.getScriptProject().isOnBuildpath(module)) {
-			IPreferenceStore store = DLTKUIPlugin.getDefault()
-					.getPreferenceStore();
-			boolean value = store.getBoolean(
-					PreferenceConstants.NOTIFICATION_NOT_ON_BUILDPATH_MESSAGE);
-			if (!value) {
-				MessageDialog.openInformation(shell,
-						ScriptTextMessages.CompletionProcessor_error_notOnBuildPath_title,
-						ScriptTextMessages.CompletionProcessor_error_notOnBuildPath_message);
+		Runnable openDialog = () -> {
+			Shell shell = context.getViewer().getTextWidget().getShell();
+			if (e.isDoesNotExist() && !module.getScriptProject().isOnBuildpath(module)) {
+				IPreferenceStore store = DLTKUIPlugin.getDefault().getPreferenceStore();
+				boolean value = store.getBoolean(PreferenceConstants.NOTIFICATION_NOT_ON_BUILDPATH_MESSAGE);
+				if (!value) {
+					MessageDialog.openInformation(shell,
+							ScriptTextMessages.CompletionProcessor_error_notOnBuildPath_title,
+							ScriptTextMessages.CompletionProcessor_error_notOnBuildPath_message);
+				}
+				store.setValue(PreferenceConstants.NOTIFICATION_NOT_ON_BUILDPATH_MESSAGE, true);
+			} else {
+				ErrorDialog.openError(shell, ScriptTextMessages.CompletionProcessor_error_accessing_title,
+						ScriptTextMessages.CompletionProcessor_error_accessing_message, e.getStatus());
 			}
-			store.setValue(
-					PreferenceConstants.NOTIFICATION_NOT_ON_BUILDPATH_MESSAGE,
-					true);
-		} else
-			ErrorDialog.openError(shell,
-					ScriptTextMessages.CompletionProcessor_error_accessing_title,
-					ScriptTextMessages.CompletionProcessor_error_accessing_message,
-					e.getStatus());
+		};
+		if (Display.getCurrent() != null) {
+			openDialog.run();
+		} else {
+			Display.getDefault().asyncExec(openDialog);
+		}
 	}
 
 	// Code template completion proposals for script language
-	protected List<ICompletionProposal> computeTemplateCompletionProposals(
-			int offset, ScriptContentAssistInvocationContext context,
-			IProgressMonitor monitor) {
-		TemplateCompletionProcessor templateProcessor = createTemplateProposalComputer(
-				context);
+	protected List<ICompletionProposal> computeTemplateCompletionProposals(int offset,
+			ScriptContentAssistInvocationContext context, IProgressMonitor monitor) {
+		TemplateCompletionProcessor templateProcessor = createTemplateProposalComputer(context);
 		if (templateProcessor != null) {
-			ICompletionProposal[] proposals = templateProcessor
-					.computeCompletionProposals(context.getViewer(), offset);
+			ICompletionProposal[] proposals = templateProcessor.computeCompletionProposals(context.getViewer(), offset);
 			if (proposals != null && proposals.length != 0) {
 				updateTemplateProposalRelevance(context, proposals);
 			}
@@ -149,9 +139,8 @@
 	}
 
 	// Script language specific completion proposals like types or keywords
-	protected List<ICompletionProposal> computeScriptCompletionProposals(
-			int offset, ScriptContentAssistInvocationContext context,
-			IProgressMonitor monitor) {
+	protected List<ICompletionProposal> computeScriptCompletionProposals(int offset,
+			ScriptContentAssistInvocationContext context, IProgressMonitor monitor) {
 
 		// Source module getting
 		ISourceModule sourceModule = context.getSourceModule();
@@ -166,9 +155,16 @@
 		}
 
 		collector.setInvocationContext(context);
-		Point selection = context.getViewer().getSelectedRange();
-		if (selection.y > 0) {
-			collector.setReplacementLength(selection.y);
+		Runnable collectLength = () -> {
+			Point selection = context.getViewer().getSelectedRange();
+			if (selection.y > 0) {
+				collector.setReplacementLength(selection.y);
+			}
+		};
+		if (Display.getCurrent() != null) {
+			collectLength.run();
+		} else {
+			Display.getDefault().syncExec(collectLength);
 		}
 
 		// Filling collector with proposals
@@ -180,8 +176,7 @@
 							+ element.getClass());
 				}
 			}
-			int timeout = DLTKUIPlugin.getDefault().getPreferenceStore()
-					.getInt(PreferenceConstants.CODEASSIST_TIMEOUT);
+			int timeout = DLTKUIPlugin.getDefault().getPreferenceStore().getInt(PreferenceConstants.CODEASSIST_TIMEOUT);
 			collector.startCompletion();
 			sourceModule.codeComplete(offset, collector, timeout);
 			collector.endCompletion();
@@ -189,8 +184,7 @@
 			handleCodeCompletionException(e, context);
 		}
 
-		ICompletionProposal[] proposals = collector
-				.getScriptCompletionProposals();
+		ICompletionProposal[] proposals = collector.getScriptCompletionProposals();
 
 		// Checking proposals
 		if (proposals.length == 0) {
@@ -215,22 +209,21 @@
 	 * org.eclipse.core.runtime.IProgressMonitor)
 	 */
 	/*
-	 * public List computeContextInformation(ContentAssistInvocationContext
-	 * context, IProgressMonitor monitor) { if (context instanceof
-	 * ScriptContentAssistInvocationContext) {
-	 * ScriptContentAssistInvocationContext scriptContext=
-	 * (ScriptContentAssistInvocationContext) context;
+	 * public List computeContextInformation(ContentAssistInvocationContext context,
+	 * IProgressMonitor monitor) { if (context instanceof
+	 * ScriptContentAssistInvocationContext) { ScriptContentAssistInvocationContext
+	 * scriptContext= (ScriptContentAssistInvocationContext) context;
 	 *
 	 * int contextInformationPosition=
 	 * guessContextInformationPosition(scriptContext); List result=
-	 * addContextInformations(scriptContext, contextInformationPosition,
-	 * monitor); return result; } return Collections.EMPTY_LIST; }
+	 * addContextInformations(scriptContext, contextInformationPosition, monitor);
+	 * return result; } return Collections.EMPTY_LIST; }
 	 */
 
 	// Completion proposals
 	@Override
-	public List<ICompletionProposal> computeCompletionProposals(
-			ContentAssistInvocationContext context, IProgressMonitor monitor) {
+	public List<ICompletionProposal> computeCompletionProposals(ContentAssistInvocationContext context,
+			IProgressMonitor monitor) {
 
 		if (context instanceof ScriptContentAssistInvocationContext) {
 			ScriptContentAssistInvocationContext scriptContext = (ScriptContentAssistInvocationContext) context;
@@ -238,12 +231,10 @@
 			List<ICompletionProposal> proposals = new ArrayList<>();
 
 			// Language specific proposals (already sorted and etc.)
-			proposals.addAll(computeScriptCompletionProposals(
-					context.getInvocationOffset(), scriptContext, monitor));
+			proposals.addAll(computeScriptCompletionProposals(context.getInvocationOffset(), scriptContext, monitor));
 
 			// Template proposals (already sorted and etc.)
-			proposals.addAll(computeTemplateCompletionProposals(
-					context.getInvocationOffset(), scriptContext, monitor));
+			proposals.addAll(computeTemplateCompletionProposals(context.getInvocationOffset(), scriptContext, monitor));
 
 			return proposals;
 		}
@@ -251,22 +242,20 @@
 		return Collections.emptyList();
 	}
 
-	protected int guessContextInformationPosition(
-			ContentAssistInvocationContext context) {
+	protected int guessContextInformationPosition(ContentAssistInvocationContext context) {
 		return context.getInvocationOffset();
 	}
 
 	@Override
-	public List<IContextInformation> computeContextInformation(
-			ContentAssistInvocationContext context, IProgressMonitor monitor) {//
+	public List<IContextInformation> computeContextInformation(ContentAssistInvocationContext context,
+			IProgressMonitor monitor) {//
 
 		if (context instanceof ScriptContentAssistInvocationContext) {
 			ScriptContentAssistInvocationContext scriptContext = (ScriptContentAssistInvocationContext) context;
 
-			int contextInformationPosition = guessContextInformationPosition(
-					scriptContext);
-			List<IContextInformation> result = addContextInformations(
-					scriptContext, contextInformationPosition, monitor);
+			int contextInformationPosition = guessContextInformationPosition(scriptContext);
+			List<IContextInformation> result = addContextInformations(scriptContext, contextInformationPosition,
+					monitor);
 			return result;
 		}
 		return Collections.emptyList();
@@ -312,11 +301,9 @@
 	 * template support.
 	 * </p>
 	 */
-	protected TemplateCompletionProcessor createTemplateProposalComputer(
-			ScriptContentAssistInvocationContext context) {
+	protected TemplateCompletionProcessor createTemplateProposalComputer(ScriptContentAssistInvocationContext context) {
 		return null;
 	}
 
-	protected abstract ScriptCompletionProposalCollector createCollector(
-			ScriptContentAssistInvocationContext context);
+	protected abstract ScriptCompletionProposalCollector createCollector(ScriptContentAssistInvocationContext context);
 }