IDEA-298857 Command line "Idea diff" does not make Idea window focused (part 2 - "merge")

GitOrigin-RevId: 1af9be1ed0a5e6a46b0d56107d6061b7888fd9c8
This commit is contained in:
Vladimir Krivosheev
2022-10-13 09:28:12 +00:00
committed by intellij-monorepo-bot
parent 1a17e44496
commit b3d585e63a
@@ -1,131 +1,98 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.diff.applications;
package com.intellij.diff.applications
import com.intellij.diff.DiffDialogHints;
import com.intellij.diff.DiffManagerEx;
import com.intellij.diff.DiffRequestFactory;
import com.intellij.diff.chains.DiffRequestProducerException;
import com.intellij.diff.merge.MergeRequest;
import com.intellij.diff.merge.MergeRequestProducer;
import com.intellij.diff.merge.MergeResult;
import com.intellij.ide.CliResult;
import com.intellij.idea.SplashManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.application.ApplicationStarterBase;
import com.intellij.openapi.diff.DiffBundle;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.WindowWrapper;
import com.intellij.openapi.util.UserDataHolder;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.diff.DiffDialogHints
import com.intellij.diff.DiffManagerEx
import com.intellij.diff.DiffRequestFactory
import com.intellij.diff.chains.DiffRequestProducerException
import com.intellij.diff.merge.MergeRequest
import com.intellij.diff.merge.MergeRequestProducer
import com.intellij.diff.merge.MergeResult
import com.intellij.ide.CliResult
import com.intellij.idea.SplashManager
import com.intellij.openapi.application.ApplicationNamesInfo
import com.intellij.openapi.application.ApplicationStarterBase
import com.intellij.openapi.application.EDT
import com.intellij.openapi.diff.DiffBundle
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.WindowWrapper
import com.intellij.openapi.util.UserDataHolder
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.ui.AppIcon
import com.intellij.util.containers.ContainerUtil
import com.intellij.util.ui.UIUtil
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.concurrent.atomic.AtomicReference
import java.awt.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
internal class MergeApplication : ApplicationStarterBase(3, 4) {
override val commandName: String
get() = "merge"
final class MergeApplication extends ApplicationStarterBase {
MergeApplication() {
super(3, 4);
}
override val usageMessage: String
get() {
val scriptName = ApplicationNamesInfo.getInstance().scriptName
return DiffBundle.message("merge.application.usage.parameters.and.description", scriptName)
}
@Override
public String getCommandName() {
return "merge";
}
@Override
public @NotNull String getUsageMessage() {
final String scriptName = ApplicationNamesInfo.getInstance().getScriptName();
return DiffBundle.message("merge.application.usage.parameters.and.description", scriptName);
}
@Override
public @NotNull CompletableFuture<CliResult> processCommand(@NotNull List<String> args, @Nullable String currentDirectory) throws Exception {
List<String> filePaths = args.subList(1, 4);
List<VirtualFile> files = DiffApplicationBase.findFilesOrThrow(filePaths, currentDirectory);
Project project = DiffApplicationBase.guessProject(files);
List<VirtualFile> contents = Arrays.asList(files.get(0), files.get(2), files.get(1)); // left, base, right
VirtualFile outputFile;
if (args.size() == 5) {
String outputFilePath = args.get(4);
outputFile = DiffApplicationBase.findOrCreateFile(outputFilePath, currentDirectory);
DiffApplicationBase.refreshAndEnsureFilesValid(Collections.singletonList(outputFile));
override suspend fun executeCommand(args: List<String>, currentDirectory: String?): CliResult {
val filePaths = args.subList(1, 4)
val files = DiffApplicationBase.findFilesOrThrow(filePaths, currentDirectory)
val project = DiffApplicationBase.guessProject(files)
val contents = listOf(files[0], files[2], files[1]) // left, base, right
val outputFile: VirtualFile?
if (args.size == 5) {
val outputFilePath = args[4]
outputFile = DiffApplicationBase.findOrCreateFile(outputFilePath, currentDirectory)
DiffApplicationBase.refreshAndEnsureFilesValid(listOf(outputFile))
}
else {
outputFile = files.get(2); // base
outputFile = files[2] // base
}
if (outputFile == null) {
throw Exception(DiffBundle.message("cannot.create.file.error", ContainerUtil.getLastItem(filePaths)))
}
if (outputFile == null) throw new Exception(DiffBundle.message("cannot.create.file.error", ContainerUtil.getLastItem(filePaths)));
CompletableFuture<CliResult> future = new CompletableFuture<>();
AtomicReference<CliResult> resultRef = new AtomicReference<>(new CliResult(127, null));
ApplicationManager.getApplication().invokeLater(() -> {
MergeRequestProducer requestProducer = new MyMergeRequestProducer(project, outputFile, contents, resultRef);
WindowWrapper.Mode mode = project != null ? WindowWrapper.Mode.FRAME : WindowWrapper.Mode.MODAL;
DiffDialogHints dialogHints = new DiffDialogHints(mode, null, wrapper -> {
Window window = wrapper.getWindow();
SplashManager.hideBeforeShow(window);
UIUtil.runWhenWindowClosed(window, () -> {
future.complete(resultRef.get());
});
});
DiffManagerEx.getInstance().showMergeBuiltin(project, requestProducer, dialogHints);
});
return future;
val deferred = CompletableDeferred<CliResult>()
withContext(Dispatchers.EDT) {
val resultRef = AtomicReference(CliResult(127, null))
val requestProducer = MyMergeRequestProducer(project, outputFile, contents, resultRef)
val mode = if (project == null) WindowWrapper.Mode.MODAL else WindowWrapper.Mode.FRAME
val dialogHints = DiffDialogHints(mode, null) { wrapper ->
val window = wrapper.window
SplashManager.hideBeforeShow(window)
AppIcon.getInstance().requestFocus(window)
UIUtil.runWhenWindowClosed(window) { deferred.complete(resultRef.get()) }
}
DiffManagerEx.getInstance().showMergeBuiltin(project, requestProducer, dialogHints)
}
return deferred.await()
}
private static final class MyMergeRequestProducer implements MergeRequestProducer {
private final Project myProject;
private final VirtualFile myOutputFile;
private final List<VirtualFile> myContents;
private final AtomicReference<CliResult> myResultRef;
private class MyMergeRequestProducer(private val project: Project?,
private val outputFile: VirtualFile,
private val contents: List<VirtualFile>,
private val resultRef: AtomicReference<CliResult>) : MergeRequestProducer {
override fun getName(): String = DiffBundle.message("merge.window.title.file", outputFile.presentableUrl)
private MyMergeRequestProducer(@Nullable Project project,
@NotNull VirtualFile outputFile,
@NotNull List<VirtualFile> contents,
@NotNull AtomicReference<CliResult> resultRef) {
myProject = project;
myOutputFile = outputFile;
myContents = contents;
myResultRef = resultRef;
}
@Override
public @NotNull String getName() {
return DiffBundle.message("merge.window.title.file", myOutputFile.getPresentableUrl());
}
@Override
public @NotNull MergeRequest process(@NotNull UserDataHolder context, @NotNull ProgressIndicator indicator)
throws DiffRequestProducerException, ProcessCanceledException {
try {
List<VirtualFile> contents = DiffApplicationBase.replaceNullsWithEmptyFile(myContents);
return DiffRequestFactory.getInstance().createMergeRequestFromFiles(myProject, myOutputFile, contents, result -> {
override fun process(context: UserDataHolder, indicator: ProgressIndicator): MergeRequest {
return try {
val contents = DiffApplicationBase.replaceNullsWithEmptyFile(contents)
DiffRequestFactory.getInstance().createMergeRequestFromFiles(project, outputFile, contents) { result ->
try {
saveIfNeeded(myOutputFile);
saveIfNeeded(outputFile)
}
finally {
int exitCode = result != MergeResult.CANCEL ? 0 : 1;
myResultRef.set(new CliResult(exitCode, null));
resultRef.set(CliResult(if (result == MergeResult.CANCEL) 1 else 0, null))
}
});
}
}
catch (Throwable e) {
myResultRef.set(new CliResult(127, e.getMessage()));
throw new DiffRequestProducerException(e);
catch (e: Throwable) {
resultRef.set(CliResult(127, e.message))
throw DiffRequestProducerException(e)
}
}
}
}
}