[rd-editor] IJPL-201535 Refactor CommandProcessor

GitOrigin-RevId: a2f3a0b91d7377387c382803666517b550ce7029
This commit is contained in:
Alexander Trushev
2025-09-23 20:26:21 +00:00
committed by intellij-monorepo-bot
parent a4cf6abb29
commit dd7a88e031
26 changed files with 522 additions and 277 deletions
@@ -175,7 +175,6 @@ class NotebookIntervalPointerFactoryImpl(
eventChanges: NotebookIntervalPointersEventChanges,
shiftChanges: NotebookIntervalPointersEventChanges,
) {
CommandProcessor.getInstance().currentCommand
registerUndoableAction(object : BasicUndoableAction(document) {
override fun undo() {}
@@ -89,7 +89,7 @@ public interface ModCommandExecutor {
title, true, context.project());
if (!command.isEmpty()) {
CommandProcessor commandProcessor = CommandProcessor.getInstance();
if (commandProcessor.getCurrentCommand() == null) {
if (!commandProcessor.isCommandInProgress()) {
commandProcessor.executeCommand(context.project(),
() -> getInstance().executeInteractively(context, command, editor), title, null);
} else {
@@ -106,7 +106,7 @@ public final class TemplateState extends TemplateStateBase implements Disposable
myEditorDocumentListener = new DocumentListener() {
@Override
public void beforeDocumentChange(@NotNull DocumentEvent e) {
if (CommandProcessor.getInstance().getCurrentCommand() != null && !isUndoOrRedoInProgress()) {
if (CommandProcessor.getInstance().isCommandInProgress() && !isUndoOrRedoInProgress()) {
myDocumentChanged = true;
}
}
@@ -245,6 +245,7 @@ a:com.intellij.openapi.application.ReadAction
a:com.intellij.openapi.command.CommandProcessor
- *a:allowMergeGlobalCommands(java.lang.Runnable):V
- *a:executeCommand(com.intellij.openapi.project.Project,java.lang.Runnable,java.lang.String,java.lang.Object,com.intellij.openapi.command.UndoConfirmationPolicy,Z,com.intellij.openapi.editor.Document):V
- *:isCommandInProgress():Z
f:com.intellij.openapi.command.CoroutinesKt
- *sf:execute(com.intellij.openapi.command.WriteCommandAction$Builder,kotlin.jvm.functions.Function0,kotlin.coroutines.Continuation):java.lang.Object
- *sf:writeCommandAction(com.intellij.openapi.application.ReadAndWriteScope,com.intellij.openapi.project.Project,java.lang.String,kotlin.jvm.functions.Function0):com.intellij.openapi.application.ReadResult
@@ -105,6 +105,11 @@ public abstract class CommandProcessor {
@ApiStatus.Experimental
public abstract void allowMergeGlobalCommands(@NotNull Runnable action);
@ApiStatus.Experimental
public boolean isCommandInProgress() {
return getCurrentCommand() != null;
}
/**
* @deprecated use {@link CommandListener#TOPIC}
*/
@@ -1003,7 +1003,6 @@ com.intellij.openapi.command.CommandToken
- a:getProject():com.intellij.openapi.project.Project
c:com.intellij.openapi.command.impl.CoreCommandProcessor
- com.intellij.openapi.command.CommandProcessorEx
- p:myCurrentCommand:com.intellij.openapi.command.impl.CoreCommandProcessor$CommandDescriptor
- <init>():V
- addAffectedDocuments(com.intellij.openapi.project.Project,com.intellij.openapi.editor.Document[]):V
- addAffectedFiles(com.intellij.openapi.project.Project,com.intellij.openapi.vfs.VirtualFile[]):V
@@ -1,7 +1,6 @@
com/intellij/diagnostic/ActivityCategory
com/intellij/lang/impl/PsiBuilderImpl$MyTreeStructure
com/intellij/lang/impl/PsiBuilderImpl$StartMarker
com/intellij/openapi/command/impl/CoreCommandProcessor$CommandDescriptor
com/intellij/openapi/extensions/impl/ExtensionsAreaImpl
com/intellij/psi/impl/DiffLog
com/intellij/psi/stubs/StubBuilderType
@@ -0,0 +1,140 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.command.impl;
import com.intellij.openapi.command.CommandEvent;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.CommandToken;
import com.intellij.openapi.command.UndoConfirmationPolicy;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NlsContexts.Command;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
final class CommandDescriptor implements CommandToken {
private final @NotNull CommandIdentity identity;
private final @NotNull Runnable command;
private final @Nullable Project project;
private final @Nullable @Command String name;
private final @Nullable Object groupId;
private final @Nullable Document document;
private final @NotNull UndoConfirmationPolicy undoConfirmationPolicy;
private final boolean shouldRecordActionForActiveDocument;
CommandDescriptor(
@NotNull Runnable command,
@Nullable Project project,
@Nullable @Command String name,
@Nullable Object groupId,
@NotNull UndoConfirmationPolicy undoConfirmationPolicy,
boolean shouldRecordActionForActiveDocument,
@Nullable Document document
) {
this(
new CommandIdentity(),
command,
project,
name,
groupId,
undoConfirmationPolicy,
shouldRecordActionForActiveDocument,
document
);
}
private CommandDescriptor(
@NotNull CommandIdentity identity,
@NotNull Runnable command,
@Nullable Project project,
@Nullable @Command String name,
@Nullable Object groupId,
@NotNull UndoConfirmationPolicy undoConfirmationPolicy,
boolean shouldRecordActionForActiveDocument,
@Nullable Document document
) {
this.identity = identity;
this.command = command;
this.project = project;
this.name = name;
this.groupId = groupId;
this.undoConfirmationPolicy = undoConfirmationPolicy;
this.shouldRecordActionForActiveDocument = shouldRecordActionForActiveDocument;
this.document = document;
}
@NotNull CommandEvent toCommandEvent(@NotNull CommandProcessor processor) {
return new CommandEvent(
processor,
command,
name,
groupId,
project,
undoConfirmationPolicy,
shouldRecordActionForActiveDocument,
document
);
}
@NotNull CommandDescriptor withName(@Nullable @Command String name) {
return new CommandDescriptor(
identity,
command,
project,
name,
groupId,
undoConfirmationPolicy,
shouldRecordActionForActiveDocument,
document
);
}
@NotNull CommandDescriptor withGroupId(@Nullable Object groupId) {
return new CommandDescriptor(
identity,
command,
project,
name,
groupId,
undoConfirmationPolicy,
shouldRecordActionForActiveDocument,
document
);
}
@Override
public @Nullable Project getProject() {
return project;
}
@NotNull Runnable getCommand() {
return command;
}
@Nullable @Command String getName() {
return name;
}
@Nullable Object getGroupId() {
return groupId;
}
@Override
public boolean equals(Object object) {
if (!(object instanceof CommandDescriptor)) return false;
CommandDescriptor that = (CommandDescriptor)object;
return Objects.equals(identity, that.identity);
}
@Override
public int hashCode() {
return Objects.hashCode(identity);
}
@Override
public String toString() {
return "'" + name + "', group: '" + groupId + "'";
}
}
@@ -0,0 +1,30 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.command.impl;
import java.util.concurrent.atomic.AtomicInteger;
final class CommandIdentity {
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(0);
private final int id = ID_GENERATOR.incrementAndGet();
@Override
public boolean equals(Object object) {
if (!(object instanceof CommandIdentity)) return false;
CommandIdentity identity = (CommandIdentity) object;
return id == identity.id;
}
@Override
public int hashCode() {
return id;
}
@Override
public String toString() {
return "CommandIdentity{" +
"id=" + id +
'}';
}
}
@@ -0,0 +1,90 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.command.impl;
import com.intellij.openapi.command.CommandEvent;
import com.intellij.openapi.command.CommandListener;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.List;
final class CommandListeners implements CommandListener {
private final List<CommandListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
void addCommandListener(@NotNull CommandListener listener) {
myListeners.add(listener);
}
@Override
public void commandStarted(@NotNull CommandEvent event) {
for (CommandListener listener : myListeners) {
try {
listener.commandStarted(event);
}
catch (Throwable e) {
CoreCommandProcessor.LOG.error(e);
}
}
}
@Override
public void beforeCommandFinished(@NotNull CommandEvent event) {
for (CommandListener listener : myListeners) {
try {
listener.beforeCommandFinished(event);
}
catch (Throwable e) {
CoreCommandProcessor.LOG.error(e);
}
}
}
@Override
public void commandFinished(@NotNull CommandEvent event) {
for (CommandListener listener : myListeners) {
try {
listener.commandFinished(event);
}
catch (Throwable e) {
CoreCommandProcessor.LOG.error(e);
}
}
}
@Override
public void undoTransparentActionStarted() {
for (CommandListener listener : myListeners) {
try {
listener.undoTransparentActionStarted();
}
catch (Throwable e) {
CoreCommandProcessor.LOG.error(e);
}
}
}
@Override
public void beforeUndoTransparentActionFinished() {
for (CommandListener listener : myListeners) {
try {
listener.beforeUndoTransparentActionFinished();
}
catch (Throwable e) {
CoreCommandProcessor.LOG.error(e);
}
}
}
@Override
public void undoTransparentActionFinished() {
for (CommandListener listener : myListeners) {
try {
listener.undoTransparentActionFinished();
}
catch (Throwable e) {
CoreCommandProcessor.LOG.error(e);
}
}
}
}
@@ -0,0 +1,57 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.command.impl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandEvent;
import com.intellij.openapi.command.CommandListener;
import com.intellij.util.messages.MessageBus;
import org.jetbrains.annotations.NotNull;
final class CommandPublisher implements CommandListener {
private final CommandListeners listeners;
private final CommandListener publisher;
CommandPublisher() {
CommandListeners listeners = new CommandListeners();
MessageBus messageBus = ApplicationManager.getApplication().getMessageBus();
messageBus.simpleConnect().subscribe(TOPIC, listeners);
this.listeners = listeners;
this.publisher = messageBus.syncPublisher(TOPIC);
}
void addCommandListener(@NotNull CommandListener listener) {
listeners.addCommandListener(listener);
}
@Override
public void commandStarted(@NotNull CommandEvent event) {
publisher.commandStarted(event);
}
@Override
public void beforeCommandFinished(@NotNull CommandEvent event) {
publisher.beforeCommandFinished(event);
}
@Override
public void commandFinished(@NotNull CommandEvent event) {
publisher.commandFinished(event);
}
@Override
public void undoTransparentActionStarted() {
publisher.undoTransparentActionStarted();
}
@Override
public void beforeUndoTransparentActionFinished() {
publisher.beforeUndoTransparentActionFinished();
}
@Override
public void undoTransparentActionFinished() {
publisher.undoTransparentActionFinished();
}
}
@@ -15,220 +15,131 @@ import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.concurrency.ThreadingAssertions;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Stack;
import com.intellij.util.messages.MessageBus;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class CoreCommandProcessor extends CommandProcessorEx {
@ApiStatus.Internal
protected static final Logger LOG = Logger.getInstance("#com.intellij.openapi.command.impl");
@ApiStatus.Internal
public static final class CommandDescriptor implements CommandToken {
public final @NotNull Runnable myCommand;
public final Project myProject;
public @NlsContexts.Command String myName;
public Object myGroupId;
public final Document myDocument;
final @NotNull UndoConfirmationPolicy myUndoConfirmationPolicy;
final boolean myShouldRecordActionForActiveDocument;
CommandDescriptor(@NotNull Runnable command,
Project project,
@NlsContexts.Command String name,
Object groupId,
@NotNull UndoConfirmationPolicy undoConfirmationPolicy,
boolean shouldRecordActionForActiveDocument,
Document document) {
myCommand = command;
myProject = project;
myName = name;
myGroupId = groupId;
myUndoConfirmationPolicy = undoConfirmationPolicy;
myShouldRecordActionForActiveDocument = shouldRecordActionForActiveDocument;
myDocument = document;
}
@Override
public Project getProject() {
return myProject;
}
@Override
public String toString() {
return "'" + myName + "', group: '" + myGroupId + "'";
}
}
protected CommandDescriptor myCurrentCommand;
// Stack is used instead of ConcurrentLinkedDeque because null values are not supported by ConcurrentLinkedDeque
private final Stack<CommandDescriptor> myInterruptedCommands = new Stack<>();
private final List<CommandListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private int myUndoTransparentCount;
private int myAllowMergeGlobalCommandsCount = 0;
private final CommandListener eventPublisher;
public CoreCommandProcessor() {
MessageBus messageBus = ApplicationManager.getApplication().getMessageBus();
messageBus.simpleConnect().subscribe(CommandListener.TOPIC, new CommandListener() {
@Override
public void commandStarted(@NotNull CommandEvent event) {
for (CommandListener listener : myListeners) {
try {
listener.commandStarted(event);
}
catch (Throwable e) {
LOG.error(e);
}
}
}
@Override
public void beforeCommandFinished(@NotNull CommandEvent event) {
for (CommandListener listener : myListeners) {
try {
listener.beforeCommandFinished(event);
}
catch (Throwable e) {
LOG.error(e);
}
}
}
@Override
public void commandFinished(@NotNull CommandEvent event) {
for (CommandListener listener : myListeners) {
try {
listener.commandFinished(event);
}
catch (Throwable e) {
LOG.error(e);
}
}
}
@Override
public void undoTransparentActionStarted() {
for (CommandListener listener : myListeners) {
try {
listener.undoTransparentActionStarted();
}
catch (Throwable e) {
LOG.error(e);
}
}
}
@Override
public void beforeUndoTransparentActionFinished() {
for (CommandListener listener : myListeners) {
try {
listener.beforeUndoTransparentActionFinished();
}
catch (Throwable e) {
LOG.error(e);
}
}
}
@Override
public void undoTransparentActionFinished() {
for (CommandListener listener : myListeners) {
try {
listener.undoTransparentActionFinished();
}
catch (Throwable e) {
LOG.error(e);
}
}
}
});
// will, command events occurred quite often, let's cache publisher
eventPublisher = messageBus.syncPublisher(CommandListener.TOPIC);
}
private final CommandPublisher eventPublisher = new CommandPublisher();
private final Stack<@Nullable CommandDescriptor> interruptedCommands = new Stack<>();
private @Nullable CommandDescriptor currentCommand;
private int undoTransparentCount;
private int allowMergeGlobalCommandsCount = 0;
@Override
public void executeCommand(Project project, @NotNull Runnable runnable, String name, Object groupId) {
public void executeCommand(
@Nullable Project project,
@NotNull Runnable runnable,
@Nullable String name,
@Nullable Object groupId
) {
executeCommand(project, runnable, name, groupId, UndoConfirmationPolicy.DEFAULT);
}
@Override
public void executeCommand(Project project, @NotNull Runnable runnable, String name, Object groupId, Document document) {
public void executeCommand(
@Nullable Project project,
@NotNull Runnable runnable,
@Nullable String name,
@Nullable Object groupId,
@Nullable Document document
) {
executeCommand(project, runnable, name, groupId, UndoConfirmationPolicy.DEFAULT, document);
}
@Override
public void executeCommand(Project project,
final @NotNull Runnable command,
final String name,
final Object groupId,
@NotNull UndoConfirmationPolicy undoConfirmationPolicy) {
public void executeCommand(
@Nullable Project project,
@NotNull Runnable command,
@Nullable String name,
@Nullable Object groupId,
@NotNull UndoConfirmationPolicy undoConfirmationPolicy
) {
executeCommand(project, command, name, groupId, undoConfirmationPolicy, null);
}
@Override
public void executeCommand(Project project,
final @NotNull Runnable command,
final String name,
final Object groupId,
@NotNull UndoConfirmationPolicy undoConfirmationPolicy,
Document document) {
public void executeCommand(
@Nullable Project project,
@NotNull Runnable command,
@Nullable String name,
@Nullable Object groupId,
@NotNull UndoConfirmationPolicy undoConfirmationPolicy,
@Nullable Document document
) {
executeCommand(project, command, name, groupId, undoConfirmationPolicy, true, document);
}
@Override
public void executeCommand(@Nullable Project project,
@NotNull Runnable command,
@Nullable String name,
@Nullable Object groupId,
@NotNull UndoConfirmationPolicy undoConfirmationPolicy,
boolean shouldRecordCommandForActiveDocument) {
public void executeCommand(
@Nullable Project project,
@NotNull Runnable command,
@Nullable String name,
@Nullable Object groupId,
@NotNull UndoConfirmationPolicy undoConfirmationPolicy,
boolean shouldRecordCommandForActiveDocument
) {
executeCommand(project, command, name, groupId, undoConfirmationPolicy, shouldRecordCommandForActiveDocument, null);
}
@Override
public void executeCommand(@Nullable Project project,
@NotNull Runnable command,
@Nullable @NlsContexts.Command String name,
@Nullable Object groupId,
@NotNull UndoConfirmationPolicy undoConfirmationPolicy,
boolean shouldRecordCommandForActiveDocument,
@Nullable Document document) {
public void executeCommand(
@Nullable Project project,
@NotNull Runnable command,
@Nullable @NlsContexts.Command String name,
@Nullable Object groupId,
@NotNull UndoConfirmationPolicy undoConfirmationPolicy,
boolean shouldRecordCommandForActiveDocument,
@Nullable Document document
) {
Application application = ApplicationManager.getApplication();
application.assertIsDispatchThread();
if (LOG.isDebugEnabled()) {
String currentCommandName;
if (myCurrentCommand != null) currentCommandName = myCurrentCommand.myName;
else currentCommandName = "<null>";
LOG.debug("executeCommand: " + command + ", name = " + name + ", groupId = " + groupId +
", in command = " + currentCommandName +
", in transparent action = " + isUndoTransparentActionInProgress());
CommandDescriptor currentCommand = this.currentCommand;
LOG.debug(String.format(
"executeCommand: %s, name = %s, groupId = %s, in command = %s, in transparent action = %s",
command,
name,
groupId,
currentCommand == null ? "<null>" : currentCommand.getName(),
isUndoTransparentActionInProgress()
));
}
if (project != null && project.isDisposed()) {
LOG.error("Project "+project+" already disposed");
LOG.error("Project " + project + " already disposed");
return;
}
if (myCurrentCommand != null) {
application.runWriteIntentReadAction(() -> { command.run(); return null; });
if (currentCommand != null) {
application.runWriteIntentReadAction(() -> {
command.run();
return null;
});
return;
}
CommandDescriptor descriptor = new CommandDescriptor(command, project, name, groupId, undoConfirmationPolicy,
shouldRecordCommandForActiveDocument, document);
myCurrentCommand = descriptor;
CommandDescriptor descriptor = new CommandDescriptor(
command,
project,
name,
groupId,
undoConfirmationPolicy,
shouldRecordCommandForActiveDocument,
document
);
currentCommand = descriptor;
application.runWriteIntentReadAction(() -> {
Throwable throwable = null;
try {
fireCommandStarted();
fireCommandStarted(descriptor);
command.run();
}
catch (Throwable th) {
@@ -248,152 +159,144 @@ public class CoreCommandProcessor extends CommandProcessorEx {
}
@Override
public @Nullable CommandToken startCommand(final @Nullable Project project,
final String name,
final @Nullable Object groupId,
final @NotNull UndoConfirmationPolicy undoConfirmationPolicy) {
public @Nullable CommandToken startCommand(
@Nullable Project project,
@Nullable String name,
@Nullable Object groupId,
@NotNull UndoConfirmationPolicy undoConfirmationPolicy
) {
ApplicationManager.getApplication().assertWriteIntentLockAcquired();
if (project != null && project.isDisposed()) return null;
if (project != null && project.isDisposed()) {
return null;
}
if (LOG.isDebugEnabled()) {
LOG.debug("startCommand: name = " + name + ", groupId = " + groupId);
}
if (myCurrentCommand != null) {
if (currentCommand != null) {
return null;
}
Document document = groupId instanceof Document
? (Document)groupId
: groupId instanceof Ref && ((Ref<?>)groupId).get() instanceof Document
? (Document)((Ref<?>)groupId).get()
: null;
myCurrentCommand = new CommandDescriptor(EmptyRunnable.INSTANCE, project, name, groupId, undoConfirmationPolicy, true, document);
fireCommandStarted();
return myCurrentCommand;
CommandDescriptor descriptor = new CommandDescriptor(
EmptyRunnable.INSTANCE,
project,
name,
groupId,
undoConfirmationPolicy,
true,
getDocumentFromGroupId(groupId)
);
currentCommand = descriptor;
fireCommandStarted(descriptor);
return descriptor;
}
@Override
public void finishCommand(@NotNull CommandToken command, @Nullable Throwable throwable) {
ApplicationManager.getApplication().assertWriteIntentLockAcquired();
LOG.assertTrue(myCurrentCommand != null, "no current command in progress");
fireCommandFinished();
}
private void fireCommandFinished() {
CommandDescriptor currentCommand = myCurrentCommand;
CommandEvent event = new CommandEvent(this, currentCommand.myCommand,
currentCommand.myName,
currentCommand.myGroupId,
currentCommand.myProject,
currentCommand.myUndoConfirmationPolicy,
currentCommand.myShouldRecordActionForActiveDocument,
currentCommand.myDocument);
CommandListener publisher = eventPublisher;
try {
publisher.beforeCommandFinished(event);
}
finally {
myCurrentCommand = null;
publisher.commandFinished(event);
}
LOG.debug("finishCommand: name = " + event.getCommandName() + ", groupId = " + event.getCommandGroupId());
CommandDescriptor currentCommand = this.currentCommand;
LOG.assertTrue(currentCommand != null, "no current command in progress");
fireCommandFinished(currentCommand);
}
@Override
public void enterModal() {
ThreadingAssertions.assertEventDispatchThread();
CommandDescriptor currentCommand = myCurrentCommand;
myInterruptedCommands.push(currentCommand);
CommandDescriptor currentCommand = this.currentCommand;
interruptedCommands.push(currentCommand);
if (currentCommand != null) {
fireCommandFinished();
fireCommandFinished(currentCommand);
}
}
@Override
public void leaveModal() {
ThreadingAssertions.assertEventDispatchThread();
LOG.assertTrue(myCurrentCommand == null, "Command must not run: " + myCurrentCommand);
myCurrentCommand = myInterruptedCommands.pop();
if (myCurrentCommand != null) {
fireCommandStarted();
LOG.assertTrue(currentCommand == null, "Command must not run: " + currentCommand);
CommandDescriptor descriptor = interruptedCommands.pop();
currentCommand = descriptor;
if (descriptor != null) {
fireCommandStarted(descriptor);
}
}
@Override
public void setCurrentCommandName(String name) {
ThreadingAssertions.assertWriteIntentReadAccess();
CommandDescriptor currentCommand = myCurrentCommand;
CommandDescriptor currentCommand = this.currentCommand;
LOG.assertTrue(currentCommand != null);
currentCommand.myName = name;
this.currentCommand = currentCommand.withName(name);
}
@Override
public void setCurrentCommandGroupId(Object groupId) {
ThreadingAssertions.assertWriteIntentReadAccess();
CommandDescriptor currentCommand = myCurrentCommand;
CommandDescriptor currentCommand = this.currentCommand;
LOG.assertTrue(currentCommand != null);
currentCommand.myGroupId = groupId;
this.currentCommand = currentCommand.withGroupId(groupId);
}
@Override
public @Nullable Runnable getCurrentCommand() {
CommandDescriptor currentCommand = myCurrentCommand;
return currentCommand != null ? currentCommand.myCommand : null;
CommandDescriptor currentCommand = this.currentCommand;
return currentCommand != null ? currentCommand.getCommand() : null;
}
@Override
public @Nullable String getCurrentCommandName() {
CommandDescriptor currentCommand = myCurrentCommand;
if (currentCommand != null) return currentCommand.myName;
if (!myInterruptedCommands.isEmpty()) {
final CommandDescriptor command = myInterruptedCommands.peek();
return command != null ? command.myName : null;
CommandDescriptor currentCommand = this.currentCommand;
if (currentCommand != null) {
return currentCommand.getName();
}
if (!interruptedCommands.isEmpty()) {
CommandDescriptor command = interruptedCommands.peek();
return command != null ? command.getName() : null;
}
return null;
}
@Override
public @Nullable Object getCurrentCommandGroupId() {
CommandDescriptor currentCommand = myCurrentCommand;
if (currentCommand != null) return currentCommand.myGroupId;
if (!myInterruptedCommands.isEmpty()) {
final CommandDescriptor command = myInterruptedCommands.peek();
return command != null ? command.myGroupId : null;
CommandDescriptor currentCommand = this.currentCommand;
if (currentCommand != null) {
return currentCommand.getGroupId();
}
if (!interruptedCommands.isEmpty()) {
final CommandDescriptor command = interruptedCommands.peek();
return command != null ? command.getGroupId() : null;
}
return null;
}
@Override
public @Nullable Project getCurrentCommandProject() {
CommandDescriptor currentCommand = myCurrentCommand;
return currentCommand != null ? currentCommand.myProject : null;
CommandDescriptor currentCommand = this.currentCommand;
return currentCommand != null ? currentCommand.getProject() : null;
}
@Override
public void addCommandListener(@NotNull CommandListener listener) {
myListeners.add(listener);
eventPublisher.addCommandListener(listener);
}
@Override
public void runUndoTransparentAction(@NotNull Runnable action) {
if (LOG.isDebugEnabled()) {
LOG.debug("runUndoTransparentAction: " + action + ", in command = " + (myCurrentCommand != null) +
", in transparent action = " + isUndoTransparentActionInProgress());
LOG.debug("runUndoTransparentAction: " + action + ", in command = " + (currentCommand != null) +
", in transparent action = " + isUndoTransparentActionInProgress());
}
if (myUndoTransparentCount++ == 0) {
if (undoTransparentCount++ == 0) {
eventPublisher.undoTransparentActionStarted();
}
try {
action.run();
}
finally {
if (myUndoTransparentCount == 1) {
if (undoTransparentCount == 1) {
eventPublisher.beforeUndoTransparentActionFinished();
}
if (--myUndoTransparentCount == 0) {
if (--undoTransparentCount == 0) {
eventPublisher.undoTransparentActionFinished();
}
}
@@ -402,17 +305,17 @@ public class CoreCommandProcessor extends CommandProcessorEx {
@Override
public final AutoCloseable withUndoTransparentAction() {
if (LOG.isDebugEnabled()) {
LOG.debug("withUndoTransparentAction in command = " + (myCurrentCommand != null) +
LOG.debug("withUndoTransparentAction in command = " + (currentCommand != null) +
", in transparent action = " + isUndoTransparentActionInProgress());
}
if (myUndoTransparentCount++ == 0) {
if (undoTransparentCount++ == 0) {
eventPublisher.undoTransparentActionStarted();
}
return () -> {
if (myUndoTransparentCount == 1) {
if (undoTransparentCount == 1) {
eventPublisher.beforeUndoTransparentActionFinished();
}
if (--myUndoTransparentCount == 0) {
if (--undoTransparentCount == 0) {
eventPublisher.undoTransparentActionFinished();
}
};
@@ -420,7 +323,7 @@ public class CoreCommandProcessor extends CommandProcessorEx {
@Override
public boolean isUndoTransparentActionInProgress() {
return myUndoTransparentCount > 0;
return undoTransparentCount > 0;
}
@Override
@@ -437,8 +340,8 @@ public class CoreCommandProcessor extends CommandProcessorEx {
@ApiStatus.Internal
@ApiStatus.Experimental
public Boolean isMergeGlobalCommandsAllowed() {
return myAllowMergeGlobalCommandsCount > 0;
public boolean isMergeGlobalCommandsAllowed() {
return allowMergeGlobalCommandsCount > 0;
}
@Override
@@ -446,13 +349,13 @@ public class CoreCommandProcessor extends CommandProcessorEx {
@ApiStatus.Experimental
public AccessToken allowMergeGlobalCommands() {
ThreadingAssertions.assertWriteIntentReadAccess();
myAllowMergeGlobalCommandsCount++;
allowMergeGlobalCommandsCount++;
return new AccessToken() {
@Override
public void finish() {
ThreadingAssertions.assertWriteIntentReadAccess();
myAllowMergeGlobalCommandsCount--;
allowMergeGlobalCommandsCount--;
}
};
}
@@ -464,16 +367,38 @@ public class CoreCommandProcessor extends CommandProcessorEx {
}
}
private void fireCommandStarted() {
CommandDescriptor currentCommand = myCurrentCommand;
CommandEvent event = new CommandEvent(this,
currentCommand.myCommand,
currentCommand.myName,
currentCommand.myGroupId,
currentCommand.myProject,
currentCommand.myUndoConfirmationPolicy,
currentCommand.myShouldRecordActionForActiveDocument,
currentCommand.myDocument);
@ApiStatus.Internal
protected boolean isCommandTokenActive(@NotNull CommandToken command) {
return command.equals(currentCommand);
}
private void fireCommandStarted(@NotNull CommandDescriptor command) {
CommandEvent event = command.toCommandEvent(this);
eventPublisher.commandStarted(event);
}
private void fireCommandFinished(@NotNull CommandDescriptor command) {
CommandEvent event = command.toCommandEvent(this);
try {
eventPublisher.beforeCommandFinished(event);
}
finally {
this.currentCommand = null;
eventPublisher.commandFinished(event);
}
LOG.debug("finishCommand: name = " + event.getCommandName() + ", groupId = " + event.getCommandGroupId());
}
private static @Nullable Document getDocumentFromGroupId(@Nullable Object groupId) {
if (groupId instanceof Document) {
return (Document) groupId;
}
if (groupId instanceof Ref) {
Object value = ((Ref<?>) groupId).get();
if (value instanceof Document) {
return (Document) value;
}
}
return null;
}
}
@@ -936,7 +936,7 @@ public final class DocumentImpl extends UserDataHolderBase implements DocumentEx
if (!myAssertThreading) return;
CommandProcessor commandProcessor = CommandProcessor.getInstance();
if (!commandProcessor.isUndoTransparentActionInProgress() &&
commandProcessor.getCurrentCommand() == null) {
!commandProcessor.isCommandInProgress()) {
throw new IncorrectOperationException("Must not change document outside command or undo-transparent action. See com.intellij.openapi.command.WriteCommandAction or com.intellij.openapi.command.CommandProcessor");
}
}
@@ -270,7 +270,7 @@ public class PomModelImpl extends UserDataHolderBase implements PomModel {
throw new IllegalStateException("Attempt to modify PSI for non-committed Document!");
}
CommandProcessor commandProcessor = CommandProcessor.getInstance();
if (physical && !commandProcessor.isUndoTransparentActionInProgress() && commandProcessor.getCurrentCommand() == null) {
if (physical && !commandProcessor.isUndoTransparentActionInProgress() && !commandProcessor.isCommandInProgress()) {
throw new IncorrectOperationException("Must not change PSI outside command or undo-transparent action. See com.intellij.openapi.command.WriteCommandAction or com.intellij.openapi.command.CommandProcessor");
}
}
@@ -61,7 +61,7 @@ internal class ActionTracker(
}
fun ignoreCurrentDocumentChange() {
if (CommandProcessor.getInstance().currentCommand == null) {
if (!CommandProcessor.getInstance().isCommandInProgress) {
return
}
@@ -676,7 +676,7 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
if (sameElement) {
JComponent preferredFocusableComponent = content.getPreferredFocusableComponent();
// focus toolwindow on the second actionPerformed
boolean focus = requestFocus || CommandProcessor.getInstance().getCurrentCommand() != null;
boolean focus = requestFocus || CommandProcessor.getInstance().isCommandInProgress();
if (preferredFocusableComponent != null && focus) {
IdeFocusManager.getInstance(myProject).requestFocus(preferredFocusableComponent, true);
}
@@ -56,7 +56,7 @@ final class ScratchImplUtil {
@Nullable VirtualFile file,
@NotNull LanguageItem item) throws IOException {
ApplicationManager.getApplication().assertWriteAccessAllowed();
if (CommandProcessor.getInstance().getCurrentCommand() == null) {
if (!CommandProcessor.getInstance().isCommandInProgress()) {
throw new AssertionError("command required");
}
@@ -528,7 +528,7 @@ public class VariableInplaceRenamer extends InplaceRefactoring {
boolean bind = false;
if (myInsertedName != null) {
final CommandProcessor commandProcessor = CommandProcessor.getInstance();
if (commandProcessor.getCurrentCommand() != null && getVariable() != null) {
if (commandProcessor.isCommandInProgress() && getVariable() != null) {
commandProcessor.setCurrentCommandName(getCommandName());
}
@@ -192,7 +192,7 @@ public final class LineWrappingUtil {
try {
Runnable command = () -> EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_ENTER)
.execute(editor, editor.getCaretModel().getCurrentCaret(), dataContext);
if (commandProcessor.getCurrentCommand() == null) {
if (!commandProcessor.isCommandInProgress()) {
commandProcessor.executeCommand(project, command, WRAP_LINE_COMMAND_NAME, null);
}
else {
@@ -21,7 +21,7 @@ import org.jetbrains.annotations.Nullable;
public final class CommandProcessorImpl extends CoreCommandProcessor implements Disposable {
@Override
public void finishCommand(final @NotNull CommandToken command, final @Nullable Throwable throwable) {
if (myCurrentCommand != command) return;
if (!isCommandTokenActive(command)) return;
final boolean failed;
try {
if (throwable != null) {
@@ -1175,7 +1175,7 @@ public final class EditorUtil {
* command (so that it becomes part of it), otherwise does nothing.
*/
public static void performBeforeCommandEnd(@NotNull Runnable task) {
if (CommandProcessor.getInstance().getCurrentCommand() == null) return;
if (!CommandProcessor.getInstance().isCommandInProgress()) return;
MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect();
connection.subscribe(CommandListener.TOPIC, new CommandListener() {
@Override
@@ -270,7 +270,7 @@ public final class ScrollingModelImpl implements ScrollingModelEx {
if (!editor.getSettings().isAnimatedScrolling() || animationDisabled || RemoteDesktopService.isRemoteSession()) {
useAnimation = false;
}
else if (CommandProcessor.getInstance().getCurrentCommand() == null) {
else if (!CommandProcessor.getInstance().isCommandInProgress()) {
useAnimation = editor.getComponent().isShowing();
}
else {
@@ -488,8 +488,8 @@ public class FileDocumentManagerImpl extends FileDocumentManagerBase implements
if (lineSeparator == null) {
lineSeparator = document.getUserData(LINE_SEPARATOR_KEY);
if (lineSeparator == null) {
Runnable currentCommand = CommandProcessor.getInstance().getCurrentCommand();
Project project = currentCommand == null ? null : CommandProcessor.getInstance().getCurrentCommandProject();
CommandProcessor commandProcessor = CommandProcessor.getInstance();
Project project = commandProcessor.isCommandInProgress() ? commandProcessor.getCurrentCommandProject() : null;
if (project == null) {
project = ProjectUtil.guessProjectForFile(virtualFile);
}
@@ -62,7 +62,7 @@ public class DocumentTest extends LightPlatformTestCase {
public void testModificationInsideCommandAssertion() {
CommandProcessor commandProcessor = CommandProcessor.getInstance();
assertTrue(!commandProcessor.isUndoTransparentActionInProgress() &&
commandProcessor.getCurrentCommand() == null);
!commandProcessor.isCommandInProgress());
final Document doc = new DocumentImpl("xxx");
@@ -354,7 +354,7 @@ class ChangelistsLocalLineStatusTracker internal constructor(project: Project,
if (project.isDisposed) return
if (hasUndoInCommand) return
if (undoManager.isUndoOrRedoInProgress) return
if (CommandProcessor.getInstance().currentCommand == null) return
if (!CommandProcessor.getInstance().isCommandInProgress) return
hasUndoInCommand = true
registerUndoAction(true)
@@ -375,13 +375,13 @@ class ChangelistsLocalLineStatusTracker internal constructor(project: Project,
}
override fun undoTransparentActionStarted() {
if (CommandProcessor.getInstance().currentCommand == null) {
if (!CommandProcessor.getInstance().isCommandInProgress) {
hasUndoInCommand = false
}
}
override fun undoTransparentActionFinished() {
if (CommandProcessor.getInstance().currentCommand == null) {
if (!CommandProcessor.getInstance().isCommandInProgress) {
hasUndoInCommand = false
}
}
@@ -911,7 +911,7 @@ class LineStatusTrackerManager(
override fun commandFinished(event: CommandEvent) {
if (!partialChangeListsEnabled) return
if (CommandProcessor.getInstance().currentCommand == null &&
if (!CommandProcessor.getInstance().isCommandInProgress &&
!filesWithDamagedInactiveRanges.isEmpty()) {
showInactiveRangesDamagedNotification()
}