mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
a single phase for original & copy commit, no restart phase => no finishing character swallowing => PROFIT!!!!
This commit is contained in:
+1
-1
@@ -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
|
||||
|
||||
+34
-21
@@ -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 {
|
||||
|
||||
|
||||
+18
-12
@@ -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
|
||||
|
||||
+3
-1
@@ -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) {
|
||||
|
||||
+14
-19
@@ -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) {
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user