diff options
author | Dawid Pakuła | 2018-05-19 18:32:33 +0000 |
---|---|---|
committer | Dawid Pakuła | 2018-05-22 10:46:34 +0000 |
commit | 30061a13a03c470c959f108a39b9d4f9d4ad01c0 (patch) | |
tree | e6f0c8f5fc1d43a2816e5ab577dc0e223472a0b9 | |
parent | 8914d96dd8db9bf3ad4a748c5ffc2f536596fc55 (diff) | |
download | eclipse.platform.text-30061a13a03c470c959f108a39b9d4f9d4ad01c0.tar.gz eclipse.platform.text-30061a13a03c470c959f108a39b9d4f9d4ad01c0.tar.xz eclipse.platform.text-30061a13a03c470c959f108a39b9d4f9d4ad01c0.zip |
Bug 534395 - [content assist] Prefix autocompletion not work in async mode
Change-Id: I967d74001e8a07295946b43e41e99167aa1760c2
Signed-off-by: Dawid Pakuła <zulus@w3des.net>
2 files changed, 117 insertions, 63 deletions
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/AsyncCompletionProposalPopup.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/AsyncCompletionProposalPopup.java index b1a02d8a193..26f260d4ac4 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/AsyncCompletionProposalPopup.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/AsyncCompletionProposalPopup.java @@ -21,6 +21,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; import org.eclipse.osgi.util.NLS; @@ -148,79 +149,132 @@ class AsyncCompletionProposalPopup extends CompletionProposalPopup { fFilterOffset= fInvocationOffset; fLastCompletionOffset= fFilterOffset; // start invocation of processors as Futures, and make them populate the proposals upon completion - List<ICompletionProposal> computedProposals = Collections.synchronizedList(new ArrayList<>()); fFutures= buildCompletionFuturesOrJobs(fInvocationOffset); - List<CompletableFuture<Void>> populateFutures = new ArrayList<>(fFutures.size()); - for (CompletableFuture<List<ICompletionProposal>> future : fFutures) { - populateFutures.add(future.thenAccept(proposals -> - computedProposals.addAll(proposals) - )); - } + runFutures(fInvocationOffset, null, true, autoActivated, true); + } else { + fLastCompletionOffset= fFilterOffset; + handleRepeatedInvocation(); + } - long requestBeginningTimestamp = System.currentTimeMillis(); - long stillRemainingThreeshold = MAX_WAIT_IN_MS; - for (CompletableFuture<?> future : populateFutures) { - try { - future.get(stillRemainingThreeshold, TimeUnit.MILLISECONDS); - } catch (TimeoutException | ExecutionException | InterruptedException ex) { - // future failed or took more time than we want to wait - } - stillRemainingThreeshold = MAX_WAIT_IN_MS - (System.currentTimeMillis() - requestBeginningTimestamp); - if (stillRemainingThreeshold < 0) { - // we already spent too much time (more than MAX_WAIT_IN_MS), stop waiting. - break; - } + return getErrorMessage(); + } + + @Override + void handleRepeatedInvocation() { + cancelFutures(); + fFutures= buildCompletionFuturesOrJobs(fInvocationOffset); + runFutures(fInvocationOffset, null, false, false, false); + } + + private List<ICompletionProposal> runFutures(int offset, Consumer<List<ICompletionProposal>> callback, boolean createSelector, boolean autoActivated, boolean autoInsert) { + List<ICompletionProposal> computedProposals= Collections.synchronizedList(new ArrayList<>()); + List<CompletableFuture<Void>> populateFutures= new ArrayList<>(fFutures.size()); + for (CompletableFuture<List<ICompletionProposal>> future : fFutures) { + populateFutures.add(future.thenAccept(proposals -> computedProposals.addAll(proposals))); + } + + long requestBeginningTimestamp= System.currentTimeMillis(); + long stillRemainingThreeshold= MAX_WAIT_IN_MS; + for (CompletableFuture<?> future : populateFutures) { + try { + future.get(stillRemainingThreeshold, TimeUnit.MILLISECONDS); + } catch (TimeoutException | ExecutionException | InterruptedException ex) { + // future failed or took more time than we want to wait } - fComputedProposals = computedProposals; - if (stillRemainingThreeshold > 0) { // everything ready in time, go synchronous - int count= computedProposals.size(); - if (count == 0 && hideWhenNoProposals(autoActivated)) - return null; - - if (count == 1 && !autoActivated && canAutoInsert(computedProposals.get(0))) { - insertProposal(computedProposals.get(0), (char) 0, 0, fInvocationOffset); - hide(); - } else { + stillRemainingThreeshold= MAX_WAIT_IN_MS - (System.currentTimeMillis() - requestBeginningTimestamp); + if (stillRemainingThreeshold < 0) { + // we already spent too much time (more than MAX_WAIT_IN_MS), stop waiting. + break; + } + } + fComputedProposals= computedProposals; + if (stillRemainingThreeshold > 0) { // everything ready in time, go synchronous + int count= computedProposals.size(); + if (count == 0 && hideWhenNoProposals(autoActivated)) + return computedProposals; + + if (autoInsert && count == 1 && !autoActivated && canAutoInsert(computedProposals.get(0))) { + insertProposal(computedProposals.get(0), (char) 0, 0, offset); + hide(); + } else { + if (createSelector) { createProposalSelector(); + } + if (callback != null) { + callback.accept(computedProposals); + } else { setProposals(computedProposals, false); displayProposals(); } - } else { // processors took too much time, go asynchronous + } + } else { // processors took too much time, go asynchronous + if (createSelector) { createProposalSelector(); - ComputingProposal computingProposal= new ComputingProposal(fInvocationOffset, fFutures.size()); - computedProposals.add(0, computingProposal); - fComputedProposals = computedProposals; - setProposals(fComputedProposals, false); - Set<CompletableFuture<Void>> remaining = Collections.synchronizedSet(new HashSet<>(populateFutures)); - for (CompletableFuture<Void> populateFuture : populateFutures) { - populateFuture.thenRun(() -> { - remaining.removeIf(CompletableFuture::isDone); - computingProposal.setRemaining(remaining.size()); - if (remaining.isEmpty()) { - computedProposals.remove(computingProposal); - } - List<ICompletionProposal> newProposals = new ArrayList<>(computedProposals); - fComputedProposals = newProposals; - Display.getDefault().asyncExec(() -> { - if (!autoActivated && remaining.isEmpty() && newProposals.size() == 1 && canAutoInsert(newProposals.get(0))) { - if (Helper.okToUse(fProposalShell)) { - insertProposal(newProposals.get(0), (char) 0, 0, fInvocationOffset); - hide(); - } - return; + } + ComputingProposal computingProposal= new ComputingProposal(offset, fFutures.size()); + computedProposals.add(0, computingProposal); + setProposals(fComputedProposals, false); + Set<CompletableFuture<Void>> remaining= Collections.synchronizedSet(new HashSet<>(populateFutures)); + for (CompletableFuture<Void> populateFuture : populateFutures) { + populateFuture.thenRun(() -> { + remaining.removeIf(CompletableFuture::isDone); + computingProposal.setRemaining(remaining.size()); + if (remaining.isEmpty()) { + computedProposals.remove(computingProposal); + } + List<ICompletionProposal> newProposals= new ArrayList<>(computedProposals); + fComputedProposals= newProposals; + Display.getDefault().asyncExec(() -> { + if (autoInsert && !autoActivated && remaining.isEmpty() && newProposals.size() == 1 && canAutoInsert(newProposals.get(0))) { + if (Helper.okToUse(fProposalShell)) { + insertProposal(newProposals.get(0), (char) 0, 0, offset); + hide(); } + return; + } + if (remaining.isEmpty() && callback != null) { + callback.accept(newProposals); + } else { setProposals(newProposals, false); displayProposals(); - }); + } }); - } - displayProposals(); + }); } - } else { - fLastCompletionOffset= fFilterOffset; - handleRepeatedInvocation(); + displayProposals(); + } + return computedProposals; + } + + @Override + public String incrementalComplete() { + cancelFutures(); + if (Helper.okToUse(fProposalShell) && fFilteredProposals != null) { + return super.incrementalComplete(); } + final Control control= fContentAssistSubjectControlAdapter.getControl(); + + if (fKeyListener == null) + fKeyListener= new ProposalSelectionListener(); + + if (!Helper.okToUse(fProposalShell) && !control.isDisposed()) + fContentAssistSubjectControlAdapter.addKeyListener(fKeyListener); + fInvocationOffset= fContentAssistSubjectControlAdapter.getSelectedRange().x; + fFilterOffset= fInvocationOffset; + fLastCompletionOffset= fFilterOffset; + + fFutures= buildCompletionFuturesOrJobs(fInvocationOffset); + fFilteredProposals= runFutures(fInvocationOffset, (List<ICompletionProposal> proposals) -> { + ensureDocumentListenerInstalled(); + if (proposals.size() > 0 && completeCommonPrefix()) { + hide(); + } else { + fFilteredProposals= proposals; + setProposals(proposals, false); + displayProposals(); + } + }, true, false, true); return getErrorMessage(); } diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java index 3161ed5fe1d..9951e6f2910 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java @@ -290,7 +290,7 @@ class CompletionProposalPopup implements IContentAssistListener { /** Listener filling the document event queue. */ private IDocumentListener fDocumentListener; /** The filter list of proposals. */ - private List<ICompletionProposal> fFilteredProposals; + List<ICompletionProposal> fFilteredProposals; /** The computed list of proposals. */ List<ICompletionProposal> fComputedProposals; /** The offset for which the proposals have been computed. */ @@ -1267,7 +1267,7 @@ class CompletionProposalPopup implements IContentAssistListener { * * @since 3.2 */ - private void ensureDocumentListenerInstalled() { + void ensureDocumentListenerInstalled() { if (fDocumentListener == null) { fDocumentListener= new IDocumentListener() { @Override @@ -1619,7 +1619,7 @@ class CompletionProposalPopup implements IContentAssistListener { if (count == 1 && canAutoInsert(fFilteredProposals.get(0))) { insertProposal(fFilteredProposals.get(0), (char) 0, 0, fInvocationOffset); - hide(); + hide(); } else { ensureDocumentListenerInstalled(); if (count > 0 && completeCommonPrefix()) @@ -1630,8 +1630,8 @@ class CompletionProposalPopup implements IContentAssistListener { setProposals(fComputedProposals, false); displayProposals(); } + } } - } }); } return getErrorMessage(); @@ -1647,7 +1647,7 @@ class CompletionProposalPopup implements IContentAssistListener { * selector can be closed, <code>false</code> otherwise * @since 3.0 */ - private boolean completeCommonPrefix() { + boolean completeCommonPrefix() { // 0: insert single proposals if (fFilteredProposals.size() == 1) { |