diff --git a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java index 37535df104b7..34747d5c0984 100644 --- a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java @@ -34,7 +34,9 @@ import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; import com.intellij.psi.util.PsiMethodUtil; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.listeners.RefactoringElementListener; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -123,6 +125,11 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration extends Location { private final Project myProject; private final Module myModule; + public PsiLocation(E psiElement) { + this(psiElement.getProject(), psiElement); + } + public PsiLocation(@NotNull final Project project, @NotNull final E psiElement) { myPsiElement = psiElement; myProject = project; - myModule = ModuleUtil.findModuleForPsiElement(psiElement); + myModule = ModuleUtilCore.findModuleForPsiElement(psiElement); } public PsiLocation(@NotNull Project project, Module module, @NotNull E psiElement) { diff --git a/platform/lang-api/src/com/intellij/execution/actions/ConfigurationContext.java b/platform/lang-api/src/com/intellij/execution/actions/ConfigurationContext.java index 77c41f423402..5b0eef8c3568 100644 --- a/platform/lang-api/src/com/intellij/execution/actions/ConfigurationContext.java +++ b/platform/lang-api/src/com/intellij/execution/actions/ConfigurationContext.java @@ -32,6 +32,7 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; @@ -102,6 +103,13 @@ public class ConfigurationContext { myLocation = new PsiLocation(project, myModule, element); } + public ConfigurationContext(PsiElement element) { + myModule = ModuleUtilCore.findModuleForPsiElement(element); + myLocation = new PsiLocation(element.getProject(), myModule, element); + myRuntimeConfiguration = null; + myContextComponent = null; + } + /** * Returns the configuration created from this context. * @@ -276,6 +284,7 @@ public class ConfigurationContext { return myPreferredProducers; } + @Nullable public List getConfigurationsFromContext() { if (myConfigurationsFromContext == null) { myConfigurationsFromContext = PreferredProducerFind.getConfigurationsFromContext(myLocation, this, true); diff --git a/platform/lang-api/src/com/intellij/execution/actions/PreferredProducerFind.java b/platform/lang-api/src/com/intellij/execution/actions/PreferredProducerFind.java index 8c5cae1ce35c..2282a02df8a6 100644 --- a/platform/lang-api/src/com/intellij/execution/actions/PreferredProducerFind.java +++ b/platform/lang-api/src/com/intellij/execution/actions/PreferredProducerFind.java @@ -90,6 +90,7 @@ class PreferredProducerFind { return producers; } + @Nullable public static List getConfigurationsFromContext(final Location location, final ConfigurationContext context, final boolean strict) { diff --git a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java index 4290ff885cea..b7052a994986 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java @@ -25,6 +25,7 @@ import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizerUtil; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.psi.PsiElement; import com.intellij.util.xmlb.annotations.Attribute; import com.intellij.util.xmlb.annotations.Transient; import org.jdom.Element; @@ -122,6 +123,10 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements return true; } + public boolean isLineMarkerPlace(PsiElement place, PsiElement sourceElement) { + return place == sourceElement; + } + public final boolean equals(final Object obj) { return super.equals(obj); } diff --git a/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerProvider.java b/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerProvider.java new file mode 100644 index 000000000000..a8637e28c22c --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerProvider.java @@ -0,0 +1,131 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.lineMarker; + +import com.intellij.codeHighlighting.Pass; +import com.intellij.codeInsight.daemon.LineMarkerInfo; +import com.intellij.codeInsight.daemon.LineMarkerProvider; +import com.intellij.execution.Executor; +import com.intellij.execution.ExecutorRegistry; +import com.intellij.execution.Location; +import com.intellij.execution.PsiLocation; +import com.intellij.execution.actions.ConfigurationContext; +import com.intellij.execution.actions.ConfigurationFromContext; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.configurations.RunConfigurationBase; +import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.impl.ActionPopupMenuImpl; +import com.intellij.openapi.editor.markup.GutterIconRenderer; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Getter; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNameIdentifierOwner; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseEvent; +import java.util.Collection; +import java.util.List; + +public class RunLineMarkerProvider implements LineMarkerProvider { + + @Nullable + @Override + public LineMarkerInfo getLineMarkerInfo(@NotNull final PsiElement element) { + if (!(element instanceof PsiNameIdentifierOwner)) { + return null; + } + ConfigurationContext context = new ConfigurationContext(element); + List configurations = context.getConfigurationsFromContext(); + if (configurations != null && !configurations.isEmpty()) { + configurations = ContainerUtil.filter(configurations, new Condition() { + @Override + public boolean value(ConfigurationFromContext context) { + RunConfiguration configuration = context.getConfiguration(); + if (!(configuration instanceof RunConfigurationBase)) return false; + return ((RunConfigurationBase)configuration).isLineMarkerPlace(element, context.getSourceElement()); + } + }); + if (configurations.isEmpty()) return null; + Icon icon = null; + for (ConfigurationFromContext configuration : configurations) { + icon = configuration.getConfiguration().getType().getIcon(); + } + return new LineMarkerInfo(element, element.getTextOffset(), icon, Pass.UPDATE_ALL, null, + null, GutterIconRenderer.Alignment.CENTER) { + @Nullable + @Override + public GutterIconRenderer createGutterRenderer() { + return new LineMarkerGutterIconRenderer(this) { + @Override + public boolean isNavigateAction() { + return true; + } + + @Override + public AnAction getClickAction() { + return new AnAction() { + @Override + public void actionPerformed(AnActionEvent e) { + Executor[] executors = ExecutorRegistry.getInstance().getRegisteredExecutors(); + List actions = ContainerUtil.mapNotNull(executors, + new Function() { + @Override + public AnAction fun(Executor executor) { + return ActionManager.getInstance().getAction(executor.getContextActionId()); + } + }); + ActionPopupMenuImpl popupMenu = (ActionPopupMenuImpl)ActionManager.getInstance().createActionPopupMenu(ActionPlaces.EDITOR_POPUP, new DefaultActionGroup(actions)); + + final MouseEvent me = (MouseEvent)e.getInputEvent(); + final Component c = me.getComponent(); + if (c != null && c.isShowing()) { + popupMenu.setDataContextProvider(new Getter() { + @Override + public DataContext get() { + final DataContext delegate = DataManager.getInstance().getDataContext(c, me.getX(), me.getY()); + return new DataContext() { + @Nullable + @Override + public Object getData(@NonNls String dataId) { + if (Location.DATA_KEY.is(dataId)) return new PsiLocation(element); + return delegate.getData(dataId); + } + }; + } + }); + popupMenu.getComponent().show(c, me.getX(), me.getY()); + } + } + }; + } + }; + } + }; + } + return null; + } + + @Override + public void collectSlowLineMarkers(@NotNull List elements, @NotNull Collection result) { + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionPopupMenuImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionPopupMenuImpl.java index 185557cafa67..de41534d68f8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionPopupMenuImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionPopupMenuImpl.java @@ -42,7 +42,7 @@ import java.awt.*; * @author Anton Katilin * @author Vladimir Kondratyev */ -final class ActionPopupMenuImpl implements ActionPopupMenu, ApplicationActivationListener { +public final class ActionPopupMenuImpl implements ActionPopupMenu, ApplicationActivationListener { private final MyMenu myMenu; private final ActionManagerImpl myManager; diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index eb6eb6f24354..05b54bd85a70 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -561,6 +561,8 @@ + +