diff options
author | Mickael Istria | 2017-09-13 16:51:46 +0000 |
---|---|---|
committer | Mickael Istria | 2017-09-24 20:24:25 +0000 |
commit | d9b4c1b5fa395ecc797e2b66c23885ca6e88f31d (patch) | |
tree | 371a3f8f50c588ff4e0dc13c469b936841d033ac | |
parent | a094046b191efc72bef93d227499cb75bc532e87 (diff) | |
download | eclipse.platform.text-d9b4c1b5fa395ecc797e2b66c23885ca6e88f31d.tar.gz eclipse.platform.text-d9b4c1b5fa395ecc797e2b66c23885ca6e88f31d.tar.xz eclipse.platform.text-d9b4c1b5fa395ecc797e2b66c23885ca6e88f31d.zip |
Bug 522255 - Filter/restart completion session only uses 1st processorI20170927-2000I20170927-0420I20170926-2000I20170925-2000
Change-Id: Ie5697da68555f80569c870c6d54ea7f0ec94370a
Signed-off-by: Mickael Istria <mistria@redhat.com>
4 files changed, 219 insertions, 153 deletions
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/ContentAssistant.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/ContentAssistant.java index 72c62e98716..838eba116f1 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/ContentAssistant.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/ContentAssistant.java @@ -15,11 +15,17 @@ *******************************************************************************/ package org.eclipse.jface.text.contentassist; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.function.Function; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTError; @@ -1909,16 +1915,16 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt * * @param viewer the text viewer * @param offset a offset within the document - * @return a content-assist processor or <code>null</code> if none exists - * @since 3.0 + * @return the content-assist processors or <code>null</code> if none exists + * @since 3.13 */ - private IContentAssistProcessor getProcessor(ITextViewer viewer, int offset) { + private Set<IContentAssistProcessor> getProcessors(ITextViewer viewer, int offset) { try { IDocument document= viewer.getDocument(); String type= TextUtilities.getContentType(document, getDocumentPartitioning(), offset, true); - return getContentAssistProcessor(type); + return getContentAssistProcessors(type); } catch (BadLocationException x) { } @@ -1927,14 +1933,14 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt } /** - * Returns the content assist processor for the content type of the specified document position. + * Returns the content assist processors for the content type of the specified document position. * * @param contentAssistSubjectControl the content assist subject control * @param offset a offset within the document - * @return a content-assist processor or <code>null</code> if none exists - * @since 3.0 + * @return the content-assist processors or <code>null</code> if none exists + * @since 3.13 */ - private IContentAssistProcessor getProcessor(IContentAssistSubjectControl contentAssistSubjectControl, int offset) { + private Set<IContentAssistProcessor> getProcessors(IContentAssistSubjectControl contentAssistSubjectControl, int offset) { try { IDocument document= contentAssistSubjectControl.getDocument(); @@ -1944,7 +1950,7 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt else type= IDocument.DEFAULT_CONTENT_TYPE; - return getContentAssistProcessor(type); + return getContentAssistProcessors(type); } catch (BadLocationException x) { } @@ -1966,22 +1972,25 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt final IContentAssistSubjectControl contentAssistSubjectControl, final int offset) { fLastErrorMessage= null; - final ICompletionProposal[][] result= { null }; - - final IContentAssistProcessor p= getProcessor(contentAssistSubjectControl, offset); - if (p instanceof ISubjectControlContentAssistProcessor) { - // Ensure that the assist session ends cleanly even if the processor throws an exception. - SafeRunner.run(new ExceptionLoggingSafeRunnable(COMPLETION_ERROR_MESSAGE_KEY) { - @Override - public void run() throws Exception { - result[0]= ((ISubjectControlContentAssistProcessor) p) - .computeCompletionProposals(contentAssistSubjectControl, offset); - fLastErrorMessage= p.getErrorMessage(); + final List<ICompletionProposal> result= new ArrayList<>(); + final Set<IContentAssistProcessor> processors= getProcessors(contentAssistSubjectControl, offset); + if (processors != null) { + processors.forEach(p -> { + if (p instanceof ISubjectControlContentAssistProcessor) { + // Ensure that the assist session ends cleanly even if the processor throws an exception. + SafeRunner.run(new ExceptionLoggingSafeRunnable(COMPLETION_ERROR_MESSAGE_KEY) { + @Override + public void run() throws Exception { + result.addAll(Arrays.asList( ((ISubjectControlContentAssistProcessor) p) + .computeCompletionProposals(contentAssistSubjectControl, offset))); + fLastErrorMessage= p.getErrorMessage(); + } + }); } }); } - return result[0]; + return result.isEmpty() ? null : result.toArray(new ICompletionProposal[result.size()]); } /** @@ -1996,21 +2005,22 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt ICompletionProposal[] computeCompletionProposals(final ITextViewer viewer, final int offset) { fLastErrorMessage= null; - final ICompletionProposal[][] result= { null }; - - final IContentAssistProcessor p= getProcessor(viewer, offset); - if (p != null) { + final Set<IContentAssistProcessor> processors= getProcessors(viewer, offset); + final List<ICompletionProposal> res = new ArrayList<>(); + if (processors != null && !processors.isEmpty()) { // Ensure that the assist session ends cleanly even if the processor throws an exception. SafeRunner.run(new ExceptionLoggingSafeRunnable(COMPLETION_ERROR_MESSAGE_KEY) { @Override public void run() throws Exception { - result[0]= p.computeCompletionProposals(viewer, offset); - fLastErrorMessage= p.getErrorMessage(); + processors.forEach(p -> { + res.addAll(Arrays.asList(p.computeCompletionProposals(viewer, offset))); + fLastErrorMessage= p.getErrorMessage(); + }); } }); } - return result[0]; + return res.isEmpty() ? null : res.toArray(new ICompletionProposal[res.size()]); } /** @@ -2026,21 +2036,22 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt IContextInformation[] computeContextInformation(final ITextViewer viewer, final int offset) { fLastErrorMessage= null; - final IContextInformation[][] result= { null }; - - final IContentAssistProcessor p= getProcessor(viewer, offset); - if (p != null) { + final List<IContextInformation> result= new ArrayList<>(); + final Set<IContentAssistProcessor> processors= getProcessors(viewer, offset); + if (processors != null && !processors.isEmpty()) { // Ensure that the assist session ends cleanly even if the processor throws an exception. SafeRunner.run(new ExceptionLoggingSafeRunnable(CONTEXT_ERROR_MESSAGE_KEY) { @Override public void run() throws Exception { - result[0]= p.computeContextInformation(viewer, offset); - fLastErrorMessage= p.getErrorMessage(); + processors.forEach(p -> { + result.addAll(Arrays.asList(p.computeContextInformation(viewer, offset))); + fLastErrorMessage= p.getErrorMessage(); + }); } }); } - return result[0]; + return result.isEmpty() ? null : result.toArray(new IContextInformation[result.size()]); } /** @@ -2058,22 +2069,25 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt final IContentAssistSubjectControl contentAssistSubjectControl, final int offset) { fLastErrorMessage= null; - final IContextInformation[][] result= { null }; - - final IContentAssistProcessor p= getProcessor(contentAssistSubjectControl, offset); - if (p instanceof ISubjectControlContentAssistProcessor) { - // Ensure that the assist session ends cleanly even if the processor throws an exception. - SafeRunner.run(new ExceptionLoggingSafeRunnable(CONTEXT_ERROR_MESSAGE_KEY) { - @Override - public void run() throws Exception { - result[0]= ((ISubjectControlContentAssistProcessor) p) - .computeContextInformation(contentAssistSubjectControl, offset); - fLastErrorMessage= p.getErrorMessage(); + final List<IContextInformation> result= new ArrayList<>(); + final Set<IContentAssistProcessor> processors = getProcessors(contentAssistSubjectControl, offset); + if (processors != null) { + processors.forEach(p -> { + if (p instanceof ISubjectControlContentAssistProcessor) { + // Ensure that the assist session ends cleanly even if the processor throws an exception. + SafeRunner.run(new ExceptionLoggingSafeRunnable(CONTEXT_ERROR_MESSAGE_KEY) { + @Override + public void run() throws Exception { + result.addAll(Arrays.asList( ((ISubjectControlContentAssistProcessor) p) + .computeContextInformation(contentAssistSubjectControl, offset))); + fLastErrorMessage= p.getErrorMessage(); + } + }); } }); } - return result[0]; + return result.isEmpty() ? null : result.toArray(new IContextInformation[result.size()]); } /** @@ -2088,7 +2102,12 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt * @since 3.0 */ IContextInformationValidator getContextInformationValidator(ITextViewer viewer, int offset) { - IContentAssistProcessor p= getProcessor(viewer, offset); + Set<IContentAssistProcessor> processors= getProcessors(viewer, offset); + if (processors == null || processors.isEmpty()) { + return null; + } + // pick first one, arbitrary + IContentAssistProcessor p = processors.iterator().next(); return p != null ? p.getContextInformationValidator() : null; } @@ -2104,7 +2123,12 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt * @since 3.0 */ IContextInformationValidator getContextInformationValidator(IContentAssistSubjectControl contentAssistSubjectControl, int offset) { - IContentAssistProcessor p= getProcessor(contentAssistSubjectControl, offset); + Set<IContentAssistProcessor> processors= getProcessors(contentAssistSubjectControl, offset); + if (processors == null || processors.isEmpty()) { + return null; + } + // pick first one, arbitrary + IContentAssistProcessor p = processors.iterator().next(); return p != null ? p.getContextInformationValidator() : null; } @@ -2152,8 +2176,7 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt * @since 3.0 */ char[] getCompletionProposalAutoActivationCharacters(IContentAssistSubjectControl contentAssistSubjectControl, int offset) { - IContentAssistProcessor p= getProcessor(contentAssistSubjectControl, offset); - return p != null ? p.getCompletionProposalAutoActivationCharacters() : null; + return mergeResults(getProcessors(contentAssistSubjectControl, offset), IContentAssistProcessor::getCompletionProposalAutoActivationCharacters); } /** @@ -2167,8 +2190,7 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt * @see IContentAssistProcessor#getCompletionProposalAutoActivationCharacters() */ char[] getCompletionProposalAutoActivationCharacters(ITextViewer viewer, int offset) { - IContentAssistProcessor p= getProcessor(viewer, offset); - return p != null ? p.getCompletionProposalAutoActivationCharacters() : null; + return mergeResults(getProcessors(viewer, offset), IContentAssistProcessor::getCompletionProposalAutoActivationCharacters); } /** @@ -2183,8 +2205,7 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt * @since 3.0 */ char[] getContextInformationAutoActivationCharacters(ITextViewer viewer, int offset) { - IContentAssistProcessor p= getProcessor(viewer, offset); - return p != null ? p.getContextInformationAutoActivationCharacters() : null; + return mergeResults(getProcessors(viewer, offset), IContentAssistProcessor::getContextInformationAutoActivationCharacters); } /** @@ -2199,8 +2220,34 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt * @since 3.0 */ char[] getContextInformationAutoActivationCharacters(IContentAssistSubjectControl contentAssistSubjectControl, int offset) { - IContentAssistProcessor p= getProcessor(contentAssistSubjectControl, offset); - return p != null ? p.getContextInformationAutoActivationCharacters() : null; + return mergeResults(getProcessors(contentAssistSubjectControl, offset), IContentAssistProcessor::getContextInformationAutoActivationCharacters); + } + + private char[] mergeResults(Collection<IContentAssistProcessor> processors, Function<IContentAssistProcessor, char[]> f) { + char[][] arrays = processors.stream() + .map(f) + .filter(Objects::nonNull) + .filter(array -> array.length > 0) + .toArray(char[][]::new); + if (arrays.length == 0) { + return null; + } else if (arrays.length == 1) { + return arrays[0]; + } else { + LinkedHashSet<Character> res = new LinkedHashSet<>(); + for (char[] current : arrays) { + for (char c : current) { + res.add(Character.valueOf(c)); + } + } + char[] array = new char[res.size()]; + int index = 0; + for (Character c : res) { + array[index] = c.charValue(); + index++; + } + return array; + } } @Override @@ -2443,11 +2490,12 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt */ void fireSessionBeginEvent(boolean isAutoActivated) { if (fContentAssistSubjectControlAdapter != null && !isProposalPopupActive()) { - IContentAssistProcessor processor= getProcessor(fContentAssistSubjectControlAdapter, fContentAssistSubjectControlAdapter.getSelectedRange().x); - ContentAssistEvent event= new ContentAssistEvent(this, processor, isAutoActivated); - for (ICompletionListener listener : fCompletionListeners) { - listener.assistSessionStarted(event); - } + getProcessors(fContentAssistSubjectControlAdapter, fContentAssistSubjectControlAdapter.getSelectedRange().x).forEach(processor -> { + ContentAssistEvent event= new ContentAssistEvent(this, processor, isAutoActivated); + for (ICompletionListener listener : fCompletionListeners) { + listener.assistSessionStarted(event); + } + }); } } @@ -2458,12 +2506,13 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt */ void fireSessionRestartEvent() { if (fContentAssistSubjectControlAdapter != null) { - IContentAssistProcessor processor= getProcessor(fContentAssistSubjectControlAdapter, fContentAssistSubjectControlAdapter.getSelectedRange().x); - ContentAssistEvent event= new ContentAssistEvent(this, processor); - for (ICompletionListener listener : fCompletionListeners) { - if (listener instanceof ICompletionListenerExtension) - ((ICompletionListenerExtension)listener).assistSessionRestarted(event); - } + getProcessors(fContentAssistSubjectControlAdapter, fContentAssistSubjectControlAdapter.getSelectedRange().x).forEach(processor -> { + ContentAssistEvent event= new ContentAssistEvent(this, processor); + for (ICompletionListener listener : fCompletionListeners) { + if (listener instanceof ICompletionListenerExtension) + ((ICompletionListenerExtension)listener).assistSessionRestarted(event); + } + }); } } @@ -2474,11 +2523,12 @@ public class ContentAssistant implements IContentAssistant, IContentAssistantExt */ void fireSessionEndEvent() { if (fContentAssistSubjectControlAdapter != null) { - IContentAssistProcessor processor= getProcessor(fContentAssistSubjectControlAdapter, fContentAssistSubjectControlAdapter.getSelectedRange().x); - ContentAssistEvent event= new ContentAssistEvent(this, processor); - for (ICompletionListener listener : fCompletionListeners) { - listener.assistSessionEnded(event); - } + getProcessors(fContentAssistSubjectControlAdapter, fContentAssistSubjectControlAdapter.getSelectedRange().x).forEach(processor -> { + ContentAssistEvent event= new ContentAssistEvent(this, processor); + for (ICompletionListener listener : fCompletionListeners) { + listener.assistSessionEnded(event); + } + }); } } diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/CompletionTest.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/CompletionTest.java index 7ed46a86486..31b0543957f 100644 --- a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/CompletionTest.java +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/CompletionTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Red Hat Inc. and others + * Copyright (c) 2016-2017 Red Hat Inc. and others * 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 @@ -14,9 +14,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.Arrays; -import java.util.HashSet; import java.util.Set; +import java.util.stream.Collectors; +import org.junit.After; import org.junit.Test; import org.eclipse.swt.SWT; @@ -24,13 +25,13 @@ import org.eclipse.swt.custom.ST; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.Widget; +import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.tests.util.DisplayHelper; @@ -45,65 +46,78 @@ import org.eclipse.ui.texteditor.ITextEditorActionConstants; */ public class CompletionTest extends AbstratGenericEditorTest { + private Shell completionShell; + @Test public void testCompletion() throws Exception { - Set<Shell> beforeShell = new HashSet<>(Arrays.asList(Display.getDefault().getShells())); + final Set<Shell> beforeShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet()); editor.selectAndReveal(3, 0); ContentAssistAction action = (ContentAssistAction) editor.getAction(ITextEditorActionConstants.CONTENT_ASSIST); action.update(); action.run(); waitAndDispatch(100); - Set<Shell> afterShell = new HashSet<>(Arrays.asList(Display.getDefault().getShells())); - afterShell.removeAll(beforeShell); - assertEquals("No completion", 1, afterShell.size()); - Shell completionShell= afterShell.iterator().next(); + this.completionShell= findNewShell(beforeShells); final Table completionProposalList = findCompletionSelectionControl(completionShell); + checkCompletionContent(completionProposalList); + // TODO find a way to actually trigger completion and verify result against Editor content + // Assert.assertEquals("Completion didn't complete", "bars are good for a beer.", ((StyledText)editor.getAdapter(Control.class)).getText()); + } + + /** + * Checks that completion behaves as expected: + * 1. Computing is shown instantaneously + * 2. 1st proposal shown instantaneously + * 3. 2s later, 2nd proposal is shown + * @param completionProposalList the completion list + */ + private void checkCompletionContent(final Table completionProposalList) { // should be instantaneous, but happens to go asynchronous on CI so let's allow a wait new DisplayHelper() { @Override protected boolean condition() { return completionProposalList.getItemCount() == 2; } - }.waitForCondition(completionShell.getDisplay(), 200); + }.waitForCondition(completionProposalList.getDisplay(), 200); assertEquals(2, completionProposalList.getItemCount()); final TableItem computingItem = completionProposalList.getItem(0); assertTrue("Missing computing info entry", computingItem.getText().contains("Computing")); //$NON-NLS-1$ //$NON-NLS-2$ TableItem completionProposalItem = completionProposalList.getItem(1); - ICompletionProposal completionProposal = (ICompletionProposal)completionProposalItem.getData(); - assertEquals(BarContentAssistProcessor.PROPOSAL, completionProposal .getDisplayString()); + final ICompletionProposal selectedProposal = (ICompletionProposal)completionProposalItem.getData(); + assertTrue("Incorrect proposal content", BarContentAssistProcessor.PROPOSAL.endsWith(selectedProposal .getDisplayString())); completionProposalList.setSelection(completionProposalItem); // asynchronous new DisplayHelper() { @Override protected boolean condition() { - return completionProposalList.getItem(0) != computingItem; + return completionProposalList.getItem(0) != computingItem && completionProposalList.getItemCount() == 2; } - }.waitForCondition(completionShell.getDisplay(), LongRunningBarContentAssistProcessor.DELAY + 200); - assertEquals(2, completionProposalList.getItemCount()); + }.waitForCondition(completionProposalList.getDisplay(), LongRunningBarContentAssistProcessor.DELAY + 200); completionProposalItem = completionProposalList.getItem(0); - assertEquals(BarContentAssistProcessor.PROPOSAL, ((ICompletionProposal)completionProposalItem.getData()).getDisplayString()); + assertTrue("Proposal content seems incorrect", BarContentAssistProcessor.PROPOSAL.endsWith(((ICompletionProposal)completionProposalItem.getData()).getDisplayString())); TableItem otherProposalItem = completionProposalList.getItem(1); - assertEquals(LongRunningBarContentAssistProcessor.PROPOSAL, ((ICompletionProposal)otherProposalItem.getData()).getDisplayString()); - assertEquals("Addition of completion proposal should keep selection", completionProposal, completionProposalList.getSelection()[0].getData()); + assertTrue("Proposal content seems incorrect", LongRunningBarContentAssistProcessor.PROPOSAL.endsWith(((ICompletionProposal)otherProposalItem.getData()).getDisplayString())); + assertEquals("Addition of completion proposal should keep selection", selectedProposal, completionProposalList.getSelection()[0].getData()); + } - // TODO find a way to actually trigger completion and verify result against Editor content - // Assert.assertEquals("Completion didn't complete", "bars are good for a beer.", ((StyledText)editor.getAdapter(Control.class)).getText()); - completionShell.close(); + private Shell findNewShell(Set<Shell> beforeShells) { + Shell[] afterShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()) + .filter(Shell::isVisible) + .filter(shell -> !beforeShells.contains(shell)) + .toArray(Shell[]::new); + assertEquals("No new shell found", 1, afterShells.length); + return afterShells[0]; } @Test public void testCompletionFreeze_bug521484() throws Exception { - Set<Shell> beforeShell = new HashSet<>(Arrays.asList(Display.getDefault().getShells())); + final Set<Shell> beforeShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet()); editor.selectAndReveal(3, 0); ContentAssistAction action = (ContentAssistAction) editor.getAction(ITextEditorActionConstants.CONTENT_ASSIST); action.update(); action.run(); waitAndDispatch(100); - Set<Shell> afterShell = new HashSet<>(Arrays.asList(Display.getDefault().getShells())); - afterShell.removeAll(beforeShell); - assertEquals("No completion", 1, afterShell.size()); - Shell completionShell= afterShell.iterator().next(); - final Table completionProposalList = findCompletionSelectionControl(completionShell); + this.completionShell= findNewShell(beforeShells); + final Table completionProposalList = findCompletionSelectionControl(this.completionShell); // should be instantaneous, but happens to go asynchronous on CI so let's allow a wait new DisplayHelper() { @Override @@ -116,22 +130,34 @@ public class CompletionTest extends AbstratGenericEditorTest { assertTrue("Missing computing info entry", computingItem.getText().contains("Computing")); //$NON-NLS-1$ //$NON-NLS-2$ // Some processors are long running, moving cursor can cause freeze (bug 521484) // asynchronous + long timestamp = System.currentTimeMillis(); + emulatePressLeftArrowKey(); + DisplayHelper.sleep(editor.getSite().getShell().getDisplay(), 200); //give time to process events + long processingDuration = System.currentTimeMillis() - timestamp; + assertTrue("UI Thread frozen for " + processingDuration + "ms", processingDuration < LongRunningBarContentAssistProcessor.DELAY); + } + + @Test + public void testMoveCaretBackUsesAllProcessors_bug522255() throws Exception { + final Set<Shell> beforeShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet()); + testCompletion(); + emulatePressLeftArrowKey(); + DisplayHelper.sleep(editor.getSite().getShell().getDisplay(), LongRunningBarContentAssistProcessor.DELAY + 500); // adding delay is a workaround for bug521484, use only 100ms without the bug + this.completionShell= findNewShell(beforeShells); + final Table completionProposalList = findCompletionSelectionControl(this.completionShell); + assertEquals("Missing proposals from a Processor", 2, completionProposalList.getItemCount()); // replace with line below when #5214894 is done + // checkCompletionContent(completionProposalList); // use this instead of assert above when #521484 is done + } + + private void emulatePressLeftArrowKey() { + editor.selectAndReveal(((ITextSelection)editor.getSelectionProvider().getSelection()).getOffset() - 1, 0); StyledText styledText = (StyledText) editor.getAdapter(Control.class); - styledText.setSelection(styledText.getSelectionRange().x - 1); Event e = new Event(); e.type = ST.VerifyKey; e.widget = styledText; e.keyCode = SWT.ARROW_LEFT; e.display = styledText.getDisplay(); - long timestamp = System.currentTimeMillis(); styledText.notifyListeners(ST.VerifyKey, e); - DisplayHelper.sleep(styledText.getDisplay(), 200); //give time to process events - long processingDuration = System.currentTimeMillis() - timestamp; - assertTrue("UI Thread frozen for " + processingDuration + "ms", processingDuration < LongRunningBarContentAssistProcessor.DELAY); - - if (!completionShell.isDisposed()) { - completionShell.close(); - } } private Table findCompletionSelectionControl(Widget control) { @@ -148,4 +174,10 @@ public class CompletionTest extends AbstratGenericEditorTest { return null; } + @After + public void closeShell() { + if (this.completionShell != null && !completionShell.isDisposed()) { + completionShell.close(); + } + } } diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/BarContentAssistProcessor.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/BarContentAssistProcessor.java index 745f42dc3bf..f53da979686 100644 --- a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/BarContentAssistProcessor.java +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/BarContentAssistProcessor.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.ui.genericeditor.tests.contributions; +import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.contentassist.CompletionProposal; import org.eclipse.jface.text.contentassist.ICompletionProposal; @@ -19,15 +20,30 @@ import org.eclipse.jface.text.contentassist.IContextInformationValidator; public class BarContentAssistProcessor implements IContentAssistProcessor { - public static final String PROPOSAL = "s are good for a beer."; + public static final String PROPOSAL = "bars are good for a beer."; + private final String completeString; + + public BarContentAssistProcessor() { + this(PROPOSAL); + } + + public BarContentAssistProcessor(String completeString) { + this.completeString = completeString; + } @Override public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { - String text = viewer.getDocument().get(); - if (text.length() >= 3 && offset >= 3 && text.substring(offset - 3, offset).equals("bar")) { - String message = PROPOSAL; - CompletionProposal proposal = new CompletionProposal(message, offset, 0, message.length()); - return new ICompletionProposal[] { proposal }; + for (int offsetInProposal = Math.min(this.completeString.length(), viewer.getDocument().getLength()); offsetInProposal > 0; offsetInProposal--) { + String maybeMatchingString = this.completeString.substring(0, offsetInProposal); + try { + int lastIndex = offset - offsetInProposal + this.completeString.length(); + if (offset >= offsetInProposal && viewer.getDocument().get(offset - offsetInProposal, maybeMatchingString.length()).equals(maybeMatchingString)) { + CompletionProposal proposal = new CompletionProposal(this.completeString.substring(offsetInProposal), offset, 0, lastIndex); + return new ICompletionProposal[] { proposal }; + } + } catch (BadLocationException e) { + e.printStackTrace(); + } } return new ICompletionProposal[0]; } diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/LongRunningBarContentAssistProcessor.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/LongRunningBarContentAssistProcessor.java index 6f504d78053..ce0dc48cf41 100644 --- a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/LongRunningBarContentAssistProcessor.java +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/LongRunningBarContentAssistProcessor.java @@ -11,17 +11,17 @@ package org.eclipse.ui.genericeditor.tests.contributions; import org.eclipse.jface.text.ITextViewer; -import org.eclipse.jface.text.contentassist.CompletionProposal; import org.eclipse.jface.text.contentassist.ICompletionProposal; -import org.eclipse.jface.text.contentassist.IContentAssistProcessor; -import org.eclipse.jface.text.contentassist.IContextInformation; -import org.eclipse.jface.text.contentassist.IContextInformationValidator; -public class LongRunningBarContentAssistProcessor implements IContentAssistProcessor { +public class LongRunningBarContentAssistProcessor extends BarContentAssistProcessor { - public static final String PROPOSAL = "s are also good for soft drink cocktails."; + public static final String PROPOSAL = "bars are also good for soft drink cocktails."; public static final int DELAY = 2000; + public LongRunningBarContentAssistProcessor() { + super(PROPOSAL); + } + @Override public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { try { @@ -30,38 +30,6 @@ public class LongRunningBarContentAssistProcessor implements IContentAssistProce // TODO Auto-generated catch block e.printStackTrace(); } - String text = viewer.getDocument().get(); - if (text.length() >= 3 && offset >= 3 && text.substring(offset - 3, offset).equals("bar")) { - String message = PROPOSAL; - CompletionProposal proposal = new CompletionProposal(message, offset, 0, message.length()); - return new ICompletionProposal[] { proposal }; - } - return new ICompletionProposal[0]; - } - - @Override - public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { - return null; + return super.computeCompletionProposals(viewer, offset); } - - @Override - public char[] getCompletionProposalAutoActivationCharacters() { - return null; - } - - @Override - public char[] getContextInformationAutoActivationCharacters() { - return null; - } - - @Override - public String getErrorMessage() { - return null; - } - - @Override - public IContextInformationValidator getContextInformationValidator() { - return null; - } - } |