/* * Copyright (c) 2014, 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.core.completion; import com.google.common.util.concurrent.Uninterruptibles; import com.google.dart.server.AnalysisServerListener; import com.google.dart.server.AnalysisServerListenerAdapter; import com.google.dart.server.GetSuggestionsConsumer; import com.google.dart.server.generated.AnalysisServer; import org.dartlang.analysis.server.protocol.CompletionSuggestion; import org.dartlang.analysis.server.protocol.RequestError; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * This listener processes notifications from {@link AnalysisServer} and collects any completion * suggestions received for the given completion request. Clients should instantiate the collector * then call {@link #requestSuggestions(String, int, long)} to begin collecting completions from the * server. */ public class DartSuggestionReceiver { /** * The server providing the suggestions. */ private final AnalysisServer server; /** * Response handler for the completion.getSuggestions request. */ GetSuggestionsConsumer consumer = new GetSuggestionsConsumer() { @Override public void computedCompletionId(String completionId) { DartSuggestionReceiver.this.completionId = completionId; if (latch != null) { server.addAnalysisServerListener(listener); } } @Override public void onError(RequestError requestError) { latch.countDown(); } }; /** * The completion identifier returned by the server. */ private String completionId; /** * Notification handler for collecting suggestions from the server. */ private AnalysisServerListener listener = new AnalysisServerListenerAdapter() { @Override public void computedCompletion(String completionId, int replacementOffset, int replacementLength, List<CompletionSuggestion> completions, boolean isLast) { if (completionId.equals(DartSuggestionReceiver.this.completionId)) { DartSuggestionReceiver.this.replacementOffset = replacementOffset; DartSuggestionReceiver.this.replacementLength = replacementLength; DartSuggestionReceiver.this.suggestions = completions; // System.out.println(System.currentTimeMillis() + " >>> notification received for " // + completionId); if (isLast) { server.removeAnalysisServerListener(this); latch.countDown(); } } } }; /** * The replacement offset for the current completions. */ private int replacementOffset; /** * The replacement length for the current completions. */ private int replacementLength; /** * The suggestions returned by the server or {@code null} if none. */ private List<CompletionSuggestion> suggestions; /** * The latch used by {@link #listener} to notify {@link #requestSuggestions(String, int, long)} * when suggestions are available or {@code null} if no request has been made or if the request is * complete. */ private CountDownLatch latch; /** * {@code true} if the final code completion notification has been received by * {@link #requestSuggestions(String, int, long)} in the allotted time. */ private boolean complete; public DartSuggestionReceiver(AnalysisServer server) { this.server = server; } /** * Answer the replacement length for the current completions. */ public int getReplacementLength() { return replacementLength; } /** * Answer the replacement offset for the current completions. */ public int getReplacementOffset() { return replacementOffset; } /** * Answer the current suggestions returned by the server or {@code null} if none */ public List<CompletionSuggestion> getSuggestions() { return suggestions; } /** * Answer {@code true} if the final code completion notification has been received by * {@link #requestSuggestions(String, int, long)} in the allotted time. */ public boolean isComplete() { return complete; } /** * Send a completion request to the server. Since the server sends multiple notifications * containing suggestions, each superseding the prior notification, this method returns either the * final suggestions when they are received or the best available suggestions if the final * suggestions have not been received with the given amount of time. * * @param file The absolute path of the file in which the completion is requested * @param offset The offset in the file where the completion is requested * @param millisToWait the maximum # of milliseconds to wait for the final list of completions. * @return the completion suggestions or {@code null} if none */ public List<CompletionSuggestion> requestSuggestions(String file, int offset, long millisToWait) { latch = new CountDownLatch(1); server.completion_getSuggestions(file, offset, consumer); complete = Uninterruptibles.awaitUninterruptibly(latch, millisToWait, TimeUnit.MILLISECONDS); latch = null; server.removeAnalysisServerListener(listener); return suggestions; } }