IDEA-131134 Support multiple breakpoints within on single line - initial commit

This commit is contained in:
Egor.Ushakov
2015-06-11 20:45:23 +03:00
parent ac351ea039
commit 0908de1bde
14 changed files with 434 additions and 119 deletions
@@ -79,6 +79,7 @@ public class CompoundPositionManager extends PositionManagerEx implements MultiR
return defaultValue;
}
@Nullable
@Override
public SourcePosition getSourcePosition(final Location location) {
if (location == null) return null;
@@ -20,6 +20,7 @@ import com.intellij.debugger.NoDataException;
import com.intellij.debugger.PositionManager;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
import com.intellij.debugger.requests.ClassPrepareRequestor;
import com.intellij.execution.filters.LineNumbersMapping;
@@ -122,6 +123,7 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio
});
}
@Nullable
public SourcePosition getSourcePosition(final Location location) throws NoDataException {
DebuggerManagerThreadImpl.assertIsManagerThread();
if(location == null) {
@@ -254,51 +256,17 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio
PsiFile file = original.getFile();
int line = original.getLine();
if (LambdaMethodFilter.isLambdaName(myExpectedMethodName) && myLambdaOrdinal > -1) {
List<PsiLambdaExpression> lambdas = DebuggerUtilsEx.collectLambdas(original, false);
Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
if (document == null || line >= document.getLineCount()) {
return original;
}
PsiElement element = original.getElementAt();
TextRange lineRange = new TextRange(document.getLineStartOffset(line), document.getLineEndOffset(line));
do {
PsiElement parent = element.getParent();
if (parent == null || (parent.getTextOffset() < lineRange.getStartOffset())) {
break;
}
element = parent;
}
while(true);
final List<PsiLambdaExpression> lambdas = new ArrayList<PsiLambdaExpression>(3);
final PsiElementVisitor lambdaCollector = new JavaRecursiveElementVisitor() {
@Override
public void visitLambdaExpression(PsiLambdaExpression expression) {
super.visitLambdaExpression(expression);
lambdas.add(expression);
}
};
element.accept(lambdaCollector);
// add initial lambda if we're inside already
NavigatablePsiElement method = PsiTreeUtil.getParentOfType(element, PsiMethod.class, PsiLambdaExpression.class);
if (method instanceof PsiLambdaExpression) {
lambdas.add((PsiLambdaExpression)method);
}
for (PsiElement sibling = getNextElement(element); sibling != null; sibling = getNextElement(sibling)) {
if (!lineRange.intersects(sibling.getTextRange())) {
break;
}
sibling.accept(lambdaCollector);
}
if (myLambdaOrdinal < lambdas.size()) {
PsiElement body = lambdas.get(myLambdaOrdinal).getBody();
if (body instanceof PsiCodeBlock) {
for (PsiStatement statement : ((PsiCodeBlock)body).getStatements()) {
if (lineRange.intersects(statement.getTextRange())) {
body = statement;
break;
}
}
PsiElement firstElem = DebuggerUtilsEx.getFirstElementOnTheLine(lambdas.get(myLambdaOrdinal), document, line);
if (firstElem != null) {
return SourcePosition.createFromElement(firstElem);
}
return SourcePosition.createFromElement(body);
}
}
else {
@@ -316,14 +284,6 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio
});
}
private static PsiElement getNextElement(PsiElement element) {
PsiElement sibling = element.getNextSibling();
if (sibling != null) return sibling;
element = element.getParent();
if (element != null) return getNextElement(element);
return null;
}
@Nullable
@Override
public RangeHighlighter createHighlighter(Document document, Project project, TextAttributes attributes) {
@@ -58,6 +58,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.Navigatable;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.classFilter.ClassFilter;
import com.intellij.ui.content.Content;
import com.intellij.unscramble.ThreadDumpPanel;
@@ -779,4 +780,85 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils {
res.append(location.method().name());
return res.toString();
}
private static PsiElement getNextElement(PsiElement element) {
PsiElement sibling = element.getNextSibling();
if (sibling != null) return sibling;
element = element.getParent();
if (element != null) return getNextElement(element);
return null;
}
public static List<PsiLambdaExpression> collectLambdas(SourcePosition position, final boolean onlyOnTheLine) {
ApplicationManager.getApplication().assertReadAccessAllowed();
PsiFile file = position.getFile();
int line = position.getLine();
Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
if (document == null || line >= document.getLineCount()) {
return Collections.emptyList();
}
PsiElement element = position.getElementAt();
final TextRange lineRange = new TextRange(document.getLineStartOffset(line), document.getLineEndOffset(line));
do {
PsiElement parent = element.getParent();
if (parent == null || (parent.getTextOffset() < lineRange.getStartOffset())) {
break;
}
element = parent;
}
while(true);
final List<PsiLambdaExpression> lambdas = new ArrayList<PsiLambdaExpression>(3);
final PsiElementVisitor lambdaCollector = new JavaRecursiveElementVisitor() {
@Override
public void visitLambdaExpression(PsiLambdaExpression expression) {
super.visitLambdaExpression(expression);
if (!onlyOnTheLine || lineRange.intersects(expression.getTextRange())) {
lambdas.add(expression);
}
}
};
element.accept(lambdaCollector);
// add initial lambda if we're inside already
NavigatablePsiElement method = PsiTreeUtil.getParentOfType(element, PsiMethod.class, PsiLambdaExpression.class);
if (method instanceof PsiLambdaExpression) {
lambdas.add((PsiLambdaExpression)method);
}
for (PsiElement sibling = getNextElement(element); sibling != null; sibling = getNextElement(sibling)) {
if (!lineRange.intersects(sibling.getTextRange())) {
break;
}
sibling.accept(lambdaCollector);
}
return lambdas;
}
@Nullable
public static PsiElement getFirstElementOnTheLine(PsiLambdaExpression lambda, Document document, int line) {
ApplicationManager.getApplication().assertReadAccessAllowed();
TextRange lineRange = new TextRange(document.getLineStartOffset(line), document.getLineEndOffset(line));
if (!lineRange.intersects(lambda.getTextRange())) return null;
PsiElement body = lambda.getBody();
if (body instanceof PsiCodeBlock) {
for (PsiStatement statement : ((PsiCodeBlock)body).getStatements()) {
if (lineRange.intersects(statement.getTextRange())) {
return statement;
}
}
}
return body;
}
public static boolean inTheSameMethod(@NotNull SourcePosition pos1, @NotNull SourcePosition pos2) {
ApplicationManager.getApplication().assertReadAccessAllowed();
PsiElement elem1 = pos1.getElementAt();
PsiElement elem2 = pos2.getElementAt();
if (elem1 == null) return elem2 == null;
if (elem2 != null) {
NavigatablePsiElement expectedMethod = PsiTreeUtil.getParentOfType(elem1, PsiMethod.class, PsiLambdaExpression.class);
NavigatablePsiElement currentMethod = PsiTreeUtil.getParentOfType(elem2, PsiMethod.class, PsiLambdaExpression.class);
return Comparing.equal(expectedMethod, currentMethod);
}
return false;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -17,26 +17,39 @@ package com.intellij.debugger.ui.breakpoints;
import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.HelpID;
import com.intellij.icons.AllIcons;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.SmartList;
import com.intellij.xdebugger.XDebuggerUtil;
import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.breakpoints.XBreakpoint;
import com.intellij.xdebugger.breakpoints.XLineBreakpoint;
import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule;
import com.intellij.xdebugger.impl.XSourcePositionImpl;
import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointVariant;
import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointVariantsProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties;
import org.jetbrains.java.debugger.breakpoints.properties.JavaLineBreakpointProperties;
import javax.swing.*;
import java.util.Collections;
import java.util.List;
/**
* Base class for java line-connected exceptions (line, method, field)
* @author egor
*/
public class JavaLineBreakpointType extends JavaLineBreakpointTypeBase<JavaBreakpointProperties> implements JavaBreakpointType {
public class JavaLineBreakpointType extends JavaLineBreakpointTypeBase<JavaBreakpointProperties>
implements JavaBreakpointType, XLineBreakpointVariantsProvider<JavaLineBreakpointType.JavaBreakpointVariant> {
public JavaLineBreakpointType() {
super("java-line", DebuggerBundle.message("line.breakpoints.tab.title"));
}
@@ -58,13 +71,13 @@ public class JavaLineBreakpointType extends JavaLineBreakpointTypeBase<JavaBreak
@Nullable
@Override
public JavaBreakpointProperties createProperties() {
public JavaLineBreakpointProperties createProperties() {
return new JavaLineBreakpointProperties();
}
@Nullable
@Override
public JavaBreakpointProperties createBreakpointProperties(@NotNull VirtualFile file, int line) {
public JavaLineBreakpointProperties createBreakpointProperties(@NotNull VirtualFile file, int line) {
return new JavaLineBreakpointProperties();
}
@@ -78,4 +91,104 @@ public class JavaLineBreakpointType extends JavaLineBreakpointTypeBase<JavaBreak
public int getPriority() {
return 100;
}
@NotNull
@Override
public List<JavaBreakpointVariant> computeLineBreakpointVariants(@NotNull Project project, @NotNull XSourcePosition position) {
PsiFile file = PsiManager.getInstance(project).findFile(position.getFile());
if (file == null) {
return Collections.emptyList();
}
SourcePosition pos = SourcePosition.createFromLine(file, position.getLine());
List<PsiLambdaExpression> lambdas = DebuggerUtilsEx.collectLambdas(pos, true);
if (lambdas.isEmpty()) {
return Collections.emptyList();
}
NavigatablePsiElement startMethod = PsiTreeUtil.getParentOfType(pos.getElementAt(), PsiMethod.class, PsiLambdaExpression.class);
//noinspection SuspiciousMethodCalls
if (lambdas.contains(startMethod) && lambdas.size() == 1) {
return Collections.emptyList();
}
Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
if (document == null) {
return Collections.emptyList();
}
List<JavaBreakpointVariant> res = new SmartList<JavaBreakpointVariant>();
res.add(new JavaBreakpointVariant(position)); //all
if (startMethod instanceof PsiMethod) {
res.add(new ExactJavaBreakpointVariant(position, startMethod)); // base method
}
for (PsiLambdaExpression lambda : lambdas) { //lambdas
PsiElement firstElem = DebuggerUtilsEx.getFirstElementOnTheLine(lambda, document, position.getLine());
res.add(new ExactJavaBreakpointVariant(XSourcePositionImpl.createByElement(firstElem), lambda));
}
return res;
}
class JavaBreakpointVariant extends XLineBreakpointVariant {
protected final XSourcePosition mySourcePosition;
private JavaBreakpointVariant(XSourcePosition position) {
mySourcePosition = position;
}
@Override
public String getText() {
return "All";
}
@Override
public Icon getIcon() {
return null;
}
@Override
public TextRange getHighlightRange() {
return null;
}
@Override
public JavaLineBreakpointProperties createProperties() {
return createBreakpointProperties(mySourcePosition.getFile(),
mySourcePosition.getLine());
}
}
private class ExactJavaBreakpointVariant extends JavaBreakpointVariant {
private final PsiElement myElement;
public ExactJavaBreakpointVariant(XSourcePosition position, PsiElement element) {
super(position);
myElement = element;
}
@Override
public Icon getIcon() {
return myElement.getIcon(0);
}
@Override
public String getText() {
return StringUtil.shortenTextWithEllipsis(myElement.getText(), 100, 0);
}
@Override
public TextRange getHighlightRange() {
return myElement.getTextRange();
}
@Override
public JavaLineBreakpointProperties createProperties() {
JavaLineBreakpointProperties properties = super.createProperties();
properties.setOffset(mySourcePosition.getOffset());
return properties;
}
}
}
@@ -62,6 +62,7 @@ import com.sun.jdi.request.BreakpointRequest;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.java.debugger.breakpoints.properties.JavaLineBreakpointProperties;
import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
import javax.swing.*;
@@ -198,12 +199,30 @@ public class LineBreakpoint extends BreakpointWithHighlighter {
return false;
}
protected boolean acceptLocation(DebugProcessImpl debugProcess, ReferenceType classType, Location loc) {
protected boolean acceptLocation(final DebugProcessImpl debugProcess, ReferenceType classType, final Location loc) {
Method method = loc.method();
if (DebuggerUtils.isSynthetic(method)) {
return false;
}
return !(method.isConstructor() && loc.codeIndex() == 0 && isAnonymousClass(classType));
boolean res = !(method.isConstructor() && loc.codeIndex() == 0 && isAnonymousClass(classType));
if (!res) return false;
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
if (getProperties() instanceof JavaLineBreakpointProperties) {
Integer offset = ((JavaLineBreakpointProperties)getProperties()).getOffset();
if (offset == null) return true;
PsiFile file = getPsiFile();
if (file != null) {
SourcePosition exactPosition = SourcePosition.createFromOffset(file, offset);
SourcePosition position = debugProcess.getPositionManager().getSourcePosition(loc);
if (position == null) return false;
return DebuggerUtilsEx.inTheSameMethod(exactPosition, position);
}
}
return true;
}
});
}
private boolean isInScopeOf(DebugProcessImpl debugProcess, String className) {
@@ -17,12 +17,12 @@ package com.intellij.debugger.ui.breakpoints;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.xdebugger.XSourcePosition;
import com.sun.jdi.Location;
import com.sun.jdi.ReferenceType;
@@ -125,19 +125,9 @@ public class RunToCursorBreakpoint extends LineBreakpoint {
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
PsiElement expectedElement = myCustomPosition.getElementAt();
if (expectedElement != null) {
SourcePosition position = debugProcess.getPositionManager().getSourcePosition(loc);
if (position != null) {
PsiElement currentElement = position.getElementAt();
if (currentElement != null) {
NavigatablePsiElement expectedMethod = PsiTreeUtil.getParentOfType(expectedElement, PsiMethod.class, PsiLambdaExpression.class);
NavigatablePsiElement currentMethod = PsiTreeUtil.getParentOfType(currentElement, PsiMethod.class, PsiLambdaExpression.class);
return Comparing.equal(expectedMethod, currentMethod);
}
}
}
return true;
SourcePosition position = debugProcess.getPositionManager().getSourcePosition(loc);
if (position == null) return false;
return DebuggerUtilsEx.inTheSameMethod(myCustomPosition, position);
}
});
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -15,8 +15,20 @@
*/
package org.jetbrains.java.debugger.breakpoints.properties;
import com.intellij.util.xmlb.annotations.OptionTag;
/**
* @author egor
*/
public class JavaLineBreakpointProperties extends JavaBreakpointProperties<JavaLineBreakpointProperties> {
private Integer myOffset = null;
@OptionTag("offset")
public Integer getOffset() {
return myOffset;
}
public void setOffset(Integer offset) {
myOffset = offset;
}
}
@@ -312,7 +312,7 @@ public abstract class SourcePosition implements Navigatable{
}
@Nullable
public static SourcePosition createFromElement(PsiElement element) {
public static SourcePosition createFromElement(@NotNull PsiElement element) {
ApplicationManager.getApplication().assertReadAccessAllowed();
PsiElement navigationElement = element.getNavigationElement();
final SmartPsiElementPointer<PsiElement> pointer =
@@ -18,6 +18,7 @@ package com.intellij.xdebugger.impl;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.editor.Caret;
@@ -28,12 +29,19 @@ import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.util.AsyncResult;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.Processor;
import com.intellij.util.SmartList;
import com.intellij.xdebugger.*;
import com.intellij.xdebugger.breakpoints.*;
import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule;
@@ -45,6 +53,8 @@ import com.intellij.xdebugger.frame.XSuspendContext;
import com.intellij.xdebugger.frame.XValueContainer;
import com.intellij.xdebugger.impl.breakpoints.XBreakpointUtil;
import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl;
import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointVariant;
import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointVariantsProvider;
import com.intellij.xdebugger.impl.breakpoints.ui.grouping.XBreakpointFileGroupingRule;
import com.intellij.xdebugger.impl.evaluate.quick.common.ValueLookupManager;
import com.intellij.xdebugger.impl.settings.XDebuggerSettingsManager;
@@ -54,6 +64,7 @@ import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.*;
/**
@@ -107,28 +118,76 @@ public class XDebuggerUtilImpl extends XDebuggerUtil {
@NotNull final VirtualFile file,
final int line,
final boolean temporary) {
toggleAndReturnLineBreakpoint(project, type, file, line, temporary);
XSourcePositionImpl position = XSourcePositionImpl.create(file, line);
if (position != null) {
toggleAndReturnLineBreakpoint(project, type, position, temporary, null);
}
}
public static <P extends XBreakpointProperties> XLineBreakpoint toggleAndReturnLineBreakpoint(@NotNull final Project project,
@NotNull
public static <P extends XBreakpointProperties> AsyncResult<XLineBreakpoint> toggleAndReturnLineBreakpoint(@NotNull final Project project,
@NotNull final XLineBreakpointType<P> type,
@NotNull final VirtualFile file,
final int line,
final boolean temporary) {
return new WriteAction<XLineBreakpoint>() {
@NotNull final XSourcePosition position,
final boolean temporary,
final RelativePoint relativePoint) {
return ApplicationManager.getApplication().runWriteAction(new Computable<AsyncResult<XLineBreakpoint>>() {
@Override
protected void run(@NotNull final Result<XLineBreakpoint> result) {
XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager();
public AsyncResult<XLineBreakpoint> compute() {
final VirtualFile file = position.getFile();
final int line = position.getLine();
final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager();
XLineBreakpoint<P> breakpoint = breakpointManager.findBreakpointAtLine(type, file, line);
if (breakpoint != null) {
breakpointManager.removeBreakpoint(breakpoint);
}
else {
if (type instanceof XLineBreakpointVariantsProvider) {
final XLineBreakpointVariantsProvider<XLineBreakpointVariant> provider =
(XLineBreakpointVariantsProvider<XLineBreakpointVariant>)type;
List<XLineBreakpointVariant> variants = provider.computeLineBreakpointVariants(project, position);
if (!variants.isEmpty()) {
if (variants.size() > 1 && relativePoint != null) {
final AsyncResult<XLineBreakpoint> res = new AsyncResult<XLineBreakpoint>();
JBPopupFactory.getInstance().createListPopup(
new BaseListPopupStep<XLineBreakpointVariant>("Create breakpoint for", variants) {
@NotNull
@Override
public String getTextFor(XLineBreakpointVariant value) {
return value.getText();
}
@Override
public Icon getIconFor(XLineBreakpointVariant value) {
return value.getIcon();
}
@Override
public PopupStep onChosen(final XLineBreakpointVariant selectedValue, boolean finalChoice) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
P properties = (P)selectedValue.createProperties();
res.setDone(breakpointManager.addLineBreakpoint(type, file.getUrl(), line, properties, temporary));
}
});
return FINAL_CHOICE;
}
}).show(relativePoint);
return res;
}
else {
P properties = (P)variants.get(0).createProperties();
return AsyncResult.done(
(XLineBreakpoint)breakpointManager.addLineBreakpoint(type, file.getUrl(), line, properties, temporary));
}
}
}
P properties = type.createBreakpointProperties(file, line);
result.setResult(breakpointManager.addLineBreakpoint(type, file.getUrl(), line, properties, temporary));
return AsyncResult.done((XLineBreakpoint)breakpointManager.addLineBreakpoint(type, file.getUrl(), line, properties, temporary));
}
return AsyncResult.rejected();
}
}.execute().getResultObject();
});
}
@Override
@@ -199,13 +258,10 @@ public class XDebuggerUtilImpl extends XDebuggerUtil {
return Collections.emptyList();
}
final Document document = editor.getDocument();
VirtualFile file = FileDocumentManager.getInstance().getFile(document);
Collection<XSourcePosition> res = new ArrayList<XSourcePosition>();
List<Caret> carets = editor.getCaretModel().getAllCarets();
for (Caret caret : carets) {
int line = caret.getLogicalPosition().line;
XSourcePositionImpl position = XSourcePositionImpl.create(file, line);
VirtualFile file = FileDocumentManager.getInstance().getFile(editor.getDocument());
List<XSourcePosition> res = new SmartList<XSourcePosition>();
for (Caret caret : editor.getCaretModel().getAllCarets()) {
XSourcePositionImpl position = XSourcePositionImpl.createByOffset(file, caret.getOffset());
if (position != null) {
res.add(position);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* 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.
@@ -65,7 +65,7 @@ public class XToggleLineBreakpointActionHandler extends DebuggerActionHandler {
Set<Integer> processedLines = new HashSet<Integer>();
for (XSourcePosition position : XDebuggerUtilImpl.getAllCaretsPositions(project, event.getDataContext())) {
if (processedLines.add(position.getLine())) {
XBreakpointUtil.toggleLineBreakpoint(project, position.getFile(), editor, position.getLine(), myTemporary, true);
XBreakpointUtil.toggleLineBreakpoint(project, position, editor, myTemporary, true);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* 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.
@@ -22,16 +22,20 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.FoldRegion;
import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.AsyncResult;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.xdebugger.XDebuggerManager;
import com.intellij.xdebugger.XDebuggerUtil;
import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.breakpoints.*;
import com.intellij.xdebugger.impl.DebuggerSupport;
import com.intellij.xdebugger.impl.XDebuggerUtilImpl;
import com.intellij.xdebugger.impl.XSourcePositionImpl;
import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointItem;
import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointPanelProvider;
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -130,12 +134,14 @@ public class XBreakpointUtil {
* - unfolds folded block on the line
* - if folded, checks if line breakpoints could be toggled inside folded text
*/
public static XLineBreakpoint toggleLineBreakpoint(Project project,
VirtualFile file,
Editor editor,
int lineStart,
@NotNull
public static AsyncResult<XLineBreakpoint> toggleLineBreakpoint(@NotNull Project project,
@NotNull XSourcePosition position,
@Nullable Editor editor,
boolean temporary,
boolean moveCarret) {
int lineStart = position.getLine();
VirtualFile file = position.getFile();
// for folded text check each line and find out type with the biggest priority
int linesEnd = lineStart;
if (editor != null) {
@@ -147,7 +153,7 @@ public class XBreakpointUtil {
final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager();
XLineBreakpointType<?>[] lineTypes = XDebuggerUtil.getInstance().getLineBreakpointTypes();
XLineBreakpointType<?> typeWinner = null;
XLineBreakpointType typeWinner = null;
int lineWinner = -1;
for (int line = lineStart; line <= linesEnd; line++) {
int maxPriority = 0;
@@ -170,18 +176,22 @@ public class XBreakpointUtil {
}
if (typeWinner != null) {
XLineBreakpoint res = XDebuggerUtilImpl.toggleAndReturnLineBreakpoint(project, typeWinner, file, lineWinner, temporary);
XSourcePosition winPosition = (lineStart == lineWinner) ? position : XSourcePositionImpl.create(file, lineWinner);
if (winPosition != null) {
AsyncResult<XLineBreakpoint> res = XDebuggerUtilImpl.toggleAndReturnLineBreakpoint(project, typeWinner, winPosition, temporary,
DebuggerUIUtil.calcPopupLocation(editor, lineWinner));
if (editor != null && lineStart != lineWinner) {
int offset = editor.getDocument().getLineStartOffset(lineWinner);
ExpandRegionAction.expandRegionAtOffset(project, editor, offset);
if (moveCarret) {
editor.getCaretModel().moveToOffset(offset);
if (editor != null && lineStart != lineWinner) {
int offset = editor.getDocument().getLineStartOffset(lineWinner);
ExpandRegionAction.expandRegionAtOffset(project, editor, offset);
if (moveCarret) {
editor.getCaretModel().moveToOffset(offset);
}
}
return res;
}
return res;
}
return null;
return AsyncResult.rejected();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -38,6 +38,7 @@ import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.AsyncResult;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -45,6 +46,7 @@ import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.VirtualFileUrlChangeAdapter;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.util.Consumer;
import com.intellij.util.SmartList;
import com.intellij.util.containers.BidirectionalMap;
import com.intellij.util.ui.update.MergingUpdateQueue;
@@ -53,6 +55,7 @@ import com.intellij.xdebugger.XDebuggerManager;
import com.intellij.xdebugger.breakpoints.SuspendPolicy;
import com.intellij.xdebugger.breakpoints.XBreakpoint;
import com.intellij.xdebugger.breakpoints.XLineBreakpoint;
import com.intellij.xdebugger.impl.XSourcePositionImpl;
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
@@ -297,20 +300,25 @@ public class XLineBreakpointManager {
if (!myProject.isDisposed() && myProject.isInitialized() && file.isValid()) {
ActionManagerEx.getInstanceEx().fireBeforeActionPerformed("ToggleLineBreakpoint", e.getMouseEvent());
XLineBreakpoint breakpoint =
XBreakpointUtil.toggleLineBreakpoint(myProject, file, editor, line, mouseEvent.isAltDown(), false);
if (!mouseEvent.isAltDown() && mouseEvent.isShiftDown() && breakpoint != null) {
breakpoint.setSuspendPolicy(SuspendPolicy.NONE);
String selection = editor.getSelectionModel().getSelectedText();
if (selection != null) {
breakpoint.setLogExpression(selection);
AsyncResult<XLineBreakpoint> result = XBreakpointUtil.toggleLineBreakpoint(
myProject, XSourcePositionImpl.create(file, line), editor, mouseEvent.isAltDown(), false);
result.doWhenDone(new Consumer<XLineBreakpoint>() {
@Override
public void consume(XLineBreakpoint breakpoint) {
if (!mouseEvent.isAltDown() && mouseEvent.isShiftDown() && breakpoint != null) {
breakpoint.setSuspendPolicy(SuspendPolicy.NONE);
String selection = editor.getSelectionModel().getSelectedText();
if (selection != null) {
breakpoint.setLogExpression(selection);
}
else {
breakpoint.setLogMessage(true);
}
// edit breakpoint
DebuggerUIUtil.showXBreakpointEditorBalloon(myProject, mouseEvent.getPoint(), ((EditorEx)editor).getGutterComponentEx(), false, breakpoint);
}
}
else {
breakpoint.setLogMessage(true);
}
// edit breakpoint
DebuggerUIUtil.showXBreakpointEditorBalloon(myProject, mouseEvent.getPoint(), ((EditorEx)editor).getGutterComponentEx(), false, breakpoint);
}
});
}
}
});
@@ -0,0 +1,34 @@
/*
* 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.xdebugger.impl.breakpoints;
import com.intellij.openapi.util.TextRange;
import com.intellij.xdebugger.breakpoints.XBreakpointProperties;
import javax.swing.*;
/**
* @author egor
*/
public abstract class XLineBreakpointVariant<P extends XBreakpointProperties> {
public abstract String getText();
public abstract Icon getIcon();
public abstract TextRange getHighlightRange();
public abstract P createProperties();
}
@@ -0,0 +1,30 @@
/*
* 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.xdebugger.impl.breakpoints;
import com.intellij.openapi.project.Project;
import com.intellij.xdebugger.XSourcePosition;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* @author egor
*/
public interface XLineBreakpointVariantsProvider<V extends XLineBreakpointVariant> {
@NotNull
List<V> computeLineBreakpointVariants(@NotNull Project project, @NotNull XSourcePosition position);
}