a single phase for original & copy commit, no restart phase => no finishing character swallowing => PROFIT!!!!

This commit is contained in:
peter
2011-08-12 18:57:11 +02:00
parent 9a8ec75115
commit 606b9a025e
9 changed files with 119 additions and 92 deletions
@@ -726,7 +726,7 @@ class Foo {
assert !lookup
}
public void _testChoosingItemDuringCopyCommit() {
public void testChoosingItemDuringCopyCommit() {
registerContributor(LongReplacementOffsetContributor)
myFixture.configureByText("a.java", """ class Foo { { int iteraaa; <caret> } } """)
@@ -22,9 +22,8 @@ import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.completion.impl.CompletionServiceImpl;
import com.intellij.codeInsight.editorActions.CompletionAutoPopupHandler;
import com.intellij.codeInsight.hint.ShowParameterInfoHandler;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
import com.intellij.ide.IdeEventQueue;
import com.intellij.ide.PowerSaveMode;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
@@ -90,24 +89,27 @@ public class AutoPopupController implements Disposable {
}
public void scheduleAutoPopup(final Editor editor, @Nullable final Condition<PsiFile> condition) {
if (ApplicationManager.getApplication().isUnitTestMode() &&
!CompletionAutoPopupHandler.ourTestingAutopopup) {
if (ApplicationManager.getApplication().isUnitTestMode() && !CompletionAutoPopupHandler.ourTestingAutopopup) {
return;
}
if (!CodeInsightSettings.getInstance().AUTO_POPUP_COMPLETION_LOOKUP) {
return;
}
LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor);
boolean shouldBeFast = lookup != null && lookup.isShown();
if (PowerSaveMode.isEnabled()) {
return;
}
if (!CompletionServiceImpl.isPhase(CompletionPhase.CommittingDocuments.class, CompletionPhase.NoCompletion.getClass())) {
return;
}
final CompletionProgressIndicator currentCompletion = CompletionServiceImpl.getCompletionService().getCurrentCompletion();
if (currentCompletion != null) {
currentCompletion.closeAndFinish(!shouldBeFast);
currentCompletion.closeAndFinish(true);
}
final CompletionPhase.CommittingDocuments phase = new CompletionPhase.CommittingDocuments(false, editor);
final CompletionPhase.CommittingDocuments phase = new CompletionPhase.CommittingDocuments(null, editor);
CompletionServiceImpl.setCompletionPhase(phase);
Runnable request = new Runnable() {
@@ -116,7 +118,7 @@ public class AutoPopupController implements Disposable {
CompletionAutoPopupHandler.runLaterWithCommitted(myProject, editor.getDocument(), new Runnable() {
@Override
public void run() {
if (phase.isExpired()) return;
if (phase.checkExpired()) return;
PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(editor.getDocument());
if (file != null && condition != null && !condition.value(file)) return;
@@ -126,11 +128,7 @@ public class AutoPopupController implements Disposable {
});
}
};
if (shouldBeFast) {
request.run();
} else {
addRequest(request, CodeInsightSettings.getInstance().AUTO_LOOKUP_DELAY);
}
addRequest(request, CodeInsightSettings.getInstance().AUTO_LOOKUP_DELAY);
}
@TestOnly
@@ -16,7 +16,6 @@
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.CodeInsightActionHandler;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.completion.impl.CompletionServiceImpl;
@@ -30,7 +29,6 @@ import com.intellij.lang.Language;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationAdapter;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
@@ -51,13 +49,15 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.CommitToPsiFileAction;
import com.intellij.psi.impl.PsiFileEx;
import com.intellij.psi.impl.PsiModificationTrackerImpl;
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
@@ -79,16 +79,22 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.CodeCompletionHandlerBase");
private final CompletionType myCompletionType;
final boolean invokedExplicitly;
final boolean synchronous;
final boolean autopopup;
public CodeCompletionHandlerBase(final CompletionType completionType) {
this(completionType, true, false);
this(completionType, true, false, true);
}
public CodeCompletionHandlerBase(CompletionType completionType, boolean invokedExplicitly, boolean autopopup) {
public CodeCompletionHandlerBase(CompletionType completionType, boolean invokedExplicitly, boolean autopopup, boolean synchronous) {
myCompletionType = completionType;
this.invokedExplicitly = invokedExplicitly;
this.autopopup = autopopup;
this.synchronous = synchronous;
if (invokedExplicitly) {
assert synchronous;
}
}
public final void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull PsiFile psiFile) {
@@ -132,8 +138,10 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler {
return;
}
time = phase.newCompletionStarted(time, repeated);
CompletionServiceImpl.assertPhase(CompletionPhase.NoCompletion.getClass());
if (invokedExplicitly) {
time = phase.newCompletionStarted(time, repeated);
}
CompletionServiceImpl.assertPhase(CompletionPhase.NoCompletion.getClass(), CompletionPhase.CommittingDocuments.class);
if (time > 1) {
if (myCompletionType == CompletionType.CLASS_NAME) {
@@ -256,6 +264,16 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler {
CompletionContext context = createCompletionContext(hostFile, hostStartOffset, hostEditor, hostMap);
CompletionParameters parameters = createCompletionParameters(invocationCount, initContext, context);
CompletionPhase phase = CompletionServiceImpl.getCompletionPhase();
if (phase instanceof CompletionPhase.CommittingDocuments) {
if (phase.indicator != null) {
phase.indicator.closeAndFinish(false);
}
((CompletionPhase.CommittingDocuments)phase).replaced = true;
} else {
CompletionServiceImpl.assertPhase(CompletionPhase.NoCompletion.getClass());
}
final Editor editor = initContext.getEditor();
final Semaphore freezeSemaphore = new Semaphore();
freezeSemaphore.down();
@@ -503,23 +521,18 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler {
final Project project = hostFile.getProject();
if (!invokedExplicitly) {
final CompletionPhase.CommittingDocuments phase = new CompletionPhase.CommittingDocuments(true, hostEditor);
CompletionServiceImpl.setCompletionPhase(phase);
ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() {
@Override
public void beforeWriteActionStart(Object action) {
if (!(action instanceof Class) || !CommitToPsiFileAction.class.isAssignableFrom((Class)action)) {
AutoPopupController.getInstance(project).scheduleAutoPopup(hostEditor, Condition.TRUE);
}
}
}, phase);
if (!synchronous) {
if (!CompletionServiceImpl.assertPhase(CompletionPhase.CommittingDocuments.class)) {
CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion);
return;
}
final CompletionPhase.CommittingDocuments phase = (CompletionPhase.CommittingDocuments)CompletionServiceImpl.getCompletionPhase();
CompletionAutoPopupHandler.runLaterWithCommitted(project, hostDocument, new Runnable() {
@Override
public void run() {
if (phase.isExpired()) return;
if (phase.checkExpired()) return;
doComplete(initContext, hasModifiers, invocationCount, hostFile, hostStartOffset, hostEditor, hostMap);
}
});
@@ -73,15 +73,14 @@ public abstract class CompletionPhase implements Disposable {
}
public static class CommittingDocuments extends CompletionPhase {
final boolean copyCommit;
boolean replaced;
private boolean actionsHappened;
private final Editor myEditor;
private final Expirable focusStamp;
private final Project myProject;
public CommittingDocuments(boolean copyCommit, Editor editor) {
super(null);
this.copyCommit = copyCommit;
public CommittingDocuments(@Nullable CompletionProgressIndicator prevIndicator, Editor editor) {
super(prevIndicator);
myEditor = editor;
myProject = editor.getProject();
focusStamp = IdeFocusManager.getInstance(myProject).getTimestamp(false);
@@ -93,21 +92,46 @@ public abstract class CompletionPhase implements Disposable {
}, this);
}
public boolean isExpired() {
if (ApplicationManager.getApplication().isWriteAccessAllowed()) return true; //it will fail anyway
if (actionsHappened) return true;
return CompletionServiceImpl.getCompletionPhase() != this || focusStamp.isExpired() || DumbService.getInstance(myProject).isDumb() || myEditor.isDisposed();
public boolean checkExpired() {
if (CompletionServiceImpl.getCompletionPhase() != this) {
return true;
}
if (actionsHappened || focusStamp.isExpired() || DumbService.getInstance(myProject).isDumb() ||
myEditor.isDisposed() ||
ApplicationManager.getApplication().isWriteAccessAllowed()) {
CompletionServiceImpl.setCompletionPhase(NoCompletion);
return true;
}
return false;
}
public boolean restartCompletion() {
if (indicator != null) {
replaced = true;
indicator.scheduleRestart();
assert this != CompletionServiceImpl.getCompletionPhase();
CompletionServiceImpl.assertPhase(CommittingDocuments.class);
}
return replaced;
}
@Override
public int newCompletionStarted(int time, boolean repeated) {
CompletionServiceImpl.setCompletionPhase(NoCompletion);
return time;
}
@Override
public void dispose() {
if (!replaced && indicator != null) {
indicator.closeAndFinish(true);
}
}
@Override
public String toString() {
return "CommittingDocuments{copyCommit=" + copyCommit + '}';
return "CommittingDocuments{hasIndicator=" + (indicator != null) + '}';
}
}
public static class Synchronous extends CompletionPhase {
@@ -164,17 +188,6 @@ public abstract class CompletionPhase implements Disposable {
return indicator.fillInCommonPrefix(true);
}
}
public static class Restarted extends CompletionPhase {
public Restarted(CompletionProgressIndicator indicator) {
super(indicator);
}
@Override
public int newCompletionStarted(int time, boolean repeated) {
indicator.closeAndFinish(false);
return indicator.nextInvocationCount(time, repeated);
}
}
public static abstract class ZombiePhase extends CompletionPhase {
@@ -429,7 +429,11 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
LOG.assertTrue(currentCompletion == this, currentCompletion + "!=" + this);
CompletionServiceImpl.getCompletionService().setCurrentCompletion(null);
CompletionServiceImpl.assertPhase(CompletionPhase.BgCalculation.class, CompletionPhase.ItemsCalculated.class, CompletionPhase.Synchronous.class, CompletionPhase.Restarted.class);
CompletionServiceImpl.assertPhase(CompletionPhase.BgCalculation.class, CompletionPhase.ItemsCalculated.class, CompletionPhase.Synchronous.class, CompletionPhase.CommittingDocuments.class);
if (CompletionServiceImpl.getCompletionPhase() instanceof CompletionPhase.CommittingDocuments) {
LOG.assertTrue(CompletionServiceImpl.getCompletionPhase().indicator != null, CompletionServiceImpl.getCompletionPhase());
((CompletionPhase.CommittingDocuments)CompletionServiceImpl.getCompletionPhase()).replaced = true;
}
CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion);
if (disposeOffsetMap) {
disposeOffsetMaps();
@@ -628,23 +632,25 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
final CompletionProgressIndicator current = CompletionServiceImpl.getCompletionService().getCurrentCompletion();
LOG.assertTrue(this == current, current + "!=" + this);
final CompletionPhase phase = new CompletionPhase.Restarted(this);
final CompletionPhase.CommittingDocuments phase = new CompletionPhase.CommittingDocuments(this, myEditor);
CompletionServiceImpl.setCompletionPhase(phase);
final Project project = getProject();
CompletionAutoPopupHandler.runLaterWithCommitted(project, myEditor.getDocument(), new Runnable() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (phase != CompletionServiceImpl.getCompletionPhase()) {
return;
}
closeAndFinish(false);
CompletionAutoPopupHandler.invokeCompletion(myParameters.getCompletionType(),
isAutopopupCompletion(), project, myEditor, myParameters.getInvocationCount());
CompletionAutoPopupHandler.runLaterWithCommitted(project, myEditor.getDocument(), new Runnable() {
@Override
public void run() {
if (phase.checkExpired()) return;
CompletionAutoPopupHandler.invokeCompletion(myParameters.getCompletionType(),
isAutopopupCompletion(), project, myEditor, myParameters.getInvocationCount());
}
});
}
});
}, project.getDisposed());
}
@Override
@@ -197,10 +197,12 @@ public class CompletionServiceImpl extends CompletionService{
}
}
public static void assertPhase(Class<? extends CompletionPhase>... possibilities) {
public static boolean assertPhase(Class<? extends CompletionPhase>... possibilities) {
if (!isPhase(possibilities)) {
LOG.error(ourPhase + "; set at " + ourPhaseTrace);
return false;
}
return true;
}
public static boolean isPhase(Class<? extends CompletionPhase>... possibilities) {
@@ -16,13 +16,11 @@
package com.intellij.codeInsight.editorActions;
import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
import com.intellij.codeInsight.completion.CompletionPhase;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.completion.impl.CompletionServiceImpl;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.ide.PowerSaveMode;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
@@ -60,31 +58,28 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate {
@Override
public Result checkAutoPopup(char charTyped, final Project project, final Editor editor, final PsiFile file) {
if (!CodeInsightSettings.getInstance().AUTO_POPUP_COMPLETION_LOOKUP) return Result.CONTINUE;
if (PowerSaveMode.isEnabled()) return Result.CONTINUE;
if (LookupManager.getActiveLookup(editor) != null) {
return Result.CONTINUE;
}
CompletionPhase oldPhase = CompletionServiceImpl.getCompletionPhase();
if (oldPhase instanceof CompletionPhase.EmptyAutoPopup && ((CompletionPhase.EmptyAutoPopup)oldPhase).editor != editor) {
CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion);
}
if (!Character.isLetter(charTyped) && charTyped != '_') {
if (CompletionServiceImpl.isPhase(CompletionPhase.EmptyAutoPopup.class, CompletionPhase.CommittingDocuments.class)) {
CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion);
}
return Result.CONTINUE;
if (oldPhase instanceof CompletionPhase.CommittingDocuments && ((CompletionPhase.CommittingDocuments)oldPhase).restartCompletion()) {
return Result.STOP;
}
if (!CompletionServiceImpl.isPhase(CompletionPhase.CommittingDocuments.class, CompletionPhase.NoCompletion.getClass())) {
return Result.CONTINUE;
if (LookupManager.getInstance(project).getActiveLookup() != null) {
return Result.STOP;
}
AutoPopupController.getInstance(project).scheduleAutoPopup(editor, null);
return Result.STOP;
if (Character.isLetter(charTyped) || charTyped == '_') {
AutoPopupController.getInstance(project).scheduleAutoPopup(editor, null);
return Result.STOP;
}
if (CompletionServiceImpl.isPhase(CompletionPhase.EmptyAutoPopup.class, CompletionPhase.CommittingDocuments.class)) {
CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion);
}
return Result.CONTINUE;
}
public static void invokeCompletion(CompletionType completionType,
@@ -104,7 +99,7 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate {
}
Editor newEditor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(topLevelEditor, topLevelFile);
try {
new CodeCompletionHandlerBase(completionType, false, autopopup).invokeCompletion(project, newEditor, time, false);
new CodeCompletionHandlerBase(completionType, false, autopopup, false).invokeCompletion(project, newEditor, time, false);
}
catch (IndexNotReadyException ignored) {
}
@@ -25,6 +25,6 @@ public class ClassNameCompleteMacro extends BaseCompleteMacro {
}
CodeInsightActionHandler getCompletionHandler() {
return new CodeCompletionHandlerBase(CompletionType.CLASS_NAME, false, false);
return new CodeCompletionHandlerBase(CompletionType.CLASS_NAME, false, false, true);
}
}
@@ -26,6 +26,6 @@ public class CompleteMacro extends BaseCompleteMacro {
}
CodeInsightActionHandler getCompletionHandler() {
return new CodeCompletionHandlerBase(CompletionType.BASIC, ApplicationManager.getApplication().isUnitTestMode(), false);
return new CodeCompletionHandlerBase(CompletionType.BASIC, ApplicationManager.getApplication().isUnitTestMode(), false, true);
}
}