diff --git a/plugins/gradle/plugin-resources/META-INF/plugin.xml b/plugins/gradle/plugin-resources/META-INF/plugin.xml
index ed820de5b250..ca1bf825c26a 100644
--- a/plugins/gradle/plugin-resources/META-INF/plugin.xml
+++ b/plugins/gradle/plugin-resources/META-INF/plugin.xml
@@ -111,6 +111,8 @@
+
+
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleExecuteTaskAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleExecuteTaskAction.java
index 164e7fa3ffe3..35bf6cbc3660 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleExecuteTaskAction.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleExecuteTaskAction.java
@@ -111,6 +111,10 @@ public class GradleExecuteTaskAction extends ExternalSystemAction {
historyService.addCommand(fullCommandLine, workDirectory);
+ runGradle(project, workDirectory, fullCommandLine);
+ }
+
+ public static void runGradle(@NotNull Project project, @NotNull String workDirectory, @NotNull String fullCommandLine) {
final ExternalTaskExecutionInfo taskExecutionInfo;
try {
taskExecutionInfo = buildTaskInfo(workDirectory, fullCommandLine);
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleRunAnythingHelpGroup.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleRunAnythingHelpGroup.java
new file mode 100644
index 000000000000..5bbc0aa50b5d
--- /dev/null
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleRunAnythingHelpGroup.java
@@ -0,0 +1,26 @@
+// 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 org.jetbrains.plugins.gradle.execution;
+
+import com.intellij.ide.actions.runAnything.activity.RunAnythingProvider;
+import com.intellij.ide.actions.runAnything.groups.RunAnythingHelpGroup;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+
+/**
+ * @author Vladislav.Soroka
+ */
+public class GradleRunAnythingHelpGroup extends RunAnythingHelpGroup {
+ @NotNull
+ @Override
+ public String getTitle() {
+ return "Gradle";
+ }
+
+ @NotNull
+ @Override
+ public Collection getProviders() {
+ return ContainerUtil.immutableSingletonList(RunAnythingProvider.EP_NAME.findExtension(GradleRunAnythingProvider.class));
+ }
+}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleRunAnythingProvider.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleRunAnythingProvider.java
new file mode 100644
index 000000000000..85469575c876
--- /dev/null
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleRunAnythingProvider.java
@@ -0,0 +1,179 @@
+// 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 org.jetbrains.plugins.gradle.execution;
+
+import com.intellij.ide.actions.runAnything.activity.RunAnythingProviderBase;
+import com.intellij.ide.actions.runAnything.items.RunAnythingItem;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.externalSystem.model.DataNode;
+import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
+import com.intellij.openapi.externalSystem.model.ProjectKeys;
+import com.intellij.openapi.externalSystem.model.project.ModuleData;
+import com.intellij.openapi.externalSystem.model.task.TaskData;
+import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.util.CachedValueProvider;
+import com.intellij.psi.util.CachedValuesManager;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.MultiMap;
+import groovyjarjarcommonscli.Option;
+import icons.GradleIcons;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.gradle.action.GradleExecuteTaskAction;
+import org.jetbrains.plugins.gradle.service.execution.cmd.GradleCommandLineOptionsProvider;
+import org.jetbrains.plugins.gradle.settings.GradleProjectSettings;
+import org.jetbrains.plugins.gradle.settings.GradleSettings;
+import org.jetbrains.plugins.gradle.util.GradleConstants;
+
+import javax.swing.*;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static com.intellij.ide.actions.runAnything.RunAnythingUtil.fetchProject;
+import static com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil.getChildren;
+
+/**
+ * @author Vladislav.Soroka
+ */
+public class GradleRunAnythingProvider extends RunAnythingProviderBase {
+
+ @NotNull
+ @Override
+ public RunAnythingItem getMainListItem(@NotNull DataContext dataContext, @NotNull String value) {
+ return new RunAnythingGradleItem(getCommand(value), getIcon(value));
+ }
+
+ @Nullable
+ @Override
+ public String findMatchingValue(@NotNull DataContext dataContext, @NotNull String pattern) {
+ return pattern.startsWith(getHelpCommand()) ? getCommand(pattern) : null;
+ }
+
+ @NotNull
+ @Override
+ public Collection getValues(@NotNull DataContext dataContext, @NotNull String pattern) {
+ if (!pattern.startsWith(getHelpCommand())) {
+ return Collections.emptyList();
+ }
+ List result = ContainerUtil.newSmartList();
+
+ int spaceIndex = StringUtil.lastIndexOf(pattern, ' ', getHelpCommand().length(), pattern.length());
+ String prefix = StringUtil.trim(spaceIndex < 0 ? getHelpCommand() : pattern.substring(0, spaceIndex + 1)) + ' ';
+ String toComplete = spaceIndex < 0 ? "" : pattern.substring(spaceIndex + 1);
+
+ appendArgumentsVariants(result, prefix, toComplete);
+ if (!result.isEmpty()) return result;
+
+ appendTasksVariants(result, prefix, dataContext);
+ return result;
+ }
+
+ private static void appendTasksVariants(@NotNull List result, @NotNull String prefix, @NotNull DataContext dataContext) {
+ MultiMap tasks = fetchTasks(dataContext);
+ for (Map.Entry> entry : tasks.entrySet()) {
+ for (String taskName : entry.getValue()) {
+ String taskFqn = entry.getKey() + taskName;
+ result.add(prefix + taskFqn);
+ }
+ }
+ }
+
+ private static void appendArgumentsVariants(@NotNull List result, @NotNull String prefix, @NotNull String toComplete) {
+ if (!toComplete.startsWith("-")) return;
+
+ boolean isLongOpt = toComplete.startsWith("--");
+ prefix += (isLongOpt ? "--" : "-");
+ for (Object option : GradleCommandLineOptionsProvider.getSupportedOptions().getOptions()) {
+ if (option instanceof Option) {
+ String opt = isLongOpt ? ((Option)option).getLongOpt() : ((Option)option).getOpt();
+ if (StringUtil.isNotEmpty(opt)) {
+ result.add(prefix + opt);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void execute(@NotNull DataContext dataContext, @NotNull String value) {
+ Project project = fetchProject(dataContext);
+ String commandLine = StringUtil.trimStart(value, getHelpCommand());
+ for (GradleProjectSettings setting : GradleSettings.getInstance(project).getLinkedProjectsSettings()) {
+ GradleExecuteTaskAction.runGradle(project, setting.getExternalProjectPath(), commandLine);
+ }
+ }
+
+ @NotNull
+ @Override
+ public String getCommand(@NotNull String value) {
+ return value;
+ }
+
+ @Nullable
+ @Override
+ public Icon getIcon(@NotNull String value) {
+ return GradleIcons.Gradle;
+ }
+
+ @NotNull
+ public String getCompletionGroupTitle() {
+ return "Gradle tasks";
+ }
+
+ @NotNull
+ @Override
+ public String getHelpCommandPlaceholder() {
+ return "gradle <--option-name...>";
+ }
+
+ @NotNull
+ @Override
+ public String getHelpCommand() {
+ return "gradle";
+ }
+
+ @Override
+ public Icon getHelpIcon() {
+ return GradleIcons.Gradle;
+ }
+
+ private static MultiMap fetchTasks(@NotNull DataContext dataContext) {
+ Project project = fetchProject(dataContext);
+ return CachedValuesManager.getManager(project).getCachedValue(
+ project, () -> CachedValueProvider.Result.create(getTasksMap(project), ProjectRootManager.getInstance(project)));
+ }
+
+ @NotNull
+ private static MultiMap getTasksMap(Project project) {
+ MultiMap tasks = MultiMap.createOrderedSet();
+ for (GradleProjectSettings setting : GradleSettings.getInstance(project).getLinkedProjectsSettings()) {
+ final ExternalProjectInfo projectData =
+ ProjectDataManager.getInstance().getExternalProjectData(project, GradleConstants.SYSTEM_ID, setting.getExternalProjectPath());
+ if (projectData == null || projectData.getExternalProjectStructure() == null) continue;
+
+ for (DataNode moduleDataNode : getChildren(projectData.getExternalProjectStructure(), ProjectKeys.MODULE)) {
+ String gradlePath;
+ String moduleId = moduleDataNode.getData().getId();
+ if (moduleId.charAt(0) != ':') {
+ int colonIndex = moduleId.indexOf(':');
+ gradlePath = colonIndex > 0 ? moduleId.substring(colonIndex) : ":";
+ }
+ else {
+ gradlePath = moduleId;
+ }
+ for (DataNode node : getChildren(moduleDataNode, ProjectKeys.TASK)) {
+ TaskData taskData = node.getData();
+ String taskName = taskData.getName();
+ if (StringUtil.isNotEmpty(taskName)) {
+ String taskPathPrefix = ":".equals(gradlePath) || taskName.startsWith(gradlePath) ? "" : (gradlePath + ':');
+ tasks.putValue(taskPathPrefix, taskName);
+ }
+ }
+ }
+ }
+ return tasks;
+ }
+}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/RunAnythingGradleItem.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/RunAnythingGradleItem.java
new file mode 100644
index 000000000000..39dcba327c3a
--- /dev/null
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/RunAnythingGradleItem.java
@@ -0,0 +1,52 @@
+// 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 org.jetbrains.plugins.gradle.execution;
+
+import com.intellij.ide.actions.runAnything.items.RunAnythingItemBase;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.ui.SimpleColoredComponent;
+import com.intellij.ui.SimpleTextAttributes;
+import groovyjarjarcommonscli.Option;
+import groovyjarjarcommonscli.Options;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.gradle.service.execution.cmd.GradleCommandLineOptionsProvider;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * @author Vladislav.Soroka
+ */
+public class RunAnythingGradleItem extends RunAnythingItemBase {
+
+ public RunAnythingGradleItem(@NotNull String command, @Nullable Icon icon) {
+ super(command, icon);
+ }
+
+ @NotNull
+ @Override
+ public Component createComponent(boolean isSelected) {
+ String command = getCommand();
+
+ int spaceIndex = StringUtil.lastIndexOf(command, ' ', 0, command.length());
+ String toComplete = spaceIndex < 0 ? "" : command.substring(spaceIndex + 1);
+ String description = null;
+ if (toComplete.startsWith("-")) {
+ boolean isLongOpt = toComplete.startsWith("--");
+ Options options = GradleCommandLineOptionsProvider.getSupportedOptions();
+ Option option = options.getOption(toComplete.substring(isLongOpt ? 2 : 1));
+ if (option != null) {
+ description = option.getDescription();
+ }
+ }
+ SimpleColoredComponent component = new SimpleColoredComponent();
+ component.append(command);
+ component.appendTextPadding(20);
+ setupIcon(component, myIcon);
+
+ if (description != null) {
+ component.append(" " + StringUtil.shortenTextWithEllipsis(description, 200, 0), SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES);
+ }
+ return component;
+ }
+}
\ No newline at end of file