/** * Copyright (c) 2010, 2013 Darmstadt University of Technology. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Marcel Bruch - initial API and implementation. */ package org.eclipse.recommenders.completion.rcp; import static com.google.common.base.Optional.*; import static com.google.common.base.Throwables.propagate; import static java.lang.Character.isJavaIdentifierPart; import static org.eclipse.recommenders.utils.Checks.*; import java.util.Collections; import org.eclipse.jdt.core.CompletionContext; import org.eclipse.jdt.core.CompletionProposal; import org.eclipse.jdt.core.CompletionRequestor; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility; import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; import org.eclipse.jdt.ui.text.java.IInvocationContext; import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.ui.IEditorPart; import com.google.common.annotations.Beta; import com.google.common.base.Function; import com.google.common.base.Optional; @Beta @SuppressWarnings("restriction") public final class CompletionContexts { private CompletionContexts() { // Not meant to be instantiated } /** * Given a completion's display string like 'ArrayList()', it returns the substring of the display string used to * match a user-entered prefix and the completion, i.e., 'ArrayList' without brackets in this case. * <p> * Examples: * * <pre> * add(Object o) --> add * ArrayList(Collection c) --> ArrayList * org.eclipse.other --> org.eclipse.other * {@link} --> {@link} * {@link Example} --> Example * {@link Example#method()} --> method * {@value Collections#EMPTY_LIST} --> EMPTY_LIST * <blockquote> --> blockquote * </blockquote> --> blockquote * </pre> * */ public static String getPrefixMatchingArea(String displayString) { displayString = stripHtmlTagDelimiters(displayString); displayString = stripValueOrLinkDelimiters(displayString); int end = displayString.length(); for (int i = 0; i < displayString.length(); i++) { char c = displayString.charAt(i); if (!isJavaIdentifierLike(c) && c != '.') { end = i; break; } } return displayString.substring(0, end); } private static String stripHtmlTagDelimiters(String string) { if (string.startsWith("<") && string.endsWith(">")) { //$NON-NLS-1$ //$NON-NLS-2$ boolean isClosingTag = string.charAt(1) == '/'; return string.substring(isClosingTag ? 2 : 1, string.length() - 1); } else { return string; } } private static String stripValueOrLinkDelimiters(String string) { if (string.startsWith("{@value ") && string.endsWith("}")) { //$NON-NLS-1$ //$NON-NLS-2$ int lastIndexOfHash = string.lastIndexOf('#'); int start = lastIndexOfHash < 0 ? "{@value ".length() : lastIndexOfHash; //$NON-NLS-1$ return string.substring(start + 1, string.length() - 1); } else if (string.startsWith("{@link ") && string.endsWith("}")) { //$NON-NLS-1$ //$NON-NLS-2$ int lastIndexOfHash = string.lastIndexOf('#'); int start = lastIndexOfHash < 0 ? "{@link ".length() : lastIndexOfHash + 1; //$NON-NLS-1$ return string.substring(start, string.length() - 1); } else { return string; } } private static boolean isJavaIdentifierLike(char c) { return isJavaIdentifierPart(c) || c == '#' || c == '@' || c == '{' || c == '}'; } /** * Creates a content assist invocation context from a quick fix invocation context. */ public static JavaContentAssistInvocationContext toContentAssistInvocationContext(IInvocationContext context) { ensureIsNotNull(context); return new QuickFixToContentAssistContextFunction().apply(context); } /** * Creates a simple (i.e., not extended) completion context. * <p> * This context may be used for snippet completions. */ public static Optional<JavaContentAssistInvocationContext> newContentAssistInvocationContext(IEditorPart editor) { if (editor instanceof JavaEditor) { JavaEditor ed = (JavaEditor) editor; ISourceViewer viewer = ed.getViewer(); int offset = viewer.getTextWidget().getCaretOffset(); return of(new JavaContentAssistInvocationContext(viewer, offset, ed)); } return absent(); } static final class QuickFixToContentAssistContextFunction implements Function<IInvocationContext, JavaContentAssistInvocationContext> { private CompletionContext internalContext; @Override public JavaContentAssistInvocationContext apply(IInvocationContext context) { ICompilationUnit cu = context.getCompilationUnit(); int offset = context.getSelectionOffset(); try { cu.codeComplete(offset, new CompletionRequestor() { @Override public void acceptContext(CompletionContext context) { internalContext = context; } @Override public boolean isExtendedContextRequired() { return true; } @Override public void accept(CompletionProposal proposal) { } }); } catch (JavaModelException e) { propagate(e); } JavaEditor editor = cast(EditorUtility.isOpenInEditor(cu)); ISourceViewer viewer = editor.getViewer(); return new JavaContentAssistInvocationContext(viewer, offset, editor) { @Override public CompletionContext getCoreContext() { return internalContext; } }; } } }