/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.ui.internal.text.dart; import com.google.dart.engine.services.assist.AssistContext; import com.google.dart.tools.core.DartCoreDebug; import com.google.dart.tools.core.completion.CompletionProposal; import com.google.dart.tools.core.internal.completion.AnalysisUtil; import com.google.dart.tools.ui.Messages; import com.google.dart.tools.ui.PreferenceConstants; import com.google.dart.tools.ui.internal.text.completion.DartMethodCompletionProposal; import com.google.dart.tools.ui.internal.text.completion.DartServerProposalCollector; import com.google.dart.tools.ui.internal.text.completion.FillArgumentNamesCompletionProposalCollector; import com.google.dart.tools.ui.internal.text.functions.DartHeuristicScanner; import com.google.dart.tools.ui.internal.text.functions.Symbols; import com.google.dart.tools.ui.text.dart.CompletionProposalCollector; import com.google.dart.tools.ui.text.dart.ContentAssistInvocationContext; import com.google.dart.tools.ui.text.dart.DartContentAssistInvocationContext; import com.google.dart.tools.ui.text.dart.IDartCompletionProposalComputer; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.contentassist.IContextInformationExtension; import org.eclipse.swt.graphics.Image; import org.eclipse.ui.IWorkbenchCommandConstants; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.keys.IBindingService; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * Computes Dart completion proposals and context infos. */ public class DartCompletionProposalComputer implements IDartCompletionProposalComputer { private static final class ContextInformationWrapper implements IContextInformation, IContextInformationExtension { private final IContextInformation fContextInformation; private int fPosition; public ContextInformationWrapper(IContextInformation contextInformation) { fContextInformation = contextInformation; } @Override public boolean equals(Object object) { if (object instanceof ContextInformationWrapper) { return fContextInformation.equals(((ContextInformationWrapper) object).fContextInformation); } else { return fContextInformation.equals(object); } } @Override public String getContextDisplayString() { return fContextInformation.getContextDisplayString(); } @Override public int getContextInformationPosition() { return fPosition; } @Override public Image getImage() { return fContextInformation.getImage(); } @Override public String getInformationDisplayString() { return fContextInformation.getInformationDisplayString(); } @Override public int hashCode() { return fContextInformation.hashCode(); } public void setContextInformationPosition(int position) { fPosition = position; } } private String fErrorMessage; public DartCompletionProposalComputer() { } @Override public List<ICompletionProposal> computeCompletionProposals( ContentAssistInvocationContext context, IProgressMonitor monitor) { if (context instanceof DartContentAssistInvocationContext) { DartContentAssistInvocationContext dartContext = (DartContentAssistInvocationContext) context; return internalCreateCompletionProposals(context.getInvocationOffset(), dartContext); } return Collections.emptyList(); } @Override public List<IContextInformation> computeContextInformation( ContentAssistInvocationContext context, IProgressMonitor monitor) { if (context instanceof DartContentAssistInvocationContext) { DartContentAssistInvocationContext javaContext = (DartContentAssistInvocationContext) context; int contextInformationPosition = guessContextInformationPosition(javaContext); List<IContextInformation> result = addContextInformations( javaContext, contextInformationPosition); return result; } return Collections.emptyList(); } @Override public String getErrorMessage() { return fErrorMessage; } @Override public void sessionEnded() { fErrorMessage = null; } @Override public void sessionStarted() { } /** * Creates the collector used to get proposals from core. * * @param context the context * @return the collector */ protected CompletionProposalCollector createCollector(DartContentAssistInvocationContext context) { if (PreferenceConstants.getPreferenceStore().getBoolean( PreferenceConstants.CODEASSIST_FILL_ARGUMENT_NAMES)) { return new FillArgumentNamesCompletionProposalCollector(context); } else { return new CompletionProposalCollector(true); } } protected int guessContextInformationPosition(ContentAssistInvocationContext context) { return context.getInvocationOffset(); } protected final int guessMethodContextInformationPosition(ContentAssistInvocationContext context) { final int contextPosition = context.getInvocationOffset(); IDocument document = context.getDocument(); DartHeuristicScanner scanner = new DartHeuristicScanner(document); int bound = Math.max(-1, contextPosition - 200); // try the innermost scope of parentheses that looks like a method call int pos = contextPosition - 1; do { int paren = scanner.findOpeningPeer(pos, bound, '(', ')'); if (paren == DartHeuristicScanner.NOT_FOUND) { break; } int token = scanner.previousToken(paren - 1, bound); // next token must be a method name (identifier) or the closing angle of a // constructor call of a parameterized type. if (token == Symbols.TokenIDENT || token == Symbols.TokenGREATERTHAN) { return paren + 1; } pos = paren - 1; } while (true); return contextPosition; } private List<IContextInformation> addContextInformations( DartContentAssistInvocationContext context, int offset) { List<ICompletionProposal> proposals = Collections.emptyList(); List<IContextInformation> result = new ArrayList<IContextInformation>(proposals.size()); List<IContextInformation> anonymousResult = new ArrayList<IContextInformation>(proposals.size()); for (Iterator<ICompletionProposal> it = proposals.iterator(); it.hasNext();) { ICompletionProposal proposal = it.next(); IContextInformation contextInformation = proposal.getContextInformation(); if (contextInformation != null) { ContextInformationWrapper wrapper = new ContextInformationWrapper(contextInformation); wrapper.setContextInformationPosition(offset); result.add(wrapper); } } if (result.size() == 0) { return anonymousResult; } return result; } /** * Returns the array with favorite static members. * * @return the <code>String</code> array with with favorite static members */ private String[] getFavoriteStaticMembers() { String serializedFavorites = PreferenceConstants.getPreferenceStore().getString( PreferenceConstants.CODEASSIST_FAVORITE_STATIC_MEMBERS); if (serializedFavorites != null && serializedFavorites.length() > 0) { return serializedFavorites.split(";"); //$NON-NLS-1$ } return new String[0]; } // This method will replace internalComputeCompletionProposals() @SuppressWarnings("deprecation") private List<ICompletionProposal> internalCreateCompletionProposals(int offset, DartContentAssistInvocationContext context) { if (DartCoreDebug.ENABLE_ANALYSIS_SERVER) { DartServerProposalCollector collector = context.getCollector(); if (collector != null) { return collector.getProposals(); } return new ArrayList<ICompletionProposal>(); } final CompletionProposalCollector collector = createCollector(context); collector.setInvocationContext(context); collector.setAllowsRequiredProposals( CompletionProposal.FIELD_REF, CompletionProposal.TYPE_REF, true); collector.setAllowsRequiredProposals( CompletionProposal.FIELD_REF, CompletionProposal.TYPE_IMPORT, true); collector.setAllowsRequiredProposals( CompletionProposal.FIELD_REF, CompletionProposal.FIELD_IMPORT, true); collector.setAllowsRequiredProposals( CompletionProposal.METHOD_REF, CompletionProposal.TYPE_REF, true); collector.setAllowsRequiredProposals( CompletionProposal.METHOD_REF, CompletionProposal.TYPE_IMPORT, true); collector.setAllowsRequiredProposals( CompletionProposal.METHOD_REF, CompletionProposal.METHOD_IMPORT, true); collector.setAllowsRequiredProposals( CompletionProposal.CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF, true); collector.setAllowsRequiredProposals( CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF, true); collector.setAllowsRequiredProposals( CompletionProposal.ANONYMOUS_CLASS_DECLARATION, CompletionProposal.TYPE_REF, true); collector.setAllowsRequiredProposals( CompletionProposal.TYPE_REF, CompletionProposal.TYPE_REF, true); collector.setAllowsRequiredProposals( CompletionProposal.TYPE_IMPORT, CompletionProposal.TYPE_IMPORT, true); collector.setFavoriteReferences(getFavoriteStaticMembers()); AssistContext assistContext = context.getAssistContext(); if (assistContext == null) { return Collections.emptyList(); } try { com.google.dart.engine.services.completion.CompletionFactory factory; AnalysisUtil util = new AnalysisUtil(); util.setRequestor(collector); factory = new com.google.dart.engine.services.completion.CompletionFactory(); com.google.dart.engine.services.completion.CompletionEngine engine; engine = new com.google.dart.engine.services.completion.CompletionEngine(util, factory); engine.complete(assistContext); } catch (OperationCanceledException x) { IBindingService bindingSvc = (IBindingService) PlatformUI.getWorkbench().getAdapter( IBindingService.class); String keyBinding = bindingSvc.getBestActiveBindingFormattedFor(IWorkbenchCommandConstants.EDIT_CONTENT_ASSIST); fErrorMessage = Messages.format( DartTextMessages.CompletionProcessor_error_javaCompletion_took_too_long_message, keyBinding); } ICompletionProposal[] javaProposals = collector.getDartCompletionProposals(); int contextInformationOffset = guessMethodContextInformationPosition(context); if (contextInformationOffset != offset) { for (int i = 0; i < javaProposals.length; i++) { if (javaProposals[i] instanceof DartMethodCompletionProposal) { DartMethodCompletionProposal jmcp = (DartMethodCompletionProposal) javaProposals[i]; jmcp.setContextInformationPosition(contextInformationOffset); } } } List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>( Arrays.asList(javaProposals)); if (proposals.size() == 0) { String error = collector.getErrorMessage(); if (error.length() > 0) { fErrorMessage = error; } } return proposals; } }