IDEA-CR-54321: IDEA-CR-52740 merged RunAnythingProviderWithVisibleExecutionFail.kt and RunAnythingNotifiableProvider.java

(cherry picked from commit 814189eb1796564df2c24671f187dc57caa16b96)

GitOrigin-RevId: 49e966e310bb3ee2ac5170a628f3c230194fd9ff
This commit is contained in:
Sergei Vorobyov
2019-11-07 02:40:58 +00:00
committed by intellij-monorepo-bot
parent 521231749b
commit f19099bf8e
7 changed files with 105 additions and 138 deletions
@@ -6,7 +6,7 @@ import com.intellij.util.execution.ParametersListUtil
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
abstract class RunAnythingCommandLineProvider : RunAnythingProviderWithVisibleExecutionFail<String>() {
abstract class RunAnythingCommandLineProvider : RunAnythingNotifiableProvider<String>() {
open fun getHelpCommandAliases(): List<String> = emptyList()
@@ -14,7 +14,7 @@ abstract class RunAnythingCommandLineProvider : RunAnythingProviderWithVisibleEx
protected abstract fun suggestCompletionVariants(dataContext: DataContext, commandLine: CommandLine): Sequence<String>
protected abstract fun runAnything(dataContext: DataContext, commandLine: CommandLine): Boolean
protected abstract fun run(dataContext: DataContext, commandLine: CommandLine): Boolean
override fun getCommand(value: String) = value
@@ -52,9 +52,9 @@ abstract class RunAnythingCommandLineProvider : RunAnythingProviderWithVisibleEx
return variants.map { "$prefix $it" }.toList()
}
override fun runAnything(dataContext: DataContext, value: String): Boolean {
override fun run(dataContext: DataContext, value: String): Boolean {
val commandLine = parseCommandLine(value) ?: return false
return runAnything(dataContext, commandLine)
return run(dataContext, commandLine)
}
class CommandLine(
@@ -1,98 +0,0 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.actions.runAnything.activity;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeBundle;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Implement notifiable provider if you desire to run an arbitrary activity in the IDE, that may hasn't provide visual effects,
* and show notification about it with optional ability to rollback the action as {@link #getRollbackAction(DataContext)}.
*
* @param <V> see {@link RunAnythingProvider}
*/
public abstract class RunAnythingNotifiableProvider<V> extends RunAnythingProviderWithVisibleExecutionFail<V> {
private static final String RUN_ANYTHING_GROUP_ID = IdeBundle.message("run.anything.custom.activity.notification.group.id");
/**
* Runs an activity silently. After the exception is passed a notification is shown.
*
* @param dataContext 'Run Anything' data context
* @return true if succeed, false is failed
*/
protected abstract boolean run(@NotNull DataContext dataContext, @NotNull V value);
/**
* Creates rollback action for {@link #run(DataContext, Object)}
*
* @param dataContext 'Run Anything' data context
* @return rollback action for {@link #run(DataContext, Object)}, null if isn't provided
*/
@Nullable
protected abstract Runnable getRollbackAction(@NotNull DataContext dataContext);
/**
* Creates post activity {@link Notification} title
*
* @param dataContext 'Run Anything' data context
*/
@NotNull
protected abstract String getNotificationTitle(@NotNull DataContext dataContext, @NotNull V value);
/**
* Creates post activity {@link Notification} content
*
* @param dataContext 'Run Anything' data context
*/
@NotNull
protected abstract String getNotificationContent(@NotNull DataContext dataContext, @NotNull V value);
/**
* Executes arbitrary activity in IDE and shows {@link Notification} with optional rollback action
*
* @param dataContext 'Run Anything' data context
* @return true if succeed, false is failed
*/
@Override
protected boolean runAnything(@NotNull DataContext dataContext, @NotNull V value) {
if (!run(dataContext, value)) return false;
getNotificationCallback(dataContext, value).run();
return true;
}
private Runnable getNotificationCallback(@NotNull DataContext dataContext, @NotNull V value) {
return () -> {
Notification notification = new Notification(
RUN_ANYTHING_GROUP_ID,
AllIcons.Actions.Run_anything,
getNotificationTitle(dataContext, value),
null,
getNotificationContent(dataContext, value),
NotificationType.INFORMATION,
null
);
Runnable rollbackAction = getRollbackAction(dataContext);
if (rollbackAction != null) {
AnAction action = new AnAction(IdeBundle.message("run.anything.custom.activity.rollback.action")) {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
rollbackAction.run();
notification.expire();
}
};
notification.addAction(action);
}
Notifications.Bus.notify(notification);
};
}
}
@@ -0,0 +1,97 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.actions.runAnything.activity
import com.intellij.icons.AllIcons.Actions.Run_anything
import com.intellij.ide.IdeBundle
import com.intellij.ide.actions.runAnything.RunAnythingUtil.fetchProject
import com.intellij.ide.actions.runAnything.activity.RunAnythingNotifiableProvider.ExecutionStatus.ERROR
import com.intellij.ide.actions.runAnything.activity.RunAnythingNotifiableProvider.ExecutionStatus.SUCCESS
import com.intellij.notification.Notification
import com.intellij.notification.NotificationType.INFORMATION
import com.intellij.notification.Notifications
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.DataContext
/**
* Implement notifiable provider if you desire to run an arbitrary activity in the IDE, that may hasn't provide visual effects,
* and show notification about it with optional actions.
*
* @param V see [RunAnythingProvider]
*/
abstract class RunAnythingNotifiableProvider<V> : RunAnythingProviderBase<V>() {
private val RUN_ANYTHING_GROUP_ID = IdeBundle.message("run.anything.custom.activity.notification.group.id")
private val notificationConfigurators = LinkedHashMap<ExecutionStatus, NotificationBuilder.() -> Unit>()
/**
* Runs an activity silently.
*
* @param dataContext 'Run Anything' data context
* @return true if succeed, false is failed
*/
protected abstract fun run(dataContext: DataContext, value: V): Boolean
override fun execute(dataContext: DataContext, value: V) {
try {
when (run(dataContext, value)) {
true -> notifyNotificationIfNeeded(SUCCESS, dataContext, value)
else -> notifyNotificationIfNeeded(ERROR, dataContext, value)
}
}
catch (ex: Throwable) {
notifyNotificationIfNeeded(ERROR, dataContext, value)
throw ex
}
}
private fun notifyNotificationIfNeeded(status: ExecutionStatus, dataContext: DataContext, value: V) {
val configure = notificationConfigurators[status] ?: return
val builder = NotificationBuilder(dataContext, value)
val notification = builder.apply(configure).build()
val project = fetchProject(dataContext)
Notifications.Bus.notify(notification, project)
}
protected fun notification(after: ExecutionStatus = SUCCESS, configure: NotificationBuilder.() -> Unit) {
notificationConfigurators[after] = configure
}
protected inner class NotificationBuilder(val dataContext: DataContext, val value: V) {
private val actions = ArrayList<ActionData>()
var title: String? = null
var subtitle: String? = null
var content: String? = null
fun action(name: String, perform: () -> Unit) {
actions.add(ActionData(name, perform))
}
fun build(): Notification {
val notification = Notification(RUN_ANYTHING_GROUP_ID, Run_anything, title, subtitle, content, INFORMATION, null)
for (actionData in actions) {
val action = object : AnAction(actionData.name) {
override fun actionPerformed(e: AnActionEvent) {
actionData.perform()
notification.expire()
}
}
notification.addAction(action)
}
return notification
}
}
protected enum class ExecutionStatus { SUCCESS, ERROR }
private data class ActionData(val name: String, val perform: () -> Unit)
init {
notification(ERROR) {
title = IdeBundle.message("run.anything.notification.warning.title")
content = IdeBundle.message("run.anything.notification.warning.content", getCommand(value))
}
}
}
@@ -1,32 +0,0 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.actions.runAnything.activity
import com.intellij.ide.IdeBundle
import com.intellij.ide.actions.runAnything.RunAnythingUtil.fetchProject
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.ui.Messages
abstract class RunAnythingProviderWithVisibleExecutionFail<V> : RunAnythingProviderBase<V>() {
protected abstract fun runAnything(dataContext: DataContext, value: V): Boolean
private fun notifyExecutionFail(dataContext: DataContext, value: V) {
Messages.showWarningDialog(
fetchProject(dataContext),
IdeBundle.message("run.anything.notification.warning.content", getCommand(value)),
IdeBundle.message("run.anything.notification.warning.title")
)
}
override fun execute(dataContext: DataContext, value: V) {
try {
if (!runAnything(dataContext, value)) {
notifyExecutionFail(dataContext, value)
}
}
catch (ex: Throwable) {
notifyExecutionFail(dataContext, value)
throw ex
}
}
}
@@ -38,7 +38,7 @@ abstract class RunAnythingCommandLineProviderTestCase : UsefulTestCase() {
override fun suggestCompletionVariants(dataContext: DataContext, commandLine: CommandLine) =
variants.asSequence()
override fun runAnything(dataContext: DataContext, commandLine: CommandLine) = true
override fun run(dataContext: DataContext, commandLine: CommandLine) = true
}
val emptyDataContext = DataContext { }
val values = provider.getValues(emptyDataContext, "$prefix $command")
@@ -60,7 +60,7 @@ abstract class RunAnythingCommandLineProviderTestCase : UsefulTestCase() {
return emptySequence()
}
override fun runAnything(dataContext: DataContext, commandLine: CommandLine): Boolean {
override fun run(dataContext: DataContext, commandLine: CommandLine): Boolean {
action(commandLine)
isRunningTouched = true
return true
@@ -88,7 +88,7 @@ class GradleRunAnythingProvider : RunAnythingCommandLineProvider() {
}
}
override fun runAnything(dataContext: DataContext, commandLine: CommandLine): Boolean {
override fun run(dataContext: DataContext, commandLine: CommandLine): Boolean {
val project = RunAnythingUtil.fetchProject(dataContext)
val executionContext = dataContext.getData(EXECUTING_CONTEXT) ?: ProjectContext(project)
val context = createContext(project, executionContext, dataContext)
@@ -46,7 +46,7 @@ class MavenRunAnythingProvider : RunAnythingCommandLineProvider() {
}
}
override fun runAnything(dataContext: DataContext, commandLine: CommandLine): Boolean {
override fun run(dataContext: DataContext, commandLine: CommandLine): Boolean {
val project = fetchProject(dataContext)
val context = dataContext.getData(EXECUTING_CONTEXT) ?: ProjectContext(project)
val projectsManager = MavenProjectsManager.getInstance(project)