diff --git a/platform/diff-impl/src/com/intellij/diff/applications/MergeApplication.kt b/platform/diff-impl/src/com/intellij/diff/applications/MergeApplication.kt index 18cb844b74b9..dfc2261deb63 100644 --- a/platform/diff-impl/src/com/intellij/diff/applications/MergeApplication.kt +++ b/platform/diff-impl/src/com/intellij/diff/applications/MergeApplication.kt @@ -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 processCommand(@NotNull List args, @Nullable String currentDirectory) throws Exception { - List filePaths = args.subList(1, 4); - List files = DiffApplicationBase.findFilesOrThrow(filePaths, currentDirectory); - Project project = DiffApplicationBase.guessProject(files); - - List 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, 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 future = new CompletableFuture<>(); - AtomicReference 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() + 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 myContents; - private final AtomicReference myResultRef; + private class MyMergeRequestProducer(private val project: Project?, + private val outputFile: VirtualFile, + private val contents: List, + private val resultRef: AtomicReference) : MergeRequestProducer { + override fun getName(): String = DiffBundle.message("merge.window.title.file", outputFile.presentableUrl) - private MyMergeRequestProducer(@Nullable Project project, - @NotNull VirtualFile outputFile, - @NotNull List contents, - @NotNull AtomicReference 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 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) } } } -} +} \ No newline at end of file