blob: f62bd84982d9309d7159d2983f8b5609dc0f2fbc [file] [log] [blame]
/*
* Copyright 2000-2011 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.debugger.actions;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.AnonymousClassMethodFilter;
import com.intellij.debugger.engine.BasicStepMethodFilter;
import com.intellij.debugger.engine.LambdaMethodFilter;
import com.intellij.debugger.engine.MethodFilter;
import com.intellij.debugger.impl.DebuggerSession;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.components.JBList;
import com.intellij.ui.popup.list.ListPopupImpl;
import com.intellij.xdebugger.impl.actions.XDebuggerActions;
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import java.util.List;
/**
* User: Alexander Podkhalyuzin
* Date: 22.11.11
*/
public abstract class JvmSmartStepIntoHandler {
public static ExtensionPointName<JvmSmartStepIntoHandler> EP_NAME = ExtensionPointName.create("com.intellij.debugger.jvmSmartStepIntoHandler");
@NotNull
public abstract List<SmartStepTarget> findSmartStepTargets(SourcePosition position);
public abstract boolean isAvailable(SourcePosition position);
/**
* Override this if you haven't PsiMethod, like in Kotlin.
* @param position
* @param session
* @param fileEditor
* @return false to continue for another handler or for default action (step into)
*/
public boolean doSmartStep(SourcePosition position, final DebuggerSession session, TextEditor fileEditor) {
final List<SmartStepTarget> targets = findSmartStepTargets(position);
if (!targets.isEmpty()) {
final SmartStepTarget firstTarget = targets.get(0);
if (targets.size() == 1) {
session.stepInto(true, createMethodFilter(firstTarget));
}
else {
final Editor editor = fileEditor.getEditor();
final PsiMethodListPopupStep popupStep = new PsiMethodListPopupStep(editor, targets, new PsiMethodListPopupStep.OnChooseRunnable() {
public void execute(SmartStepTarget chosenTarget) {
session.stepInto(true, createMethodFilter(chosenTarget));
}
});
final ListPopup popup = new ListPopupImpl(popupStep) {
@Override
protected JComponent createContent() {
registerExtraHandleShortcuts(XDebuggerActions.STEP_INTO);
registerExtraHandleShortcuts(XDebuggerActions.SMART_STEP_INTO);
return super.createContent();
}
private void registerExtraHandleShortcuts(String actionName) {
AnAction action = ActionManager.getInstance().getAction(actionName);
KeyStroke stroke = KeymapUtil.getKeyStroke(action.getShortcutSet());
if (stroke != null) {
registerAction("handleSelection " + stroke, stroke, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
handleSelect(true);
}
});
}
}
};
popup.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
popupStep.getScopeHighlighter().dropHighlight();
if (!e.getValueIsAdjusting()) {
final SmartStepTarget selectedTarget = (SmartStepTarget)((JBList)e.getSource()).getSelectedValue();
if (selectedTarget != null) {
highlightTarget(popupStep, selectedTarget);
}
}
}
});
highlightTarget(popupStep, firstTarget);
final RelativePoint point = DebuggerUIUtil.calcPopupLocation(editor, position.getLine());
popup.show(point);
}
return true;
}
return false;
}
private static void highlightTarget(PsiMethodListPopupStep popupStep, SmartStepTarget target) {
final PsiElement highlightElement = target.getHighlightElement();
if (highlightElement != null) {
popupStep.getScopeHighlighter().highlight(highlightElement, Arrays.asList(highlightElement));
}
}
/**
* Override in case if your JVMNames slightly different then it can be provided by getJvmSignature method.
*
* @param stepTarget
* @return SmartStepFilter
*/
@Nullable
protected MethodFilter createMethodFilter(SmartStepTarget stepTarget) {
if (stepTarget instanceof MethodSmartStepTarget) {
final PsiMethod method = ((MethodSmartStepTarget)stepTarget).getMethod();
return stepTarget.needsBreakpointRequest()? new AnonymousClassMethodFilter(method, stepTarget.getCallingExpressionLines()) :
new BasicStepMethodFilter(method, stepTarget.getCallingExpressionLines());
}
if (stepTarget instanceof LambdaSmartStepTarget) {
final LambdaSmartStepTarget lambdaTarget = (LambdaSmartStepTarget)stepTarget;
return new LambdaMethodFilter(lambdaTarget.getLambda(), lambdaTarget.getOrdinal(), stepTarget.getCallingExpressionLines());
}
return null;
}
}