scheduleAsyncCompletion must be run on EDT

GitOrigin-RevId: 59ad3f46285e9975c0fe7df003270f4139d03604
This commit is contained in:
Max Medvedev
2025-09-05 13:06:28 +00:00
committed by intellij-monorepo-bot
parent fb90899eeb
commit b1b8c766df
4 changed files with 20 additions and 1 deletions
@@ -9,6 +9,7 @@ import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.concurrency.annotations.RequiresEdt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
@@ -62,6 +63,7 @@ public abstract class AutoPopupController {
* @see #scheduleAutoPopup(Editor, Condition)
* @see #scheduleAutoPopup(Editor, CompletionType, Condition)
*/
@RequiresEdt
public final void scheduleAutoPopup(@NotNull Editor editor) {
scheduleAutoPopup(editor, CompletionType.BASIC, null);
}
@@ -79,6 +81,7 @@ public abstract class AutoPopupController {
* @see #scheduleAutoPopup(Editor)
* @see #scheduleAutoPopup(Editor, CompletionType, Condition)
*/
@RequiresEdt
public final void scheduleAutoPopup(@NotNull Editor editor,
@Nullable Condition<? super PsiFile> condition) {
scheduleAutoPopup(editor, CompletionType.BASIC, condition);
@@ -98,6 +101,7 @@ public abstract class AutoPopupController {
* @see #scheduleAutoPopup(Editor)
* @see #scheduleAutoPopup(Editor, Condition)
*/
@RequiresEdt
public abstract void scheduleAutoPopup(@NotNull Editor editor,
@NotNull CompletionType completionType,
@Nullable Condition<? super PsiFile> condition);
@@ -9,6 +9,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.util.UserDataHolderEx;
import com.intellij.util.concurrency.annotations.RequiresEdt;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -53,6 +54,7 @@ public interface CompletionProcessEx extends CompletionProcessBase, UserDataHold
void setParameters(@NotNull CompletionParameters parameters);
@RequiresEdt
void scheduleRestart();
void prefixUpdated();
@@ -122,6 +122,8 @@ public class AutoPopupControllerImpl extends AutoPopupController {
return;
}
ThreadingAssertions.assertEventDispatchThread();
boolean alwaysAutoPopup = Boolean.TRUE.equals(editor.getUserData(ALWAYS_AUTO_POPUP));
if (!CodeInsightSettings.getInstance().AUTO_POPUP_COMPLETION_LOOKUP && !alwaysAutoPopup) {
return;
@@ -34,6 +34,7 @@ import com.intellij.ui.HintListener
import com.intellij.ui.LightweightHint
import com.intellij.util.ThreeState
import com.intellij.util.concurrency.AppExecutorUtil
import com.intellij.util.concurrency.ThreadingAssertions
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
import com.intellij.util.concurrency.annotations.RequiresEdt
import com.intellij.util.concurrency.annotations.RequiresReadLock
@@ -77,7 +78,7 @@ sealed class CompletionPhase @ApiStatus.Internal constructor(
internal var replaced: Boolean = false
private val myTracker: ActionTracker = ActionTracker(editor, this)
private var myState: CommittingState = InProgress(1)
private var myState: CommittingState = InProgress(1) // access available on EDT only
fun ignoreCurrentDocumentChange() {
myTracker.ignoreCurrentDocumentChange()
@@ -94,6 +95,7 @@ sealed class CompletionPhase @ApiStatus.Internal constructor(
* Several typedHandlers can request auto-popup completion during processing of a single event.
* We need to trigger read-action for them independently because they can have different conditions for starting completion.
*/
@RequiresEdt
private fun addRequest() {
when (val cur = myState) {
Cancelled, Disposed, Success -> {
@@ -110,6 +112,7 @@ sealed class CompletionPhase @ApiStatus.Internal constructor(
/**
* the current request was not successful (most likely because of the failed condition), but other requests still have a chance to succeed.
*/
@RequiresEdt
private fun cancelThisRequest() {
when (val cur = myState) {
Disposed, Cancelled, Success -> {
@@ -136,6 +139,7 @@ sealed class CompletionPhase @ApiStatus.Internal constructor(
/**
* At least one of the requests succeeded, the completion process has been started, no more requests are necessary.
*/
@RequiresEdt
private fun requestCompleted() {
LOG.trace { "Request completed" }
LOG.assertTrue(myState is InProgress, "myState=$myState")
@@ -191,6 +195,7 @@ sealed class CompletionPhase @ApiStatus.Internal constructor(
* @param prevIndicator the completion indicator, if any. The indicator exists if completion was already started and we restart it with new parameters.
*/
@ApiStatus.Internal
@RequiresEdt
@JvmStatic
fun scheduleAsyncCompletion(
editor: Editor,
@@ -200,6 +205,9 @@ sealed class CompletionPhase @ApiStatus.Internal constructor(
prevIndicator: CompletionProgressIndicator?
) {
LOG.trace("Schedule async completion")
ThreadingAssertions.assertEventDispatchThread()
val topLevelEditor = InjectedLanguageEditorUtil.getTopLevelEditor(editor)
val offset = topLevelEditor.getCaretModel().offset
@@ -297,6 +305,7 @@ sealed class CompletionPhase @ApiStatus.Internal constructor(
handler.invokeCompletion(project, completionEditor, time, false)
}
@RequiresEdt
private fun getCompletionPhase(
prevIndicator: CompletionProgressIndicator?,
topLevelEditor: Editor,
@@ -321,6 +330,7 @@ sealed class CompletionPhase @ApiStatus.Internal constructor(
@RequiresBackgroundThread
@JvmStatic
fun loadContributorsOutsideEdt(editor: Editor, file: PsiFile) {
ThreadingAssertions.assertBackgroundThread()
CompletionContributor.forLanguage(PsiUtilCore.getLanguageAtOffset(file, editor.getCaretModel().offset))
}
@@ -351,6 +361,7 @@ sealed class CompletionPhase @ApiStatus.Internal constructor(
}
}
@RequiresEdt
private fun cancelPhase() {
when (myState) {
Cancelled, Disposed, Success -> {}