/* * 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.DartCore; import com.google.dart.tools.core.DartCoreDebug; import com.google.dart.tools.core.completion.DartSuggestionReceiver; import com.google.dart.tools.internal.corext.refactoring.util.ExecutionUtils; import com.google.dart.tools.ui.internal.text.completion.DartServerProposalCollector; import com.google.dart.tools.ui.internal.text.editor.DartEditor; 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.editor.tmp.JavaScriptCore; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.contentassist.ContentAssistant; import org.eclipse.jface.text.contentassist.IContextInformationValidator; import org.eclipse.swt.custom.StyledText; import org.eclipse.ui.IEditorPart; import java.util.HashMap; import java.util.List; /** * Dart completion processor. */ public class DartCompletionProcessor extends ContentAssistProcessor { private final static String VISIBILITY = JavaScriptCore.CODEASSIST_VISIBILITY_CHECK; private final static String ENABLED = "enabled"; //$NON-NLS-1$ private final static String DISABLED = "disabled"; //$NON-NLS-1$ private IContextInformationValidator fValidator; protected final IEditorPart fEditor; private AssistContext assistContext; private DartServerProposalCollector collector; public DartCompletionProcessor(IEditorPart editor, ContentAssistant assistant, String partition) { super(assistant, partition); fEditor = editor; } /** * Called on the UI thread to filter the proposals based upon the current document text. */ public void filterProposals(IDocument document, int offset) { if (collector != null) { collector.filterProposals(document, offset); } } /* * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor# * getContextInformationValidator() */ @Override public IContextInformationValidator getContextInformationValidator() { if (fValidator == null) { fValidator = new DartParameterListValidator(); } return fValidator; } /** * Tells this processor to restrict is proposals to those starting with matching cases. * * @param restrict <code>true</code> if proposals should be restricted */ public void restrictProposalsToMatchingCases(boolean restrict) { // not yet supported } /** * Tells this processor to restrict its proposal to those element visible in the actual invocation * context. * * @param restrict <code>true</code> if proposals should be restricted */ public void restrictProposalsToVisibility(boolean restrict) { HashMap<String, String> options = DartCore.getOptions(); Object value = options.get(VISIBILITY); if (value instanceof String) { String newValue = restrict ? ENABLED : DISABLED; if (!newValue.equals(value)) { options.put(VISIBILITY, newValue); DartCore.setOptions(options); } } } /** * Wait up to the given amount of time for the receiver to ready. This may involve communication * with the Analysis Server and should not be called on the UI thread. * * @param auto {@code true} if triggered automatically such as when the user types a "." * @return {@code true} if the processor is ready, else {@code false} */ public boolean waitUntilReady(boolean auto, int offset) { return DartCoreDebug.ENABLE_ANALYSIS_SERVER ? waitUntilReady_NEW(auto, offset) : waitUntilReady_OLD(); } /* * @see com.google.dart.tools.ui.internal.text.dart.ContentAssistProcessor# createContext * (org.eclipse.jface.text.ITextViewer, int) */ @Override protected ContentAssistInvocationContext createContext(ITextViewer viewer, int offset) { return new DartContentAssistInvocationContext(viewer, offset, fEditor, assistContext, collector); } /* * @see com.google.dart.tools.ui.internal.text.dart.ContentAssistProcessor# filterAndSort * (java.util.List, org.eclipse.core.runtime.IProgressMonitor) */ @SuppressWarnings("rawtypes") @Override protected List filterAndSortProposals(List proposals, IProgressMonitor monitor, final ContentAssistInvocationContext context) { if (DartCoreDebug.ENABLE_ANALYSIS_SERVER) { // Proposals have already been sorted on a background thread } else { ProposalSorterRegistry.getDefault().getCurrentSorter().sortProposals(context, proposals); } return proposals; } /** * Return the offset of the start of the text to be replaced. */ int getReplacementOffset() { return collector != null ? collector.getReplacementOffset() : 0; } private boolean waitUntilReady_NEW(boolean auto, int offset) { // TODO(scheglov) restore or remove for the new API // collector.acceptContext(new InternalCompletionContext()); final DartEditor dartEditor = (DartEditor) fEditor; // Ensure the server has the latest content before requesting suggestions dartEditor.getDartReconcilingStrategy().reconcile(); // Request suggestions from server DartSuggestionReceiver receiver = new DartSuggestionReceiver(DartCore.getAnalysisServer()); // System.out.println(System.currentTimeMillis() + " >>> completion requested"); // TODO (danrubel) how long should we wait for completions? receiver.requestSuggestions(dartEditor.getInputFilePath(), offset, auto ? 150 : 1500); // Translate server suggestions into Eclipse proposals collector = new DartServerProposalCollector(auto, receiver); final boolean sortedProposals = collector.computeAndSortProposals(); // List<ICompletionProposal> proposals = collector.getProposals(); // System.out.println(System.currentTimeMillis() + " >>> " // + (proposals != null ? proposals.size() : "no") + " suggestions" + (auto ? " [auto]" : "")); return sortedProposals; } private boolean waitUntilReady_OLD() { final DartEditor dartEditor = (DartEditor) fEditor; DartReconcilingStrategy strategy = dartEditor.getDartReconcilingStrategy(); if (strategy != null) { strategy.reconcile(); } // Block background thread up to 8 seconds waiting for old java based dart analysis long endTime = System.currentTimeMillis() + 8000; while (System.currentTimeMillis() < endTime) { StyledText control = dartEditor.getViewer().getTextWidget(); if (control.isDisposed()) { return false; } control.getDisplay().syncExec(new Runnable() { @Override public void run() { assistContext = dartEditor.getAssistContext(); } }); if (assistContext != null) { return true; } ExecutionUtils.sleep(5); } return false; } }